关于C语言判断文件尾问题的探讨

前些天心血来潮,准备做一个异或加密工具,用Java写了一个,感觉不过瘾.Java这东西还要依靠虚拟机运行.所以,准备再用C语言实现一遍.
还是参考HP UX的CP命令代码,如下:
HP UX CP
 1 #include <stdio.h>   
 2 #include <stdlib.h>   
 3 
 4 int main(int argc,char *argv[])
 5 {   
 6     int ch;   
 7     FILE *fpinPtr,*fpoutPtr;   
 8     
 9     if (argc!=3)
10     {   
11         printf("File copy program.\n\n");   
12         printf("Usage: command source_file target_file\n");   
13         printf("Usage example: \"copy src.txt obj.txt\"\n");   
14         exit(EXIT_FAILURE);   
15     }   
16     
17     if ((fpinPtr=fopen(argv[1],"rb"))==NULL)
18     {   
19         printf("Input file \"%s\" could not be opened\n",argv[1]);   
20         exit(EXIT_FAILURE);   
21     }   
22     
23     if ((fpoutPtr=fopen(argv[2],"wb"))==NULL)
24     {   
25         printf("Outout file \"%s\" could not be opened\n",argv[2]);   
26         exit(EXIT_FAILURE);   
27     }   
28     
29     while(!feof(fpinPtr))
30     {   
31         ch=fgetc(fpinPtr);   
32         if(ch>-1)   
33             fputc(ch,fpoutPtr);   
34     }   
35     
36     fclose(fpinPtr);   
37     fclose(fpoutPtr);   
38     
39     return 0;   
40 
41 

结果这次仔细看了一下,发现了一些小问题.

 这条CP命令是读取源文件单个字符然后写入目标文件的方法实现的.但是代码的第6行的变量类型是int,我想这不是浪费内存空间么,而且第32行有一句if(ch>-1) ,半天没搞懂当时写这段代码的程序员是怎么想的.于是,我把第6行改成 char ch; ,删除了第32行的代码.

编译链接一切正常,运行,校验源文件和目标文件的MD5值,不一样.晕了.

仔细对比源文件和目标文件,发现目标文件尾多了一个EOF字符,原来是这个道理.于是把原32行的代码改成if(ch > EOF),复制了一个文本文件,一切正常.然后又试着复制一个BMP文件,问题又来了.

复制位图文件后发现,目标文件比源文件要小很多,用记事本打开源文件,发现源文件里面就有许多EOF字符,这些字符都复制丢了.

而不加原始代码里32行的那句约束语句,则程序会多读取一个字符,如果是读取一个文件段,则会造成读取垃圾数据.

而原始代码正是解决了判断文件尾的问题.

网上有的帖子也说:

可以用feof()函数判断文件尾

也可以用fgetc读取内容

ch=fgetc(fp);

ch==EOF也是文件结尾 

看来也不完全对,如果用fgetc来判断,则有可能在读取位图这类二进制文件时会造成错误的文件尾提示,用feof则会多读取一次.

在此之前,我的师兄王晔用判断文件大小的方法复制文件,对小文件的操作或许可以采用.

附师兄的源码:

Wang Ye copy
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #define FILE_NAME "a.jpg"
 4 int main(void)
 5 {
 6     char tmp;
 7     long len;
 8     unsigned char *read_ptr;
 9     FILE *= fopen(FILE_NAME, "rb");
10     FILE *= fopen("a1.jpg""wb");
11 
12     if(NULL == p)
13         return 1;
14 
15     fseek(p, 0L, SEEK_END);
16     len = ftell(p);        /*求文件长度*/
17     fseek(p, 0L, SEEK_SET);
18 
19     read_ptr = (unsigned char *)calloc(len, sizeof(unsigned char));
20 
21     if(NULL == read_ptr)
22     {
23         puts("Error\n");
24         return 1;
25     }
26     fread(read_ptr, len, 1, p);
27 
28     printf("%x %x"*read_ptr, *(read_ptr + 1));
29 
30     fwrite(read_ptr, len, 1, f);
31 
32     free(read_ptr);
33     fclose(p);
34     fclose(f);
35     return 0;
36 }

参考文章:http://news.cnblogs.com/n/121416/

原文地址:https://www.cnblogs.com/Leon5/p/1614044.html