前些天心血来潮,准备做一个异或加密工具,用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 * p = fopen(FILE_NAME, " rb " ); 10 FILE * f = 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 }
参考文章: