首先先谈一般的,普通的 asc 文件
feof(FILE*)遇到文件尾时返回非0。但是feof测试文件尾,需要慎用,经常不小心会出现最后重复读取的错误。因为feof返回值是
根据statement来决定的。当fgetc getc fgets
fread返回失败的时候,才会修改statemnet,然后feof时候就会返回一个 非0值
说明已经到了文件尾了,该杀的时候了。我测试了windows和linux。其中windows每次都返回16,
linux返回1,遇到文件尾的时候。总之返回非0就是遇到文件尾了,该杀了。。。
所以检测文件尾的时候最好要少用feof,暂时我也没发现用他的好方法。
判断尾巴的方法:
1. int ch = fgetc(fp);
if(ch == EOF)break;
2. fgets返回NULL
3. fread返回0
还有适当的配合文件指针来使用
文件指针从0开始到size-1(其中size尾文件大小),其中后面还有一个虚拟的指针size位置(文件尾)
打开文件时候,指针指向0。
ps:文件指针到底指向哪呢?实际上就是指向将要读取的一个字节的地址,以前读过的就不算了。所以刚开始打开文件的时候,文件指针的偏移量就
是,指向文件的第一个字节,因为它还没有被读取。fseek(fp, 0,
SEEK_END)就是跳过整个文件,指向文件尾巴。那个实际不存在的地方。如果此时getc的话就会返回-1出错了。但是此时调用feof是不会返回非
0(遇到文件尾的),因为feof只是返回系统的一个statment的值,它是要getc gets
fread等等系统调用修改的。所以再三强调feof不是一个好方法。
fseek(fp, 0,
SEEK_END)后文件指针指向size,如果此时feof(fp)的话,是不会返回非0的,原因就是根本没有系统调用改变了那个statment的
值。所以还是返回0,这样如果不做判断直接getc的话,就会获得一个-1到自己的程序中就会出错了。当然也因为这个-1(虽然你么有判断,但是系统害是
该了你的statment)所以下一次调用feof的时候就会返回非0,然后才停止读取数据。但是已经错误了,所以大家要小心了啊
二进制文件的话,fread fwrite配合文件指针用吧。
首先解释一下只能用fread和fwrite的原因,也许有人不知道的吧- -。一句话,二进制文件里面可能有大量的asc码值等于0 或者
某个字节序列 为 0xffffffff 也就是十进制-1. 比如当你int
ch=getc(fp)的时候有可能获得-1但是却么有到达文件尾。或者fgets得到0,包括0以及后面的所以数据都会被你的应用程序所抛弃。这就是为
什么有人拷贝二进制文件然后文件远比以前的要小的原因。反正一句话,二进制文件用这些函数来搞就是找死。。。
fopen文件打开时候有个binary的模式,大家不能被误解了,只不过windows系统有点字符转换有点影响。根本不是说是把文件真的用
二进制格式打开或者用asc格式打开了。因为说到底,文件的内容都是一样当的,在怎样打开它的内容不会变的,每个字节每个位的内容都是不会变的。从理论上
来解释说就是,文件是一个物理物质,稳定性。平常遇到的按照什么asc模式和二进制模式,实际上都是实际的需要才有用的。比如可执行文件啊,图片
啊,mp3啊,读写的话只要用fread
fwrite就行了啊。但是有人会说,读写二进制的文件为什么还要fopen的时候指定b模式呢。实际上,只是用于windos的,需要澄清,linux
下面是一样的。windows的话如果不选b模式,系统内核会自动吧\n 转换成
\r\n两个字符,反之b模式则没有。就是说windows下面b模式文件就不同了。这时候,对于普通的asc文件,b模式没有影响,系统内核都会自动转
换,对用户来说是不用担心的。 但是对于二进制文件就不同了,所以需要指定。
二进制文件读写的例子(兼容asc格式)
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define LINEBUF 2000
int main(int argc, char** argv) {
if(argc != 3) {
printf("use format:\ta.out in out\n");
return -1;
}
char *str_in = argv[1];
char *str_out = argv[2];
if(strcmp(str_in, str_out) == 0) {
printf("file in and out can't the same\n");
return -1;
}
FILE* in = fopen(argv[1], "rb");
FILE* out = fopen(argv[2], "wb");
if(in == NULL || out == NULL) {
printf("file open error\n");
return -1;
}
fseek(in, 0, SEEK_END);
int size = ftell(in);
fseek(in, 0, SEEK_SET);
printf("size is: %d\n", size);
int remain = size;
char buf[LINEBUF];
int result;
int w_bytes = 0;
while(true) {
if(remain <= 0)break;
int nbytes = remain int pos1 = ftell(in);
result = fread(buf, nbytes, 1, in);
int pos2 = ftell(in);
// printf("------pos2-pos1:%d \tnbytes: %d, result:%d\n", pos2-pos1, nbytes,result);
result = fwrite(buf, nbytes, 1, out);
w_bytes += nbytes;
remain -= nbytes;
}
printf("success write %d bytes\n", w_bytes);
fclose(in);
fclose(out);
getchar();
}
可以用于asc文件,b模式也无所谓指定。
用于二进制文件的时候,windows一定要指定b模式。否则就会因为系统内核的自动转化引发错误,因为二进制文件你不需要把你的图片
mp3 可知性文件里面的 \r\n 装换为一个
\n.要是没有选择b模式,首先读文件的时候,如果\r\n很多的话,所能读出来的东西就会很少,比原文件小了很多。写文件刚好相反,一个 \n
会变成\r\n,所以二进制传输的时候一定要指定b模式就不会错了
阅读(818) | 评论(0) | 转发(0) |