c语⾔写⼆进制⽂件换⾏符,⼩⼩换⾏符乱谈(⽂本⽂件vs⼆进
制⽂件)
使⽤ C 语⾔的 打开⽂件时,可以指定的 mode 有 12 个,其中 6 个包含
"b"
使⽤ C++ 的 fstream 打开⽂件时,可⽤的模式组合有 24 个(?),其中 12 个包含
"binary"
使⽤ python 的 open 打开⽂件,除了可以使⽤ C 中的 12 个模式外,还可以使⽤
"U" 或 "rU"
使⽤ Qt 库的 QFile 打开⽂件时,可以指定
QIODevice::Text
或不指定
.
..
如此种种,看起来是如此的复杂,难怪很多刚接触编程的⽹友都不相信(或者不想相信):
这⼀切仅仅是为了⼀个⼩⼩的换⾏符!
是啊,⼀个⼩⼩的换⾏符值得如此⼤动⼲⼽么?
当使⽤ windows 下的记事本时,会不会遇到:本该换⾏的地⽅,它显⽰⼀个⿊⾊⽅块?
当使⽤⾼级点的编辑器时,是不是都提供设置换⾏符的功能?
当使⽤跨平台的⼯具 (⽐如windows下git) ,是不是需要特别注意换⾏符设置?
...
⽂本 vs ⼆进制
哎,等等...
你前⾯提的C中的"b",C++中的"fstream::binary",Qt的"QFile::Text",我都知道啊:不是区分⽂本和⼆进制操作的么?和换⾏符有什么关系?!
那么我们有必须要看看:
什么是⽂本⽂件(Text File)?
所有的⽂件都是⼆进制⽂件(Binary File)
如果⼀个⼆进制⽂件的内容全是可打印的字符和空⽩字符(空格、Tab、回车、换⾏等)组成,可称其为⽂本⽂件。
换句话说:本来就不存在 ⽂本⽂件 这个独⽴类别,⽂本⽂件属于⼆进制⽂件。
如果这样,为何C、C++等等打开⽂件是都提供⽂本和⼆进制两种模式么?(暂不解释^_^)
考虑⼀个例⼦:打开⽂件(不管后缀名等等),分别写⼊:
"/x10/x11/x12/x13/x14"
不可见字符
"/x30/x31/x32/x33/x34"
⽽后者由于全部是可打印字符,你可能就会称其为⽂本⽂件。
⽂件 vs 模式
注意区分两个概念:当我们提C、C++打开⽂件的⽅式时,我们⼀直在说 ⽂本模式 和⼆进制模式,⽽不是说打开 ⽂件⽂件 和⼆进制⽂件。这中间有很微妙的区别。
任何⼀个⽂件,你都可以⽤⽂本或⼆进制模式打开。但是对于 *.png 等这些东西,你⽤⽂本模式打开读进来的往往不是你期望的结果。
考虑这样⼀个⽂件 ,其内容:
line1/r/nline2/r/n
如果在windows下:你⽤⽂本模式打开,读进来多少个字符?⽤⼆进制模式打开,⼜是多少个字符?为何同⼀个⽂件,读进来的不⼀样?
换个⾓度考虑考虑
我们前⾯提到(C、C++、Python、还有不该和语⾔并列Qt)的⽂件操作,都是需要通过系统调⽤对⽂件进⾏操作的。具体⼀点:
在Windows下,不管通过哪种⽅式,最终都需要使⽤
HANDLE WINAPI CreateFile(
__in LPCTSTR lpFileName,
__in DWORD dwDesiredAccess,
__in DWORD dwShareMode,
__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
__in DWORD dwCreationDisposition,
__in DWORD dwFlagsAndAttributes,
__in_opt HANDLE hTemplateFile
);
参数很多,每⼀个参数⼜有很多标记位组成(具体看MSDN)。但是你可以发现:对它来说,不存在⽂本⽂件和⼆进制⽂件的区别,你也⽆法设置text或binary等标记位!!
在posix 系统下,⽂件操作需要
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
int creat(const char *pathname, mode_t mode);
同样,这⼉可以设置flags和mode,可以设置的标记很多。但是就是没有提供text和binary相关的东西!!
是不是很有意思?
系统的⽂件操作接⼝压根就没有⼆进制和⽂本的区别!
使⽤这些接⼝的C、C++、Python 却提供了⼆进制和⽂本两种模式
换⾏符
是时候谈
换⾏符
了:
line break
EOL (end-of-line)
想象⼀下,⼀个⽂本编辑器打开⼀个"⽂本⽂件",遇到哪个字符开始换⾏呢?
想想Windows下的记事本,遇到遇到"/r/n"它处理成换⾏,遇到'/n'它就只会显⽰⿊⽅框。
应⽤程序和操作系统通常⽤1到2个字符代表换⾏:
CR+LF
Windows、DOS、Symbian、Palm ...
LF
GNU/Linux、Mac OS X、FreeBSD ...
CR
Mac OS 9(之前)...
LF+CRc语言ide编辑器
Acom BBC
RS
QNX 在posix之前
NEL
z/OS、i5/OS ...
...
...
这些之中,其实我们也只对 CR+LF 与 LF 这两种换⾏符感兴趣。
有什么问题么?
本来⼀切很正常的:
在Windows下:
调⽤ CreateFile 打开⽂件
HANDLE hFile = CreateFile (TEXT(""), GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
调⽤ WriteFile 写⼊两⾏
DWORD dwBytesWritten;
WriteFile (hFile, "line1/r/nline2/r/n", 14,
&dwBytesWritten, NULL);
调⽤CloseHandle关闭⽂件
CloseHandle(hFile);
在Posix系统下
调⽤open打开⽂件
int fd = open("", O_WRONLY|O_CREAT);
调⽤write写⼊两⾏
write(fd, "line1/nline2/n", 12);
调⽤close关闭⽂件
close(fd);
各个平台相安⽆事,windows下你想换⾏就⽤'/r/n',posix下想换⾏就⽤'/n'
如何就出问题了呢?
各个平台的换⾏符不⼀致,⼀旦涉及跨平台问题就出来了。
考虑⼀下,如果使⽤C语⾔的binary模式的话,我们想⽣成⼀个像前⾯⼀样包含两⾏代码的⽂件,该怎么办?根据平台不同,⽤#if #else 进⾏预处理?
#ifdef _WIN
fwrite("line1/r/nline2/r/n");
#else
fwrite("line1/nline2/n");
#endif
还是采⽤某种⽅式,同⼀⾏代码:在不同平台下⽣成不同的东西
fwrite("line1/nline2/n");
应该就是为了这个吧,引⼊了⼀个"⽂本模式"
写⼊时,遇到'/n'就转换成平台相关的换⾏符(对与windows就是"/r/n");
读⼊时,遇到平台相关的换⾏符(⽐如windows下的"/r/n"),转换成'/n'
注意:对与posix系统,'/n'就是系统换⾏符,不存在转换
所以我们经常听说:linux下⽂本⽂件和⼆进制⽂件没有区别。
正是为了这个换⾏符,所以C、C++、Python等语⾔提供的⽂件操作函数才都有了Text、Binary两种模式:C、C++、Qt
C语⾔的⽂件操作
#include
FILE *fopen(const char * restrict filename, const char * restrict mode);
除了⽂件名之外,还要传递⼀个 mode 的字符串作为标记。⽽这些标记分为带b和不带b两类:
⽂本
⼆进制
r
rb
只读或只写
w
wb
⽂件存在则清空、不存在则创建
a
ab
追加;⽂件不存在则创建
r+
r+b
rb+
读写
同r和rb
w+
w+b或 wb+
同w和wb
a+
a+b或 ab+
同a和ab
C++的⽂件操作时
explicit fstream ( const char * filename,ios_base::openmode mode = ios_base::in | ios_base::out );除了⽂件名之外,我们需要传递⼀个 mode:
app
(app
end) 每次写操作前到⽂件尾
ate
(at e
nd) 打开⽂件后⽴即将⽂件定位到⽂件尾
binary
(binary
) 以⼆进制模式进⾏IO操作
in
(in
put) 允许读操作

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。