Chinaunix首页 | 论坛 | 博客
  • 博客访问: 443729
  • 博文数量: 138
  • 博客积分: 4114
  • 博客等级: 上校
  • 技术积分: 1341
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-14 20:41
文章分类

全部博文(138)

文章存档

2014年(1)

2013年(2)

2012年(78)

2011年(13)

2010年(34)

2009年(10)

我的朋友

分类: C/C++

2009-11-29 11:06:50

首先先谈一般的,普通的 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模式就不会错了
 
ps:fread() fwrite()返回值,成功返回读取到或者写入成功的记录个数。如果失败将会比要求的记录个数少点


原文连接

http://blog.chinaunix.net/u2/62281/showart_1077661.html
阅读(807) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~