zoukankan      html  css  js  c++  java
  • 关于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/

  • 相关阅读:
    深度优先和广度优先
    水管工游戏(深度优先)
    炸弹人
    广度优先(迷宫找人)
    System.Data.Entity.Core.MetadataException: 无法加载指定的无数据资源
    Element Cascader 级联选择器 单选操作优化
    Windows服务 ProjectInstaller 获取 路径
    Quartz.NET ScheduledFireTimeUtc 当超过1分钟时出现的问题。
    记录:一个SQL SERVER奇怪的问题。
    log4.net 配置
  • 原文地址:https://www.cnblogs.com/Leon5/p/1614044.html
Copyright © 2011-2022 走看看