读取文件遇到0X1A意外终止的解决方法

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/Apollon_krj/article/details/80020936

在Windows的集成开发环境中(Qt、VC、VS中均存在该问题)编写有关文件读取的C/C++程序,出现读取到0X1A的时候意外终止的情况,经调试检查发现0X1A经过读取之后被处理成0XFF(即EOF(-1)),但是Linux中(Redhat6.4以及Ubuntu14.04中测试)不存在这种解析错误的问题。关于出现这种问题的原因可参考:https://blog.csdn.net/zhoubl668/article/details/7054282。那么解决办法有两种:

1、用二进制的方式读取:

FILE * fp = fopen("file", "rb");//以二进制流读取

以“.dcm”的文件解析为例(将new.dcm的信息解析成十六进制输出到new.hex中去):

/*
 * 2018年4月20日16:37:10
 * 二进制流的方式读取
 * 
*/
#include "stdafx.h"

#define STRING_BUFFER 16

char strbuf[STRING_BUFFER] = {0};

int main(void)
{
    unsigned int i = 0;

    FILE * fpr = fopen("F:\\new.dcm", "rb");//以二进制流读取
    FILE * fpw = fopen("F:\\new.hex", "w");//输出文件
    if(fpr == NULL || fpw == NULL){
        printf("open file failure at line:%d\n", __LINE__);
        exit(EXIT_FAILURE);
    }

    fprintf(fpw, "%08X: ", num);
    while(!feof(fpr)){//直接用feof()可以判断
        int ch = fgetc(fpr);//一次读取一个字符
        strbuf[num % STRING_BUFFER] = (unsigned char)ch;//并记录到16个字符一行的缓冲区中
        fprintf(fpw, "%02X ", (unsigned char)ch);//将该字符(1Byte,如'A')写到输出文件中(变成2Byte,'A'对应0X41)
        num++;//读取的字符数加1
        if(num % 16 == 0){//输出文件格式化,读取16个字节换一行
            fprintf(fpw, "; ");
            for(i = 0; i<STRING_BUFFER; i++){//解析缓冲区中的字符
                if(strbuf[i] > 31 && strbuf[i] < 127)
                    fprintf(fpw, "%c", strbuf[i]);
                else
                    fprintf(fpw, ".");
            }
            fprintf(fpw, "\n%08X: ", num);//换行
            memset(strbuf, 0, STRING_BUFFER);//清空缓冲区
        }
    }

    fclose(fpr);
    fclose(fpw);

    printf("Complete!\n");
    return 0;
}

2、判断文件读取遇到EOF(0XFF)的原因是0X1A引起的还是到文件末尾引起的:

FILE * fp = fopen("file", "r");//以文本文件读取

fseek(fp, 0, SEEK_END);
const size_t len_file = ftell(fp);
fseek(fp, 0, SEEK_SET);

//获取文件长度后根据读取的字符个数来判断是否结束

同样是对上面所述文件进行读取:

#include "stdafx.h"

#define STRING_BUFFER 16

char strbuf[STRING_BUFFER] = {0};

int main(void)
{
    unsigned int num = 0, i = 0;

    FILE * fpr = fopen("F:\\new.dcm", "r");//以非二进制流读取
    FILE * fpw = fopen("F:\\new.hex", "w");
    if(fpr == NULL || fpw == NULL){
        printf("open file failure at line:%d\n", __LINE__);
        exit(EXIT_FAILURE);
    }

    //获取文件长度
    fseek(fpr, 0, SEEK_END);
    const unsigned int len_file = ftell(fpr);
    fseek(fpr, 0, SEEK_SET);

    printf("%d\n", len_file);

    fprintf(fpw, "%08X: ", num);
    //不可以用feof()判断,因为以文本形式读取时0X1A已经被解析成0XFF
    while(num < len_file){//根据读取的字符数与文件长度来判断是否到达文件末尾
        int ch = fgetc(fpr);
        if((unsigned char)ch == 0XFF){//如果读取到0XFF,判断是否是0X1A所引起的
            strbuf[num % STRING_BUFFER] = 0X1A;
            fprintf(fpw, "1A ");
            fseek(fpr, num+1, SEEK_SET);
            //不能用fseek(fpr, 1, SEEK_CUR);或fseek(fpr, ftell(fpr)+1, SEEK_SET);
            //因为如果是遇到结束符EOF或0X1A时,ftell()的值即SEEK_CUR会变成4096的倍数
        }
        else{
            strbuf[num % STRING_BUFFER] = (unsigned char)ch;
            fprintf(fpw, "%02X ", (unsigned char)ch);
        }
        num++;
        if(num % 16 == 0){
            fprintf(fpw, "; ");
            for(i = 0; i<STRING_BUFFER; i++){
                if(strbuf[i] > 31 && strbuf[i] < 127)
                    fprintf(fpw, "%c", strbuf[i]);
                else
                    fprintf(fpw, ".");
            }
            fprintf(fpw, "\n%08X: ", num);
            memset(strbuf, 0, STRING_BUFFER);
        }
    }

    fclose(fpr);
    fclose(fpw);

    printf("Complete!\n");
    return 0;
}

关于fgetc()返回值为何为int以及对于EOF引起的另外一种读取文件意外结束的情况,可以参考fgetc函数的返回值为什么是 int 类型。这两种意外结束不是一种情况,一个是逻辑不严谨导致的,一个就目前看来是微软系统库的问题。

猜你喜欢

转载自blog.csdn.net/Apollon_krj/article/details/80020936