fortran读写二进制文件

时间:2022-09-04 18:58:51

读取和写入二进制其实是两个很类似的操作,了解了其中之一,另一个也就不难了。 jL>IX`,+6  
  二进制文件我们通常使用直接读取方式,Open 语句可以写为: Y6&w0~?!  
E9YR *P4$  
引用: z*�"zXLC  
Open( 12 , File = 'TestBin.Bin' , Access = 'Direct' , Form = 'Unformatted' , RecL = 4 ) V*2uW2/}  
oM�M`7wJw  
   上面的 Access 表示直接读取方式,Form 表示无格式储存。比较重要的是 RecL 。我们读取数据时,是用记录来描述单位的,每一次读入或写入是一个记录。记录的长度在 Open 时就确定下来,以后不能改变。如果需要改变,只能 Close 以后再此 Open。 ]EC�zb/  
  记 录长度在某些编译器下表示读取的 4 字节长度的倍数,规定为 4 表示记录长度为 16 字节。有些编译器下就直接表示记录的字节数,规定为 4 则表示记录长度为 4 字节。这个问题需要参考编译器手册。在 VF 系列里,这个值是前面一个含义。可以通过设置工程属性的 Fortran,Data,Use Bytes as RECL= Unit for Unformatted Files 来改变,使之成为后一个含义。在命令行模式下,则使用 /assume:byterecl 这个编译选项。 DKx8<yEky  
  确定 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<Xz  
  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<SNi  
  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 ><iE�VrpN  
  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 < N),那么,第 M+1 到第 N-1 笔记录会用 0 填充。也就是说,二进制文件不会出现断裂。 0SKt8pL`  
#s yP=  
  二进制文件的读写是比较灵活的,实际应用中,我们使用哪种方式,我们应该根据自己的情况来设计。如何选择合适的记录长度 RecL,如何设计高效的储存方式等。 I}:> M!w