为什么写这篇文章?
因为在工作过程中, 经常会切换Linux 和Windows, 操作文档时有两次遇到莫名的问题, 怎么查程序都查不出来, 因为逻辑都没问题,但是数据就是出错了。查了N天,发现是不同操作系统换行符的问题,搞得血都吐了一堆。而网上很多文章感觉都没有讲的很清晰。
为了不让大家重蹈覆辙,参考了其他网站的文章,特地总结了一下, 希望能在一篇文章里把问题讲解清楚。
当然,如果其中理解有误的地方,请各位提出来。本来想分析一下源码,但是没有找到相关windows下转换的源码,就暂时不剖析了。如果各们有找到源码的同学,也可以分享一下,谢谢。
回车换行符的历史背景:
早期的计算机输出设备不是显示器,而是电传打字机,结构与普通的打字机差不多。有一个打印头在纸上打字,同时有一个电动机控制纸张的进出。当打印头到达行尾的时候,需要两个动作才能够到达下一行的行首:
1: 首先执行回车动作,将打印头移动到本行的行首;
2: 然后进行换行动作,电动机将纸张向上移动一行,这样打印头就处于下一行的行首,可以继续进行打印。
回车和换行对应的控制字符分别是\r和\n,这就是windows中换行符为\r\n的由来。
后来由于经常连续执行,所以在打印机中将这两个控制字符简化为一个控制字符,这就是linux/unix中的换行符\n的由来。
不同操作系统换行符的区别:
Unix 系统中: 每行结尾只有 "<换行>",即 "\n";
对应十六进制0x0A
Windows 系统中: 每行结尾是 "<回车><换行>",即 "\r\n";
对应十六进制0x0D 0x0A
Mac 系统中: 每行结尾是 "<回车>",即 "\r"。
对应十六进制0x0D
由于换行符不同, 导致的结果是:
Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;
而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号.
而在 windows下操作文件fopen使用”r”和”rb”打开文件, 结果是不一样的(Linux下没有区别):
如果 fopen是”r”文本方式打开, 读文件时会自动转换换物符\r\n为 \n。
如果 fopen是”r”文本方式打开, 写文件时会自动转换换物符\n为 \r\n。
如果 fopen是”rb”是以二进制方式打开,不会自动转换。
环境实验:windows 下fopen “r” 和”rb”的区别
在windows环境和Linux环境下,分别建立一个文本,内容相同:
Hello World!
5AA555AA
windows下创建的文件,命名为windows.txt
Linux下创建的文件,命名为Linux.txt
写个程序将使用fopen( path, “rb” ) 文本里面的内容读出来:
#include <stdio.h>
int main( int argc, char ** argv ){
FILE *fp;
char buf[255] = { 0 };
size_t num = 0;
int i = 0;
if( argc != 2 ){
printf( "You need to input the file to read!" );
return -1;
}
if((fp = fopen( argv[1], "rb" )) == NULL )
printf( "file open failed!" );
while( (num = fread(buf, sizeof(char), 10, fp )) > 0 ){
for( i = 0; i < num; ++i ){
printf( "%02X", buf[i] );
}
}
fclose( fp );
return 0;
}
fopen( path, “rb” ) 输出结果为:
结果如下:
windows下创建的文本换行符仍然是 0D0A(即\r\n),
Linux下创建的文件为 0A(即\n)
将上述代码改为 fopen( path, “r” )
结果如下:
如上, 换行符统一被转换为0A(即\n)
注意:
如果Linux创建的文本,在windows下有编辑过,文件里面的0A会被转换为0D0A
比如我复制一份Linux.txt 为Linux1.txt, 在windows下用记事板打开文件,显示文件为:
按CTRL+S保存后, 0A被转换为0D0A:
文件格式转换:
那如果我们有文件需要在不同的操作系统中来回切换操作, 怎么处理文档内的换行符呢?
方法1: NotePad++ 转换
设置行尾符格式:编辑 -> 档案格式转换 ->(可选 Windows、Unix 和 Mac中的一种)(如果是英文版的 Notepad++,则应该是 Edit -> EOL Conversion -> Windows Format、Unix/OSX Format、Old Mac Format。)
方法2: 使用UNIX命令转换:
unix2dos -k xxx_file
dos2unix -k xxx_file
参考文章: 1: https://blog.csdn.net/wzb56_earl/article/details/6860358