读取和写入二进制其实是两个很类似的操作,了解了其中之一,另一个也就不难了。 jL>IX`,+6
二进制文件我们通常使用直接读取方式,Open 语句可以写为: Y6&w0~?!
E9YR *P4$
引用: z*"zXLC
Open( 12 , File = 'TestBin.Bin' , Access = 'Direct' , Form = 'Unformatted' , RecL = 4 ) V*2uW2/}
oMM`7wJw
上面的 Access 表示直接读取方式,Form 表示无格式储存。比较重要的是 RecL 。我们读取数据时,是用记录来描述单位的,每一次读入或写入是一个记录。记录的长度在 Open 时就确定下来,以后不能改变。如果需要改变,只能 Close 以后再此 Open。 ]ECzb/
记 录长度在某些编译器下表示读取的 4 字节长度的倍数,规定为 4 表示记录长度为 16 字节。有些编译器下就直接表示记录的字节数,规定为 4 则表示记录长度为 4 字节。这个问题需要参考编译器手册。在 VF 系列里,这个值是前面一个含义。可以通过设置工程属性的 Fortran,Data,Use Bytes as RECL= Unit for Unformatted Files 来改变,使之成为后一个含义。在命令行模式下,则使用 /assume:byterecl 这个编译选项。 DKx8
确定 RecL 大小是我们需要做的事情,一般来说,不适合太大,也不适合太小。还需要结合数据储存方式来考虑。太小的话,我们需要执行读写的次数就多,太大的话,我们就不方便操作小范围的数据。 "k o?AUt
有时候我们甚至会分多次来读取数据,每一次的 RecL 都不同。对于上面的 TestBin.Bin 文件来说,它比较简单,我以 16 字节长度和 8 字节长度两种读取方式来演示,你甚至可以一次 32 个字节长度全部读完: [k M)K'-
(1)RecL = 4 【记录长度 16 字节】 ]v{f!r=}
引用: AK]{^Hvz
Program main (sHqzWh
Implicit None nlOM4fJ(
Integer*4 :: iVar1 , iVar2 c=p`5sN)
Real*4 :: rVar1 , rVar2 61L vT"
Character(Len=16) :: cStr $hZb
Open( 12 , File = 'TestBin.Bin' , Access = 'Direct' , Form = 'Unformatted' , RecL = 4 ) <5 X?6*Qvr
Read( 12 , Rec = 2 ) cStr J6r"_>)z
Read( 12 , Rec = 1 ) iVar1 , iVar2 , rVar1 , rVar2 5 0uYU[W
Write( * , * ) cStr :iqFC >D
Write( * , * ) iVar1 , iVar2 , rVar1 , rVar2 3omFd#EP
Close( 12 ) pESlBQ7{I
End Program main ChO?Lm$y
~'>RK
这里的 Open 里指定了 RecL = 4(记录长度是 16 字节)。 [-C-+jC
第一个 Read 语句,直接读取第二笔记录(也就是第 17 字节到第 32 字节)。读取出的 cStr = "ABCDEFGHIGKLMNOP"。 |TM&:4D]^
第二个 Read 语句,返回来读取第一笔记录(也就是前面 16 个字节)。读取出的数据分别放入 4 个 4 字节的变量。(其中前面两个是整型,后面两个是实型) 8fA9yQ8
输出结果为: 'NCxVbyYD
ABCDEFGHIGKLMNOP :&:IZkO
271 783 2581.192 1.6892716E-07 mw0#Dhyy1=
看到这个结果,就说明我们成功了。 cfI5KLG~#
同时我们可以看到,第一个语句,我们直接跳到第二条记录读取,并没有读取第一条。这就是直接读取数据的方便。有时候我们根本不需要某些数据,这时候,我们可以直接跳到某一条记录上。这个记录甚至可以是我们实现算出来的变量。比如: ZK,}3b{
iRec = ( a + b ) / C #;cDPBv*wS
Read( 12 , Rec = iRec ) cStr c*MSd
实现我们储存了 100 天的数据,我们只需要第 21 天的数据,我们怎么办?在顺序读取时,我们可能会开辟一个 100 元素的数组,或者循环执行 20 次空白的读取。但是在直接读取时,我们只需要执行一句 Read( 12 , Rec = 21 )。这是多么的方便。(直接读取和顺序读取虽然于文本文件和二进制文件没有直接的关联,但是文本文件通常用顺序读取,而二进制文件通常用直接读取。这是他 们的性质决定的。) /?X1>A:*
(2)RecL = 2【记录长度为 8 字节】 sX53(|?*
引用: N}{CL(xi
Program main Q]X0O10
Implicit None PRmZ3
Integer*4 :: iVar1 , iVar2 G#V5E)Dx
Real*4 :: rVar1 , rVar2 4eb
Character(Len=16) :: cStr x)<5f|j
Open( 12 , File = 'TestBin.Bin' , Access = 'Direct' , Form = 'Unformatted' , RecL = 2 ) B.fL gQK0
Read( 12 , Rec = 4 ) cStr( 9 : 16 ) t!^FWr&
Read( 12 , Rec = 3 ) cStr( 1 : 8 ) Wo5G23:xz
Read( 12 , Rec = 1 ) iVar1 , iVar2 r$ue1bH}|
Read( 12 , Rec = 2 ) rVar1 , rVar2 Avw"[~Xd
Write( * , * ) cStr >
Write( * , * ) iVar1 , iVar2 , rVar1 , rVar2 2a*1q#MpAt
Close( 12 ) `xe[/Z 2
End Program main Y5LESZWo
f ;|[
这里设定的 RecL = 2 ,意思是一笔记录 8 个字节。所以我们不能一次读取 cStr 这个 16 字节的字符串。我们必须分两次读取。第一次读取第 4 笔记录,放入字符串后半段。第二次读取第 3 笔记录,放入字符串前半段。(可以调换位置)。然后读取第一笔记录的两个整型变量和第二笔记录的两个实型变量。 ;nj'C1
输出结果和(1)的方法一样。 Wf_aEW&n
(3)写入二进制文件 P>euUVMPz4
写入二进制文件同样需要考虑 RecL 的问题。我们这里以 RecL = 4 来举例。 Hk2@X(
^w2n
引用: i#lvt#2J0
Program main L3q)j/ls
Implicit None BO[Q"g$Kon
Open( 12 , File = 'TestBinW.Bin' , Access = 'Direct' , Form = 'Unformatted' , RecL = 4 ) avO+1<`4B
Write( 12 , Rec = 1 ) 271 , 783 , 2581.192_4 , 1.6892716E-07 6z%3l7#7Yi
Write( 12 , Rec = 2 ) "ABCDEFGHIGKLMNOP" 9][Mw[k>
Close( 12 ) .NjdkHYR
End Program main `H/H LCt
86%weU/*
~w]1QHA'f
写入二进制文件和读取二进制文件是差不多的,我就不再解释了。需要注意的是,如果直接写入第 N 笔记录,而文件没有只有 M 笔记录(M 0SKt8pL`
#s yP=
二进制文件的读写是比较灵活的,实际应用中,我们使用哪种方式,我们应该根据自己的情况来设计。如何选择合适的记录长度 RecL,如何设计高效的储存方式等。 I}:> M!w