二进制和文本文件的比较

一).一般问题
  二进制文件与我们通常使用的文本文件储存方式有根本的不同。这样的不同很难用言语表达,自己亲自看一看,理解起来会容易得多。因此,我推荐学习二进制文件读写的朋友安装一款十六进制编辑器。这样的编辑器有很多,在我们的  CVF  附带的集成开发环境下就可以(将二进制文件拖动到  IDE  窗口后松开)。Visual  Studio  2005  也是可以的。(不过需要在  File  菜单下  Open,File)
  另外推荐一款使用较多的软件,叫做  UltraEdit(以下简称  UE)。是很不错的文本编辑器,也能做十六进制编辑器使用。
  为什么要用十六进制编辑器?而不用  进制呢?因为  进制实在太小,书写起来会很长,很不直观。而我们的计算机把  位作为一个字节。刚好  **  256  16  **  2。用  位  进制表达的数,我们用  个十六进制数据来表达,更直观和方便。

二).文件格式
  所有文件,笼统意义上将可以区分为两类,一类是文本文件,一类是二进制文件。

  1).文本文件
  文本文件用记事本等文本编辑器打开,我们可以看懂上面的信息。所以使用比较广泛。通常一个文本文件分为很多很多行,作为数据储存时,还有列的概念。实际上,储存在硬盘或其他介质上,文件内容是线一样储存的,列是用空格或  Tab  间隔,行是用回车和换行符间隔。
  以  ANSI  编码(使用较多)的文本文件来说,例如我们储存如下信息:
引用
10
11
12

  需要的空间是:3  行  ×  每行  个字符  个回车符  个换行符  10  字节。文本文件储存数据是有格式,无数据类型的。比如  10  这个数据,并不指定是整型还是实型还是字符串。它有长度,就是  2,两个字节。储存时计算机储存它的  ASCII  码:31h,30h。(十六进制表示)。回车符是:0Dh,换行符:0Ah。
        因此,这个数据储存是这样的:
引用
31  30  0D 0A  31  31  0D 0A  31  32

  (红色为回车符和换行符)  31h  30h  就是  10,31h  31h  就是  11,31h  32h  就是  12。因此我们也可以认为文本文件是特殊的二进制文件。
 2).二进制文件
  二进制文件,是无格式有数据类型的。比如上面的  10  11  12  三个数。但二进制文件没有行的概念。我们要紧凑地储存他们。(当然也可以中间加入一些空白的字节)
  从数据类型上来说,我们首先考虑整型。如果把  10  11  12  当作  字长的整型。则  10  表示为:0Ah  00h。因为  0Ah  对应十进制  10。而后面的  00h  是空白位。2  字长的整型如果不足  FFh,也就是不足  255,则需要一个空白位。类似的:11  表示为  0Bh  00h,12  表示为  0Ch  00h。
  当整型数据超过  255  时,我们需要  个字节来储存。比如  2748(ABCh),则表示为:BCh  0Ah。要把低位写在前面(BCh),高位写在后面(0Ah)。
  当整型数据超过  65535  时,我们就需要  个字节来储存。比如  439041101(1A2B3C4Dh),则表示成:4Dh  3Ch  2Bh  1Ah。当数据再大时,我们就需要  字节储存了。
  二进制文件的实型数据也有字节长度的区分,比如  字长,8  字长。但实型数据的长度并不仅仅代表它的表达的范围,更多的代表精度。所以,8  字长的我们又称为双精度。关于实型数据如何储存为  进制。则有很多套规则。现在都广泛使用的是  IEEE  标准浮点格式。关于这样的规则,我还正在了解,比较麻烦。就不多说了。在这里也没有必要了解。
  二进制文件也可以储存字符型数据,储存方法和文本文件一样。都是使用  ASCII  编码储存的。所以我们用记事本打开某些二进制文件时,也能看到一些有意义的字符串。(无意义的乱码我们可以认为是整型或实型,不过记事本程序当作字符来解释,因此造成了乱码)

三).使用二进制文件的好处
  为什么要使用二进制文件。原因大概有三个:
  第一是二进制文件比较节约空间,这两者储存字符型数据时并没有差别。但是在储存数字,特别是实型数字时,二进制更节省空间,比如储存  Real*4  的数据:3.1415927,文本文件需要  个字节,分别储存:3  这  个  ASCII  值,而二进制文件只需要  个字节(DB  0F  49  40)
  第二个原因是,内存中参加计算的数据都是用二进制无格式储存起来的,因此,使用二进制储存到文件就更快捷。如果储存为文本文件,则需要一个转换的过程。在数据量很大的时候,两者就会有明显的速度差别了。
  第三,就是一些比较精确的数据,使用二进制储存不会造成有效位的丢失。

四).二进制文件的储存方式
        列举一个二进制文件如下:
引用
00000000h:  0F 01 00 00 0F 03 00 00 12 53 21 45 58 62 35 34  .........S!EXb54
00000010h:  41 42 43 44 45 46 47 48 49 47 4B 4C 4D 4E 4F 50  ABCDEFGHIGKLMNOP

  这里列出的是在  UltraEdit(UE)  里看到的东西。其实只有红色部分是文件内容。前面的是  UE  加入的行号。后面的是  UE  尝试解释为字符型的参考。
  这个文件一共有  32  字节长。显示为两列,每列  16  个字节。实际上,这仅仅是  UE  的显示而已。真实的文件并不分行。仅仅知道这个文件的内容,如果我们没有任何说明的话,是不能看出任何有用信息的。
  下面我规定一下说明:我们认为,前  个字节是一个  字节的整型数据(0F  01  00  00  十六进制:10Fh  十进制:271)。这  个字节之后的  个字节是另一个  字节的整型数据(0F  03  00  00  十六进制:30Fh  十进制:783)。其后的  个字节(12  53  21  45  )表示一个  字节的实型数据:2.5811919E+3。再其后的  个字节(58  62  35  34)表示另一个  字节的实行数据:1.6892716E-7。而只后的  16  个字节(41  42  43  44  45  46  47  48  49  47  4B  4C  4D  4E  4F  50)我们认为是  16  个字节的字符串(ABCDEFGHIGKLMNOP)
  实际上,二进制文件只是储存数据,并不写明数据类型,比如上面的第  字节到第  16  字节(12  53  21  45  58  62  35  34),我们刚才认为是  个  字节的实型,其实也可以认为是  个字节的字符型( S!EXb54)。而后面的  16  个字节的字符串(ABCDEFGHIGKLMNOP),我们也可以认为是  个  字节的整型,或者  个  字节的整型,甚至  个  字节的实型,4  个  字节的实型,等等等等。
  因此,面对一个二进制文件,我们不能准确地知道它的含义,我们需要他的数据储存方式的说明。这个说明告诉我们第几个字节到第几个字节是什么类型的数据,储存的数据是什么含义。否则的话,我们只能猜测,或者无能为力。

五).如何使用语句操作二进制文件
  我们将上面的那个二进制文件保存为:TestBin.Bin  来举例。
  读取和写入二进制其实是两个很类似的操作,了解了其中之一,另一个也就不难了。
  二进制文件我们通常使用直接读取方式,Open  语句可以写为:
引用
Open(  12  File  'TestBin.Bin'  Access  'Direct'  Form  'Unformatted'  RecL  )

  上面的  Access  表示直接读取方式,Form  表示无格式储存。比较重要的是  RecL  。我们读取数据时,是用记录来描述单位的,每一次读入或写入是一个记录。记录的长度在  Open  时就确定下来,以后不能改变。如果需要改变,只能  Close  以后再此  Open。
  记录长度在某些编译器下表示读取的  字节长度的倍数,规定为  表示记录长度为  16  字节。有些编译器下就直接表示记录的字节数,规定为  则表示记录长度为  字节。这个问题需要参考编译器手册。在  VF  系列里,这个值是前面一个含义。可以通过设置工程属性的  Fortran,Data,Use  Bytes  as  RECL=  Unit  for  Unformatted  Files  来改变,使之成为后一个含义。在命令行模式下,则使用  /assume:byterecl  这个编译选项。
  确定  RecL  大小是我们需要做的事情,一般来说,不适合太大,也不适合太小。还需要结合数据储存方式来考虑。太小的话,我们需要执行读写的次数就多,太大的话,我们就不方便操作小范围的数据。
  有时候我们甚至会分多次来读取数据,每一次的  RecL  都不同。对于上面的  TestBin.Bin  文件来说,它比较简单,我以  16  字节长度和  字节长度两种读取方式来演示,你甚至可以一次  32  个字节长度全部读完:
   (1)RecL 【记录长度 16 字节】
引用
Program  main
    Implicit  None
    Integer*4  ::  iVar1  iVar2
    Real*4  ::  rVar1  rVar2
    Character(Len=16)  ::  cStr
    Open(  12  File  'TestBin.Bin'  Access  'Direct'  Form  'Unformatted'  RecL  )
    Read(  12  Rec  cStr
    Read(  12  Rec  iVar1  iVar2  rVar1  rVar2
    Write(  cStr
    Write(  iVar1  iVar2  rVar1  rVar2
    Close(  12  )
End  Program  main

  这里的  Open  里指定了  RecL  4(记录长度是  16  字节)。
  第一个  Read  语句,直接读取第二笔记录(也就是第  17  字节到第  32  字节)。读取出的  cStr  "ABCDEFGHIGKLMNOP"。
  第二个  Read  语句,返回来读取第一笔记录(也就是前面  16  个字节)。读取出的数据分别放入  个  字节的变量。(其中前面两个是整型,后面两个是实型)
输出结果为:
  ABCDEFGHIGKLMNOP
                  271                  783      2581.192            1.6892716E-07
  看到这个结果,就说明我们成功了。
  同时我们可以看到,第一个语句,我们直接跳到第二条记录读取,并没有读取第一条。这就是直接读取数据的方便。有时候我们根本不需要某些数据,这时候,我们可以直接跳到某一条记录上。这个记录甚至可以是我们实现算出来的变量。比如:
  iRec  C
        Read(  12  Rec  iRec  cStr
        实现我们储存了  100  天的数据,我们只需要第  21  天的数据,我们怎么办?在顺序读取时,我们可能会开辟一个  100  元素的数组,或者循环执行  20  次空白的读取。但是在直接读取时,我们只需要执行一句  Read(  12  Rec  21  )。这是多么的方便。(直接读取和顺序读取虽然于文本文件和二进制文件没有直接的关联,但是文本文件通常用顺序读取,而二进制文件通常用直接读取。这是他们的性质决定的。)
        (2)RecL 2【记录长度为 字节】
引用
Program  main
    Implicit  None
    Integer*4  ::  iVar1  iVar2
    Real*4  ::  rVar1  rVar2
    Character(Len=16)  ::  cStr
    Open(  12  File  'TestBin.Bin'  Access  'Direct'  Form  'Unformatted'  RecL  )
    Read(  12  Rec  cStr(  16  )
    Read(  12  Rec  cStr(    )
    Read(  12  Rec  iVar1  iVar2 
    Read(  12  Rec  rVar1  rVar2
    Write(  cStr
    Write(  iVar1  iVar2  rVar1  rVar2
    Close(  12  )
End  Program  main
       
  这里设定的  RecL  ,意思是一笔记录  个字节。所以我们不能一次读取  cStr  这个  16  字节的字符串。我们必须分两次读取。第一次读取第  笔记录,放入字符串后半段。第二次读取第  笔记录,放入字符串前半段。(可以调换位置)。然后读取第一笔记录的两个整型变量和第二笔记录的两个实型变量。
  输出结果和(1)的方法一样。
   (3)写入二进制文件
  写入二进制文件同样需要考虑  RecL  的问题。我们这里以  RecL  来举例。
引用
Program  main
    Implicit  None
    Open(  12  File  'TestBinW.Bin'  Access  'Direct'  Form  'Unformatted'  RecL  )
    Write(  12  Rec  271  783  2581.192_4  1.6892716E-07
    Write(  12  Rec  "ABCDEFGHIGKLMNOP"
    Close(  12  )
End  Program  main


  写入二进制文件和读取二进制文件是差不多的,我就不再解释了。需要注意的是,如果直接写入第  笔记录,而文件没有只有  笔记录(M  N),那么,第  M+1  到第  N-1  笔记录会用  填充。也就是说,二进制文件不会出现断裂。

  二进制文件的读写是比较灵活的,实际应用中,我们使用哪种方式,我们应该根据自己的情况来设计。如何选择合适的记录长度  RecL,如何设计高效的储存方式等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值