【转】一个问题引发的"血案" 之 文件的读写原理(fread, fwrite, fflush)
2014-03-27 00:57
751 查看
代码很简单:
以rb+形式打开一个已存在的文件(文件内容是abcdefghijklmnopqrstuvwxyz
),然后随便读几个字节,然后直接调fwrite,返回值是正确的,但是fclose后,双击打开文件,文件内容没变。
反之,以rb+形式打开一个已存在的文件(文件内容也是abcdefghijklmnopqrstuvwxyz
),随便写几个字节(写了hello world),然后直接调fread,只读出了ヘヘヘヘヘヘヘヘヘヘ,而且fclose后,双击打开文件,文件内容变成hello worldヘヘヘヘヘヘヘヘヘヘvwxyz
但是在fread和fwrite之间调一下fseek,读写内容就都对了,请问高手,这为什么呢?
fread和fwrite为什么不能连续调用?
具体代码如下:
问题原帖在这里,感觉原帖下面的答案讲的不是很详细和准确,求大神解答!
评论 (0) • 分享 • 链接 • 2012-12-08
9个答案
票 数
kenvi 50
6 票
2058
最佳答案
这个问题非常好,我仔细看了一下flush.c,fwrite.c和fread.c找到了原因。
首先,我们得了解应用程序和文件直接数据的交互是通过缓存来实现的,fread和fwrite操作的数据都是缓存(如果设置了缓存的话)里的数据。那么数据交互的模型如下所示:
然后,我们再看看fread,fwrite,fflush是如何来实现这个交互的过程呢。这三者对文件的操作都是通过FILE结构来进行的,我们先看看FILE的结构:
以上代码来自http://www.codeforge.com/read/90183/STDIO.H__html
这里是VC里的实现,不同的实现可能会有所差别,但是因为是标准IO,基本上是大同小异。
上面只是简单标注了几个重要的变量的意义。下面我来解释一下这几个变量:
FILE:这个结构其实包含的是文件信息(_flag,_file_,_tmpfname)和缓存信息(_ptr,_cnt,_base,_charbuf,_bufsiz)。
_ptr:它指的是当前操作的位置
_base:文件缓存的起始位置
bufsiz:缓存的大小
下面用图表示一下这几个变量:
当打开一个文件,并进行读取时,会先从磁盘读取一部分数据到缓存里,这时候_base指向缓存的起始地址,_ptr会根据读取的数量进行移动,_cnt则根据读取的数量进行减少。
这里只是一个简化的流程,具体参考fread.c代码http://www.codeforge.com/read/90183/FREAD.C__html
当打开一个文件,并进行写操作时,会先分配一块缓存,这时候_base指向缓存的起始地址,_ptr会根据写入缓存的数量进行移动。
这里只是一个简化的流程,具体参考fwrite.c代码http://www.codeforge.com/read/90183/FWRITE.C__html
我们再看看fflush的操作
代码参考http://www.codeforge.com/read/90183/FFLUSH.C__html
这里做了两件事:
把缓存里的输入写入文件,_write系统调用,写入的数据为缓存里[_base,_ptr]之间的数据
设置_ptr和_cnt:
也就是说,flush除了写入文件外,它还把_ptr的位置重新设置到缓存的开始处了。
也就是说,上面程序的问题在于_ptr的值,这里可以简单验证一下,把
那么,为什么问题是出现在_ptr上呢?下面来怎对上面的代码进行分析:
我给你上面的代码画了一个图,和上面两幅图略有不同
可以看到,在调用一次fwrite和一次fread后,_ptr指针的位置距离_base为21(11+10)。那么,最后的close在flush的时候会把[_base,_ptr]之间的内容输入到文件中对应的位置。也就是说fwrite写入的hello world和fread调用导致_ptr移动的部分数据也被写入到文件了,这样就导致覆盖了文件里的部分数据。
那么还有一个问题,覆盖的数据是什么呢?
数据是随机的。因为整个过程是这样的:
打开文件
建立缓存,这个缓存里的数据是未初始化的4096字节,
fwrite写入hello world在0-10字节里
fread使得_ptr跳过11-20字节
flush使得0-20字节写入文件,其中0-10是hello world,11-20未初始化
再看看读文件的过程
打开文件
建立缓存,并且读取部分文件内容到缓存里
读取文件
上面两个过程中的第2个过程是要调用fseek或者flush的关键所在,因为读写用的是同一块缓存,所以读之后再写要重置缓存,写之后再读也要重置缓存。否则两种操作会导致缓存里的数据错乱。因此,严格来说,我前面的用
=====================结束===============================
虽然花了不少时间,但是把这个问题弄明白了,自己也想通了另外一个问题,就是java的NIO里的ByteBuffer在读写之前分别要调用flip和clear,原因也是因为读写用的是同一块缓存。
如果有什么不清除的地方,请回复。我尽量解答
=======================补充内容=========================
可以通过下面的代码来看看FILE结构里的_ptr,_base,_cnt几个字段的变动
=====================补充解释一下前一部分的数据为什么没有写入==============
看看flush的代码,在写入数据的时候,会做如下判断:
这段代码做了如下三个判断:
stream->_flag & (_IOREAD | _IOWRT)) == _IOWRT:判断flush之前的操作只有写操作
bigbuf(stream) 这个貌似是判断缓存的大小
nchar = stream->_ptr - stream->_base) > 0 判断[_base,_ptr]之间是否有数据没有写入
按照前面讲解的过程,可知[_base,_ptr]之间肯定是有数据的,至于bigbuf(stream)这个不知道是判断什么的,暂且假设它是true。再看看第一个判断,我们的代码是先读后写,不满足这个条件,因此,flush不会把数据写入到磁盘。这就是为什么数据没有写入的原因了。
下面来证实一下:
上面的代码把flag的读标志去掉,并且加上写标志位,运行一下,这次数据写入了。结果如下:
abcdefghijklmnopqrstuvwxyzabcdefghijhello world
数据是写入了,但是结果貌似不对。。这个问题就留给大家去思考了。
kenvi
编辑于 2012-12-18
评论 (3) • 链接 •
2012-12-18
0
回答的非常详细,谢谢,对已代码的前一部分:
ret = fread(string, 1, 10, testFile);
ret = fwrite("hello world", 1, 11, testFile);
fclose(testFile); //test1.txt的内容还是abcdefghijklmnopqrstuvwxyz
为什么test1.txt的内容还是abcdefghijklmnopqrstuvwxyz呢? – freeboy1015 2012-12-18
0
@freeboy1015 答案我更新了。 – kenvi 2012-12-18
0
不得不赞一个,非常的好。 – _无双 2012-12-20
ajaxhe
3 票
2886
可以看看fseek的源码,VS下的C运行库的fseek会会调用_flush(stream);
如下:
补充:
@kenvi已经解释得很清楚了,这里对他后面遗留的问题进行下补充:
这里强制修改_flag的值会得到意外的结果,原因如下:
在fclose中会调用fflush函数,而fflush函数又会根据条件再次调用系统调用_write函数,进行文件的写操作。
留意这样一行语句:
(nchar = (int)(stream->_ptr - stream->_base))
因为此时
(stream->_flag & (_IOREAD | _IOWRT)) == _IOWRT
和
bigbuf(stream)
都已经成立,这里会计算nchar的值。
看看此时缓冲区的情况:
这里nchar=21,后面调用:
_write(_fileno(stream), stream->_base, nchar)
就会将字符串
abcdefghijhello world
写入到test1.txt中。
问题讨论到这里,似乎还有一个重要的问题没有解释:
为什么“abcdefghijhello world”是在文件结尾处写,而不是紧接着文件第11处偏移开始写?是谁在修改文件的实际偏移?
ajaxhe
编辑于 2012-12-19
评论 (1) • 链接 •
2012-12-09
0
正解.... – Bechengxvyuan 2012-12-19
zhujinliang
1 票
1190
那个帖子说的挺明白了,写出后,或关闭文件前,应调用fflush,将缓存更新到文件中。
打开文件后,会在内存中产生一部分文件的缓存,通过fwrite等写出,是先写入缓存,待缓存不够用了、或者用户调用fflush时,系统才将缓存中的数据同步到文件中。
评论 (2) • 链接 •
2012-12-08
0
代码中用的是fseek,没有用fflush啊 – freeboy1015 2012-12-08
0
对于test2.txt的内容变成hello worldヘヘヘヘヘヘヘヘヘヘvwxyz还是不太理解?请详细解释一下,谢谢! – freeboy1015 2012-12-10
__mt
0 票
3279
@zhujinliang同学说的比较对,应该先调用fflush。如果不是这种情况的话,可能是对数据流的某一个操作失败了。导致数据流的设置了failbit。所以导致读写失效。觉得就这两种可能吧
评论 (3) • 链接 •
2012-12-08
0
代码中用的是fseek,没有用fflush啊 – freeboy1015 2012-12-09
0
@freeboy1015 就是说你读完之后要flush一下啊,你查下flush的意思就知道了。。 – __mt 2012-12-09
0
对于test2.txt的内容变成hello worldヘヘヘヘヘヘヘヘヘヘvwxyz还是不太理解?请详细解释一下,谢谢! – freeboy1015 2012-12-10
cyrussu
0 票
1
在你read test2的写入流的时候
缓冲区没有关闭
所以写入流接上了读取流
把后面10个字符给覆盖了
所以你用fread之前也要fflush
评论 (0) • 链接 •
2012-12-17
lixunhuan
0 票
56
我只能表示VC太弱了,标准IO库的实现还是这么老土,在gcc下没调用fseek结果是完全正确的
调用程序后test1.txt是abcdefghijhello worldvwxyz。
test2.txt是hello worldlmnopqrstuvwxyz
平台
gcc 4.7.2 + ubuntu 12.10(64bit)
可怜了大家,都去看标准IO库的实现源代码了~~~
lixunhuan
编辑于 2012-12-18
评论 (0) • 链接 •
2012-12-18
cugxxs
0 票
1
没有区别啊,我把代码运行了一下,对于前一部分的代码,不管加不加fseek函数,最后test1.txt的内容都变成abcdefghijhello worldvwxyz。对于后一部分代码,不过加不加fseek函数,test2.txt的内容都变成hello worldlmnopqrstuvwxyz。
评论 (0) • 链接 •
2012-12-18
黄滨
0 票
1
运行了一下楼主的代码,只是在fread后打印string 结果如下(linux下gcc编译gcc 版本 4.1.1 20070105 (Red Hat 4.1.1-52) ):
[huangbin@localhost shujia]$ ./a.out
string= abcdefghij
[huangbin@localhost shujia]$ cat test1.txt
abcdefghijhello worldvwxyz
能写入的。
但是在VC下确实和楼主说的一样。按理说应该是fread后不用再去定位文件流位置的,直接就能在文件流读取的位置处写入内容。可能是标准IO库版本比较老,需要再定位文件流位置才能写入。
有兴趣可以看看相应的IO库源码。
评论 (0) • 链接 •
2012-12-18
百度
0 票
1
gcc 版本 4.7.2 (Ubuntu/Linaro 4.7.2-2ubuntu1)
cat test1.txt
abcdefghijhello worldvwxyz
cat test2.txt
hello worldlmnopqrstuvwxyz
以rb+形式打开一个已存在的文件(文件内容是abcdefghijklmnopqrstuvwxyz
),然后随便读几个字节,然后直接调fwrite,返回值是正确的,但是fclose后,双击打开文件,文件内容没变。
反之,以rb+形式打开一个已存在的文件(文件内容也是abcdefghijklmnopqrstuvwxyz
),随便写几个字节(写了hello world),然后直接调fread,只读出了ヘヘヘヘヘヘヘヘヘヘ,而且fclose后,双击打开文件,文件内容变成hello worldヘヘヘヘヘヘヘヘヘヘvwxyz
但是在fread和fwrite之间调一下fseek,读写内容就都对了,请问高手,这为什么呢?
fread和fwrite为什么不能连续调用?
具体代码如下:
#include <stdio.h> int main() { FILE *testFile = NULL; int ret = 0; char string[200] = {'\0'}; testFile=fopen("test1.txt", "rb+"); //test1.txt的内容是abcdefghijklmnopqrstuvwxyz if(testFile == NULL) { return 0; } ret = fread(string, 1, 10, testFile); //ret = fseek(testFile, 0, SEEK_CUR); ret = fwrite("hello world", 1, 11, testFile); fclose(testFile); //test1.txt的内容还是abcdefghijklmnopqrstuvwxyz //如果fread和fwrite之间调用了fseek,文件内容变成abcdefghijhello worldvwxyz testFile=fopen("test2.txt", "rb+"); //test2.txt的内容也是abcdefghijklmnopqrstuvwxyz if(testFile == NULL) { return 0; } ret = fwrite("hello world", 1, 11, testFile); //ret = fseek(testFile, 0, SEEK_CUR); ret = fread(string, 1, 10, testFile); fclose(testFile); //test2.txt的内容变成hello worldヘヘヘヘヘヘヘヘヘヘvwxyz //如果fread和fwrite之间调用了fseek,文件内容变成hello worldlmnopqrstuvwxyz return 0; }
问题原帖在这里,感觉原帖下面的答案讲的不是很详细和准确,求大神解答!
评论 (0) • 分享 • 链接 • 2012-12-08
9个答案
票 数
kenvi 50
6 票
2058
最佳答案
这个问题非常好,我仔细看了一下flush.c,fwrite.c和fread.c找到了原因。
首先,我们得了解应用程序和文件直接数据的交互是通过缓存来实现的,fread和fwrite操作的数据都是缓存(如果设置了缓存的话)里的数据。那么数据交互的模型如下所示:
然后,我们再看看fread,fwrite,fflush是如何来实现这个交互的过程呢。这三者对文件的操作都是通过FILE结构来进行的,我们先看看FILE的结构:
struct _iobuf { char *_ptr;//文件缓存的当前位置 int _cnt;//缓存里可以读取的字节数 char *_base;//文件缓存的起始位置 int _flag; int _file; int _charbuf; int _bufsiz;//缓存大小 char *_tmpfname; }; typedef struct _iobuf FILE;
以上代码来自http://www.codeforge.com/read/90183/STDIO.H__html
这里是VC里的实现,不同的实现可能会有所差别,但是因为是标准IO,基本上是大同小异。
上面只是简单标注了几个重要的变量的意义。下面我来解释一下这几个变量:
FILE:这个结构其实包含的是文件信息(_flag,_file_,_tmpfname)和缓存信息(_ptr,_cnt,_base,_charbuf,_bufsiz)。
_ptr:它指的是当前操作的位置
_base:文件缓存的起始位置
bufsiz:缓存的大小
下面用图表示一下这几个变量:
当打开一个文件,并进行读取时,会先从磁盘读取一部分数据到缓存里,这时候_base指向缓存的起始地址,_ptr会根据读取的数量进行移动,_cnt则根据读取的数量进行减少。
这里只是一个简化的流程,具体参考fread.c代码http://www.codeforge.com/read/90183/FREAD.C__html
当打开一个文件,并进行写操作时,会先分配一块缓存,这时候_base指向缓存的起始地址,_ptr会根据写入缓存的数量进行移动。
这里只是一个简化的流程,具体参考fwrite.c代码http://www.codeforge.com/read/90183/FWRITE.C__html
我们再看看fflush的操作
if ((stream->_flag & (_IOREAD | _IOWRT)) == _IOWRT && bigbuf(stream) && (nchar = stream->_ptr - stream->_base) > 0) { if ( _write(_fileno(stream), stream->_base, nchar) == nchar ) { /* if this is a read/write file, clear _IOWRT so that * next operation can be a read */ if ( _IORW & stream->_flag ) stream->_flag &= ~_IOWRT; } else { stream->_flag |= _IOERR; rc = EOF; } } stream->_ptr = stream->_base; stream->_cnt = 0;
代码参考http://www.codeforge.com/read/90183/FFLUSH.C__html
这里做了两件事:
把缓存里的输入写入文件,_write系统调用,写入的数据为缓存里[_base,_ptr]之间的数据
设置_ptr和_cnt:
stream->_ptr = stream->_base;stream->_cnt = 0;
也就是说,flush除了写入文件外,它还把_ptr的位置重新设置到缓存的开始处了。
也就是说,上面程序的问题在于_ptr的值,这里可以简单验证一下,把
ret = fseek(testFile,0, SEEK_CUR);替换成
stream->_ptr = stream->_base也可以得到正确的结果。
那么,为什么问题是出现在_ptr上呢?下面来怎对上面的代码进行分析:
我给你上面的代码画了一个图,和上面两幅图略有不同
可以看到,在调用一次fwrite和一次fread后,_ptr指针的位置距离_base为21(11+10)。那么,最后的close在flush的时候会把[_base,_ptr]之间的内容输入到文件中对应的位置。也就是说fwrite写入的hello world和fread调用导致_ptr移动的部分数据也被写入到文件了,这样就导致覆盖了文件里的部分数据。
那么还有一个问题,覆盖的数据是什么呢?
数据是随机的。因为整个过程是这样的:
打开文件
建立缓存,这个缓存里的数据是未初始化的4096字节,
fwrite写入hello world在0-10字节里
fread使得_ptr跳过11-20字节
flush使得0-20字节写入文件,其中0-10是hello world,11-20未初始化
再看看读文件的过程
打开文件
建立缓存,并且读取部分文件内容到缓存里
读取文件
上面两个过程中的第2个过程是要调用fseek或者flush的关键所在,因为读写用的是同一块缓存,所以读之后再写要重置缓存,写之后再读也要重置缓存。否则两种操作会导致缓存里的数据错乱。因此,严格来说,我前面的用
testFile->_ptr=testFile->_base替代的方式也是有问题的。
=====================结束===============================
虽然花了不少时间,但是把这个问题弄明白了,自己也想通了另外一个问题,就是java的NIO里的ByteBuffer在读写之前分别要调用flip和clear,原因也是因为读写用的是同一块缓存。
如果有什么不清除的地方,请回复。我尽量解答
=======================补充内容=========================
可以通过下面的代码来看看FILE结构里的_ptr,_base,_cnt几个字段的变动
void dumpFile(FILE* file){ printf("====dump file struct=====\n"); printf("ptr:%x\n",file->_ptr); printf("cnt:%d\n",file->_cnt); printf("base:%x\n",file->_base); printf("flag:%d\n",file->_flag); printf("file:%d\n",file->_file); printf("charbuf:%d\n",file->_charbuf); printf("bufsize:%d\n",file->_bufsiz); printf("tmpfname:%s\n",file->_tmpfname); printf("====dump file struct=====\n"); }
=====================补充解释一下前一部分的数据为什么没有写入==============
看看flush的代码,在写入数据的时候,会做如下判断:
if ((stream->_flag & (_IOREAD | _IOWRT)) == _IOWRT && bigbuf(stream) && (nchar = stream->_ptr - stream->_base) > 0) { if ( _write(_fileno(stream), stream->_base, nchar) == nchar ) { /* if this is a read/write file, clear _IOWRT so that * next operation can be a read */ if ( _IORW & stream->_flag ) stream->_flag &= ~_IOWRT; } else { stream->_flag |= _IOERR;
这段代码做了如下三个判断:
stream->_flag & (_IOREAD | _IOWRT)) == _IOWRT:判断flush之前的操作只有写操作
bigbuf(stream) 这个貌似是判断缓存的大小
nchar = stream->_ptr - stream->_base) > 0 判断[_base,_ptr]之间是否有数据没有写入
按照前面讲解的过程,可知[_base,_ptr]之间肯定是有数据的,至于bigbuf(stream)这个不知道是判断什么的,暂且假设它是true。再看看第一个判断,我们的代码是先读后写,不满足这个条件,因此,flush不会把数据写入到磁盘。这就是为什么数据没有写入的原因了。
下面来证实一下:
ret = fread(string, 1, 10, testFile); ret = fwrite("hello world", 1, 11, testFile); //加上写动作,去掉读动作 testFile->_flag |= _IOWRT; testFile->_flag &= ~_IOREAD; fclose(testFile);
上面的代码把flag的读标志去掉,并且加上写标志位,运行一下,这次数据写入了。结果如下:
abcdefghijklmnopqrstuvwxyzabcdefghijhello world
数据是写入了,但是结果貌似不对。。这个问题就留给大家去思考了。
kenvi
编辑于 2012-12-18
评论 (3) • 链接 •
2012-12-18
0
回答的非常详细,谢谢,对已代码的前一部分:
ret = fread(string, 1, 10, testFile);
ret = fwrite("hello world", 1, 11, testFile);
fclose(testFile); //test1.txt的内容还是abcdefghijklmnopqrstuvwxyz
为什么test1.txt的内容还是abcdefghijklmnopqrstuvwxyz呢? – freeboy1015 2012-12-18
0
@freeboy1015 答案我更新了。 – kenvi 2012-12-18
0
不得不赞一个,非常的好。 – _无双 2012-12-20
ajaxhe
3 票
2886
可以看看fseek的源码,VS下的C运行库的fseek会会调用_flush(stream);
如下:
int __cdecl _fseek_nolock (FILE *str, long offset, int whence) { REG1 FILE *stream; /* Init stream pointer */ stream = str; /* Flush buffer as necessary */ _flush(stream); ... /* Seek to the desired locale and return. */ return(_lseek(_fileno(stream), offset, whence) == -1L ? -1 : 0); }
补充:
@kenvi已经解释得很清楚了,这里对他后面遗留的问题进行下补充:
ret = fread(string, 1, 10, testFile); ret = fwrite("hello world", 1, 11, testFile); //加上写动作,去掉读动作 testFile->_flag |= _IOWRT; testFile->_flag &= ~_IOREAD; fclose(testFile);
这里强制修改_flag的值会得到意外的结果,原因如下:
在fclose中会调用fflush函数,而fflush函数又会根据条件再次调用系统调用_write函数,进行文件的写操作。
int __cdecl _flush ( FILE *str ) { /* Init pointer to stream */ stream = str; if ((stream->_flag & (_IOREAD | _IOWRT)) == _IOWRT && bigbuf(stream) && (nchar = (int)(stream->_ptr - stream->_base)) > 0) { if ( _write(_fileno(stream), stream->_base, nchar) == nchar ) { /* if this is a read/write file, clear _IOWRT so that * next operation can be a read */ if ( _IORW & stream->_flag ) stream->_flag &= ~_IOWRT; } else { stream->_flag |= _IOERR; rc = EOF; } } }
留意这样一行语句:
(nchar = (int)(stream->_ptr - stream->_base))
因为此时
(stream->_flag & (_IOREAD | _IOWRT)) == _IOWRT
和
bigbuf(stream)
都已经成立,这里会计算nchar的值。
看看此时缓冲区的情况:
这里nchar=21,后面调用:
_write(_fileno(stream), stream->_base, nchar)
就会将字符串
abcdefghijhello world
写入到test1.txt中。
问题讨论到这里,似乎还有一个重要的问题没有解释:
为什么“abcdefghijhello world”是在文件结尾处写,而不是紧接着文件第11处偏移开始写?是谁在修改文件的实际偏移?
ajaxhe
编辑于 2012-12-19
评论 (1) • 链接 •
2012-12-09
0
正解.... – Bechengxvyuan 2012-12-19
zhujinliang
1 票
1190
那个帖子说的挺明白了,写出后,或关闭文件前,应调用fflush,将缓存更新到文件中。
打开文件后,会在内存中产生一部分文件的缓存,通过fwrite等写出,是先写入缓存,待缓存不够用了、或者用户调用fflush时,系统才将缓存中的数据同步到文件中。
评论 (2) • 链接 •
2012-12-08
0
代码中用的是fseek,没有用fflush啊 – freeboy1015 2012-12-08
0
对于test2.txt的内容变成hello worldヘヘヘヘヘヘヘヘヘヘvwxyz还是不太理解?请详细解释一下,谢谢! – freeboy1015 2012-12-10
__mt
0 票
3279
@zhujinliang同学说的比较对,应该先调用fflush。如果不是这种情况的话,可能是对数据流的某一个操作失败了。导致数据流的设置了failbit。所以导致读写失效。觉得就这两种可能吧
评论 (3) • 链接 •
2012-12-08
0
代码中用的是fseek,没有用fflush啊 – freeboy1015 2012-12-09
0
@freeboy1015 就是说你读完之后要flush一下啊,你查下flush的意思就知道了。。 – __mt 2012-12-09
0
对于test2.txt的内容变成hello worldヘヘヘヘヘヘヘヘヘヘvwxyz还是不太理解?请详细解释一下,谢谢! – freeboy1015 2012-12-10
cyrussu
0 票
1
在你read test2的写入流的时候
缓冲区没有关闭
所以写入流接上了读取流
把后面10个字符给覆盖了
所以你用fread之前也要fflush
评论 (0) • 链接 •
2012-12-17
lixunhuan
0 票
56
我只能表示VC太弱了,标准IO库的实现还是这么老土,在gcc下没调用fseek结果是完全正确的
调用程序后test1.txt是abcdefghijhello worldvwxyz。
test2.txt是hello worldlmnopqrstuvwxyz
平台
gcc 4.7.2 + ubuntu 12.10(64bit)
可怜了大家,都去看标准IO库的实现源代码了~~~
lixunhuan
编辑于 2012-12-18
评论 (0) • 链接 •
2012-12-18
cugxxs
0 票
1
没有区别啊,我把代码运行了一下,对于前一部分的代码,不管加不加fseek函数,最后test1.txt的内容都变成abcdefghijhello worldvwxyz。对于后一部分代码,不过加不加fseek函数,test2.txt的内容都变成hello worldlmnopqrstuvwxyz。
评论 (0) • 链接 •
2012-12-18
黄滨
0 票
1
运行了一下楼主的代码,只是在fread后打印string 结果如下(linux下gcc编译gcc 版本 4.1.1 20070105 (Red Hat 4.1.1-52) ):
[huangbin@localhost shujia]$ ./a.out
string= abcdefghij
[huangbin@localhost shujia]$ cat test1.txt
abcdefghijhello worldvwxyz
能写入的。
但是在VC下确实和楼主说的一样。按理说应该是fread后不用再去定位文件流位置的,直接就能在文件流读取的位置处写入内容。可能是标准IO库版本比较老,需要再定位文件流位置才能写入。
有兴趣可以看看相应的IO库源码。
评论 (0) • 链接 •
2012-12-18
百度
0 票
1
gcc 版本 4.7.2 (Ubuntu/Linaro 4.7.2-2ubuntu1)
cat test1.txt
abcdefghijhello worldvwxyz
cat test2.txt
hello worldlmnopqrstuvwxyz
相关文章推荐
- fopen()函数以"a+"方式打开一个不存在的文件后读写出现问题
- 一个逗号引发的"血案"
- 在一个类的头文件(如B.h)中声明了A类,问在此文件中能否用"class A;"来代替#include "A.h"?
- "未能加载文件或程序集“XXX”或它的某一个依赖项。系统找不到指定的文件"的解决方案
- "未能载入文件或程序集“XXX”或它的某一个依赖项。系统找不到指定的文件"的解决方式
- 一个关于"int型二维数组"及"指针数组"作函参的地址传递和带回返回值的问题,指针的拓展练习〈二〉
- 解决"未能加载文件或程序集,或它的某一个依赖项,试图加载格式不正确的程序"问题一法
- fread和fwrite同时对一个文件读写
- endnote,出现"试图越过其尾端对一个未命名的文件进行读写" 错误
- " LINK :fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏"问题的最终解决办法
- 哥发明的 一个ssh整合时解决dao层代码冗余问题的"一点儿不漏"型抽取法!!!!
- 关于标准C文件流读写问题:fopen,fread,fwrite,fclose的一些注意事项
- 一个小问题引发的"Listview里有多个Edittext,点击一个全部都高亮"
- "未能加载文件或程序集“XXX”或它的某一个依赖项。系统找不到指定的文件"的解决方案
- iOS添加非(c,c++)文件引发的"NSObjCRuntime.h"错误
- 如何解决用"adobe pdf"打印Djvu文件出现横线或横条的问题
- 如何处理Oledb中EXCEL驱动读取EXCEL文件中字段长度大于255字符时出现的"数据截断"问题.
- Debug 模式 和 Release 模式下,一个线程在"编译"上引发的问题
- VS2005发布网站问题及"aspnet_merge.exe”已退出,代码为 1的错误以及所有代码文件生成一个dll
- "无法找到运行搜索助理需要的一个文件,您可能需要运行安装"的解决办法