`

深入:文本格式和二进制格式到底有什么不同?

阅读更多
一、理论分析
用C语言,经常碰到文件操作。关于二进制文件和文本文件,他们之间到底有什么不同呢?在这篇文章里,我用自己的方式来解读!不对之处,望各位牛人多指点,或联系我jiadongkai@gmail.com.
    我们都知道,在机器层面,所有的信息都是0/1,所有的信息都是通过0和1不同排列方式形成的。所以,信息不在于0和1这两个字符本身,而在于表示不同意思的这0和1两个符号的排列中所体现出的。我们都知道0和1在物理层面是脉冲的两种极值,如果在物理层面,可以显示区别的脉冲不止两个极值,而是多个值或者连续的值,这样在计算机的逻辑层面就不止0和1这两个符号了,可以有很多符号,于是,负好多了,他们排列组合的方式多了,信息的表达应该也更加高效和丰富了。
    上面一段,“信息”在机器层面是通过0和1的排列方式来体现的。可是这些0和1如何变成我们在windows环境下的记事本中看到的文本或者图片查看器中看到的图片呢?这里面就有一个编码的问题!所以,二进制文件和文本文件的不同就是编码层面的不同,二进制文件是值编码,如ASCII的文本文件文件是ASCII编码。文本编码可以是定长的(如作为基础的ASCII一个字符总是7位的,Unicode16位),也可以是不定长的(如UTF-8)。而值编码是不定长的(如BMP),它通过一定的读取规则来解释这些字节甚至一个bit就能包含一个信息。
     除了在内存和文件信息转存的时候有编码问题,在、
1、developer直接能看见的文本格式的源程序到内存的映射关系
2、从程序的内存到输出终端
这两个方面也同样存在编码转换问题!
     下面,我用一个图列出源程序(文本形式,如a.c)、内存、文件、输出终端这四方(其实输出终端、文件可以并在一起,都作为从内存中输出一类)之间编码转换的关系:



下面来解释这张图:
1、从“源程序”到“内存中”
在Java中"\r\n"等效于C中的"\n":java中中直接打印"\r\n"或者把这个字符串存进文件中用文本查看器打开都是换行的效果;在C中按文本文件的形式存,用文本查看器打开也是换行的效果,不过用二进制的形式存(保留内存中原来的格式),用文本查看器打开就会出现乱码码。
故,java中的"\r\n"和C中的"\n"在内存中都是“00001010”,所以在Java中有个转码,C中无需转码。
在源程序是字符的形式通过编码转码为内存的形式(这个编码格式是可以配置的),如果是整型或者浮点型等的也有固定的内存表示形式。
2、从“内存中”到“文件中”
看存储的格式,如果是二进制形式,数据原来在内存中怎么一个0和1排列,在文件的存储区域中还是同样的。
如果是文本格式,需要做些转码操作(如换行转为回车换行,整形数据由Turbo C++ 3.0环境下的占2Byte变为字符串的表现形式,可能就占用更多存储空间了);
3、从“文件中”到“内存中”
在C中fopen函数可以指定打开文件的形式(文本形式或者二进制的)。这两种形式的读取存在以下一些不同点:
二进制形式读取,不对文件的内存中的0和1的排列顺序做任何的调整,相当于文件存储空间和程序内存空间的之间平移;此时最小信息单位是位。也就是说一个bit就可以用来存储一个信息(如成功/失败)。我们需要在程序中对这些读进来的二进制数据按规则解析(如前两个byte可以组织成一个int类型数据等)。
文本格式读取,需要将回车换行符转换为换行符。此时最小信息单位是字节。
4、从“内存中”到“调试输出终端”
C中,一个int类型数据在内存中两个byte,要输出到终端,需要转换为文本格式的编码输出到指定的缓存,然后终端的解释器将这些字符串解释成一串字节显示在屏幕或者别的地方。


二、实验验证

    之前在思考二进制文件和文本文件的不同的时候,心想:有一个查看器,可以查看文件的二进制形式多好!
    于是,自己用c语言实现了一个在Doc命令行操作的“文件的二进制形式查看器”。这个查看器可以以文本方式和二进制方式两种方式读入文件,然后逐个自己打印出文件中的数据,打印的时候一个字节显示为八位1/0。也就说,我可以适合用这个查看器完成以下的功能:
1、以二进制形式查看文件----->可以知道数据在文件的存储空间中0/1的排列形式,直观的看出。
2、以文件形式查看文件------->可以知道文件读入函数都默认都做了哪些转码工作。如,回车换行转化为换行(在机器码层面就是:"0000110100001010"-->"00001010")

贴出所有的代码:
首先我自己创建了一个头文件:myhf.h
#include <string.h>
char _str[17];/*多出的一个字符串表示字符串的结束*/
/*
将一个字符的内存形式转化为字符串形式
即'\n'-->"1010"
*/
char * cTob(char c){
	unsigned i,a;
	i=c;/*直接将字符的内存拷贝到整型对应的内存中*/
	/*不管系统是高位补零还是补一,高位都清零*/
	a=~((~0)<<8);/*如果右移,因为是负数,这里是算数右移*/
	i=i&a;
	itoa(i,_str,2);/*整数i转化为二进制存在str数组中*/
	return _str;
}

一个C源程序:
FileReader.c

程序可以配置文件读入方式1.文本2二进制
和读取文件的路径(绝对路径或相对路径)、
量个参数
配置好参数,自动组个字节打印文件中数据,每个字节间
空一格以便查看,每个字节打印8位,不足右对齐,多余位置用
空格表示
/*
一个读取和打印文本格式和二进制格式的应用程序
@author 贾懂凯@netjava
*/
#include <stdio.h>
#include <string.h>
#include <myhf.h>
void main(){

	void showTextFile(char[]);
	void showBinFile(char[]);
	char fileName[21];
	int fileFormat;
	/*1、用户确定需要解读的文件的格式*/
	printf("please input text formart:1text 2binary\n");
	scanf("%d",&fileFormat);
	/*2、用户给出文件的名字*/
	printf("please input file-name(len<20):\n");
	
	scanf("%s",&fileName);
	/*3、根据用户需要解读的文件的格式判定调用哪个函数*/
	if(fileFormat==1){
		showTextFile(fileName);
	}else if(fileFormat==2){
		showBinFile(fileName);
	}
	printf("\n");
	printf("p:Print out the  data in the form of  memory representation (by-character printing, each person  with a single space between the characters, each character is eight less than equal amount of space)\n");
}

/*将文本文件读入,打印到终端显示成二级乃至形式*/
void showTextFile(char name[21]){
	FILE * fp;/*一个在stdio.h文件中定义的对应一个文件的结构体数据*/
	fp=fopen(name,"r");
	while(!feof(fp)){/*直到文件读取结束*/
		char c=fgetc(fp);
		char * cp=cTob(c);/*转换成二进制形式的字符串形式*/
		printf("%8s ",cp);
	}
	fclose(fp);
}
/*将二进制文件读入,打印到终端显示成二级乃至形式*/
void showBinFile(char name[21]){
	FILE * fp;/*一个在stdio.h文件中定义的对应一个文件的结构体数据*/
	fp=fopen(name,"rb");
	while(!feof(fp)){/*直到文件读取结束*/
		char c=fgetc(fp);
		char * cp=cTob(c);/*转换成二进制形式的字符串形式*/
		printf("%8s ",cp);
	}
	fclose(fp);
}



下面,我写了一个测试程序:
DemoFile.c

#include <stdio.h>
#include <string.h>

/*
测试文本文件和二进制文件的区别
这里写入字符 "ab贾懂凯\na\r\na"
*/
void main(){
	char s[]="ab贾懂凯\na\r\na";
	FILE * fp=fopen("a.txt","w");/*文本格式输出*/
	fprintf(fp,"%s",s);/*格式化输出到文件*/
	
	fp=fopen("b.txt","wb");/*二进制格式输出*/
	fprintf(fp,"%s",s);/*格式化输出到文件*/
}

先编译连接然后运行测试程序DemoFile.c,生成的两个文件截图:



然后,运行我写的&quot;文件的二进制形式查看器&quot;,doc命令行截图:



从这张doc命令行截图可以看出这个&quot;文件的二进制形式查看器&quot;打印出的0/1字符串的效果。这些字符串就是文件读入内存后的形式(在内存中0/1的排列方式这里如是打印出来了)。

到这里,对文本格式和二进制格式的区别。大家应该有一个比较深入和直观的印象了。其实,简单说,就是程序在内存、在硬盘空间或者在别的地方同一个东东有不同的表现形式而已,而这种表现形式的不同就是编码的不同造成的。当然,这篇文章里面并没有提到各种编码格式的优缺点,如二进制文件能够节省空间等等。有兴趣的朋友可以自己进一步探究!

补充:
上面解释的不是很清晰,参考这里http://wenku.baidu.com/view/d2b6a923dd36a32d7375810e.html
再给出清晰一点的定义:
所有的文件在内存和磁盘中都是二进制格式的,但由于解释这些01的编码方式不同,导致甚至同一串01都有不同的意义。不过,一般应保持写入和读取相同的编码方式。
所谓文本格式,指编码方式为UTF8等字符编码,最小的单位为byte
所谓二进制格式,指字符编码以外的编码方式,对文件中01的解释有其特有的一套规则,如BMP。当然,这种格式的文件使用window下的记事本(只支持字符编码)显然是乱码,BMP可用图片查看器解码。

另外,
C语言文件的读写,需要制定是文本格式还是二进制格式,区别是文本格式读入0000110100001010(\r\n)这个byte会变成00001010(\n),而二进制格式读入00001010依然是00001010。上面只对windows有效,在linux下\n在文本格式下写入文件也不变。

不知这样的理解有无偏差,望高手指点!



  • 大小: 74.1 KB
  • 大小: 11.4 KB
  • 大小: 175.4 KB
1
3
分享到:
评论
1 楼 weiwangchao 2015-09-08  
最后一段没看明白。

相关推荐

    Python数据分析实践:numpy读写文件操作new.pdf

    NumPy文件读写主要有二进制的文件读写和文件列表形式的数据读写两种形式: save函数是以二进制的格式保存数据 load函数是从二进制的文件中读取数据 savez函数可以将多个数组保存到一个文件中 存储时可以省略扩展名,...

    klog:纯文本文件格式和命令行工具,用于时间跟踪

    klog是纯文本文件格式,是用于时间跟踪的命令行工具。 ✦–了解如何使用klog ✦更新–查看最新更改 ✦–深入了解文件格式 获取博客 苹果系统 并解压缩 右键单击二进制文件,然后选择“打开”(由于 ) 复制到路径...

    深入Windows下的回车是回车换行(\r\n)还是换行回车(\n\r)的详解

    现在用C语言二进制形式将其读入字符串(可以参考我的一篇文章:深入C语言把文件读入字符串以及将字符串写入文件的解决方法)并按十进制输出。结果如下 可以看出回车是13和10也就是\r\n,即先回车后换行。 下面我们...

    深入SQL截取字符串(substring与patindex)的详解

    基本语法:SUBSTRING ( expression , start , length ) expression:字符串、二进制字符串、text、image、列或包含列的表达式start:整数,指定子串的开始位置 注:SQL中”1″表示字符串中的第一个字符,而.NET中”0″...

    c#-对象的txt保存、序列化和反序列化

    实现对象的保存、读取文本文件、二进制序列化和反序列化。通过这些实例,我们能够深入了解如何将对象的属性信息以不同的方式进行持久化,并在需要时再次还原,从而提高数据的可管理性和可维护性。

    注册表实用手册

    大家可以看到,dword是16进制,hex是二进制,字符串则可以直接赋值。只要将上面的内容复制保存到文本文档里,然后另存为你想要的.reg文件运行就可以了。呵呵,原来也不是很难嘛,耐心一点就可以了。当然,你要模仿,...

    ExamDiff Pro - 可视化文件和目录比较工具 3.3

    - 比较文本文件,二进制文件和目录。 - 高亮不同差异 (深入到行、词、字符级别)。 - 允许在文件比较窗格内编辑文件。 - 打印和打印预览差异报告。 - 完全支持 UNICODE。 - 允许为以后的比较创建目录快照。 - ...

    Hadoop权威指南 第二版(中文版)

     二进制输入  多种输入  数据库输入(和输出)  输出格式  文本输出  二进制输出  多个输出  延迟输出  数据库输出 第8章 MapReduce的特性  计数器  内置计数器  用户定义的Java计数器  用户定义的...

    C语言入门经典(第4版)--源代码及课后练习答案

    10.3.5 读取十六进制和八进制值 379 10.3.6 用scanf()读取字符 381 10.3.7 scanf()的陷阱 383 10.3.8 从键盘上输入字符串 383 10.3.9 键盘的非格式化输入 384 10.4 屏幕输出 389 10.4.1 使用printf()格式输出...

    Perl编程24学时教程(PDF格式,共24章)

    5.4 自由文件、测试文件和二进制数据 60 5.4.1 自由文件句柄 60 5.4.2 二进制文件 60 5.4.3 文件测试运算符 61 5.5 课时小结 62 5.6 课外作业 62 5.6.1 专家答疑 62 5.6.2 思考题 63 5.6.3 解答 63 5.6.4 实习 63 第...

    亮剑.NET深入体验与实战精要3

    9.2.7 读写二进制文件 372 9.2.8 文件复制、移动、删除 374 9.3 文件夹目录操作 375 9.4 读写INI文件 376 9.5 读写注册表 379 本章常见技术面试题 381 常见面试技巧之经典问题巧回答 381 本章小结 382 第10章 网络...

    Hadoop权威指南(中文版)2015上传.rar

    二进制输入 多种输入 数据库输入(和输出) 输出格式 文本输出 二进制输出 多个输出 延迟输出 数据库输出 第8章 MapReduce的特性 计数器 内置计数器 用户定义的Java计数器 用户定义的Streaming计数器 排序 准备 部分...

    Intel汇编语言程序设计 第四版

    ·IEEE浮点二进制表示法 ·虚拟机体系结构,IA-32保护模式分段和分页 ·介绍指令执行周期、内存、多任务、流水线和超标量体系结构 ·磁盘基础知识,包括磁盘的物理结构、FAT32和NTFS文件的结构 .PDG格式

    深入浅析mybatis oracle BLOB类型字段保存与读取

     BLOB是指二进制大对象也就是英文Binary Large Object的所写,而CLOB是指大字符对象也就是英文Character Large Object的所写。其中BLOB是用来存储大量二进制数据的;CLOB用来存储大量文本数据。BLOB通常用来保存...

    wsServer:wsServer-用C编写的微型WebSocket服务器库

    主要特点是: 发送/接收文本和二进制消息PING / PONG框架打开/关闭握手请参阅高速公路和以进行“深入”分析。建造wsServer仅需要与C99兼容的编译器,还可以选择Doxygen来生成文档。 构建过程有两种形式:纯makefile...

    《Qt 学习之路 2》

    基于最新的Qt5.0.1的学习书籍,非常适合QT5的入门学习。 适合了解QT5与QT4区别的新手。 文章结构如下: ...36 二进制文件读写 37 文本文件读写 38 存储容器 39 遍历容器 40 隐式数据共享 41 model/view 架构

    Intel汇编语言程序设计(第四版)

    ·IEEE浮点二进制表示法 ·虚拟机体系结构,IA-32保护模式分段和分页 ·介绍指令执行周期、内存、多任务、流水线和超标量体系结构 ·磁盘基础知识,包括磁盘的物理结构、FAT32和NTFS文件的结构 .

Global site tag (gtag.js) - Google Analytics