Fortran Coder

标题: 关于二进制文件读写的疑问? [打印本页]

作者: xuanyz    时间: 2020-3-31 12:39
标题: 关于二进制文件读写的疑问?
这两天学习二进制文件读写
论坛上的帖子http://fcode.cn/guide-4-1.html帮助很大,其实对于二进制数据进行读写时可以采用的读写方式有两种直接读取(Access = 'Direct' )和顺序读取(Access = 'Sequential' )
于是采用两种不同的方法分别写入和读取数据并通过屏幕输出,结果两种方法完全一样。
[Fortran] 纯文本查看 复制代码
Program www_fcode_cn      Implicit None
      Integer*4 :: iVar1 ,iVar2,iVar1M , iVar2M
      Real*4 :: rVar1 , rVar2,rVar1M , rVar2M
      Character(Len=16) :: cStr,cStrM

C         写二进制数据----------------------------------------------------
C          方法1 直接写入文件(Access = 'Direct' )
            Open( 12 , File = 'TestBin.Bin' , Access = 'Direct' ,
     &    Form = 'Unformatted' , RecL = 4 )
          Write( 12 , Rec = 1 ) 271 , 783 , 2581.192_4 , 1.6892716E-07
          Write( 12 , Rec = 2 ) "ABCDEFGHIGKLMNOP"
          Close( 12 )

C            方法2 顺序写入文件(Access = 'Sequential' )写入
             Open( 14 , File = 'TestBin2.Bin' ,Access = 'Sequential' ,
     &      Form = 'Unformatted' )
            Write(14) 271 , 783 , 2581.192_4 , 1.6892716E-07
            Write(14) "ABCDEFGHIGKLMNOP"
            Close(14 )

C          读二进制文件------------------------------------------------------
c          ****读二进制文件(Access = 'Direct' )
           Open( 12 , File = 'TestBin.Bin' , Access = 'Direct' ,
     &   Form = 'Unformatted' , RecL = 4 )
           Read( 12 , Rec = 1) iVar1 , iVar2 , rVar1 , rVar2
           Read( 12 , Rec = 2) cStr
           Write(* , * ) iVar1 , iVar2 , rVar1 , rVar2
           Write(* , * ) cStr
           Close( 12 )

c            ****读二进制文件(Access = 'Sequential' )
            Open( 14 , File = 'TestBin2.Bin',form='Unformatted',
     &    Access = 'Sequential')
            Read( 14 ) iVar1M , iVar2M , rVar1M , rVar2M
            Read( 14 ) cStrM
            Write(* , * ) iVar1M , iVar2M , rVar1M , rVar2M
            Write(* , * ) cStrM
            Close( 14 )

      End Program www_fcode_cn
      
     但存在的问题是用vs2010查看两种方法生成的二进制文件testBin.Bin和testBin2.Bin的内容是不完全相同的,可以参考附件中的图片testBin.jig和testBin2.jig,具体而言就是在利用(Access = 'Sequential' )顺序写入二进制数据的testBin2_picture.jig中多了一些表示行起始和行结束的数值符号代码:如图中 10 00 00 00,由于顺序写入时两次调用了write函数写入了两行数据,所有共有 2行*(行起始标号代码+行结束标号代码)=4组10 00 00 00 数值代码,分别出现在第一行和第二行的开始和结束的位置。
    请问有没有办法在直接法(Access = 'Direct' )写入二进制数据时也在行开始和行结束的位置加入行开始和行结束标号代码如(10 00 00 00),从而可以实现利用顺序法(Access = 'Sequential' )一次读入一行数据呢?如果可以加入,又怎么实现呢?
    先感谢了!!

testBin.JPG (11.56 KB, 下载次数: 260)

testBin.jig

testBin.jig

testBin2.JPG (34.17 KB, 下载次数: 274)

testBin2.jig

testBin2.jig

作者: fcode    时间: 2020-3-31 14:20
你提到的文章,多看几遍。
作者: xuanyz    时间: 2020-3-31 15:00
本帖最后由 xuanyz 于 2020-3-31 17:13 编辑

感谢fcode提醒,又仔细看了这篇文章,明白了部分,似乎应该是"行使用回车和换行符间隔",但回车和换行符又怎么输入呢?
作者: fcode    时间: 2020-4-1 09:20
如果你采用二进制文件,就应该放弃回车换行符的想法。(那是文本文件中的分隔符)
二进制文件通常不用分隔符,数据紧凑的在一起。程序员(或者数据格式的设计者),他们心中有数据的结构,心中知道数据的分割在什么位置就行了。

回到你的问题,如图中 10 00 00 00,这并不是“行起始和行结束的数值符号代码”,而是(顺序读取特有的)“本次记录的长度”,比如这里的 0x10000000,十进制就是16,说明本次记录的长度是16个字节。你可以把输出的内容的字节数加起来,就是16。
一般在直接读取中,不会用到本次记录的长度。因为直接读取,要求每次的记录长度是相等的。(只有每次相等,才可以根据记录数 rec 和记录长度 recl,直接计算出读取的位置,也就是 (rec-1)*recl + 1)

所以,直接读取需要在 Open 时指定 recl 也就是记录长度。指定后不能改变,除非close了重新open
而顺序读取,每次读写的记录长度不一样。为了让读取者知道本次记录有多长,就把记录长度写在本次记录的前面和后面。

除了直接读写和顺序读写,Fortran2003还增加了流文件读写,非常的灵活。反正我很久不用直接和顺序读取二进制了,自有了Fortran2003,我是凡二进制一律用流文件读写。
你可以阅读 http://stream.w.fcode.cn

作者: xuanyz    时间: 2020-4-1 10:29
感谢感谢fcode,这下全明白了,再次感谢




欢迎光临 Fortran Coder (http://bbs.fcode.cn/) Powered by Discuz! X3.2