在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 16char 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 16char 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 類型。這兩種意外結束不是一種情況,一個是邏輯不嚴謹導致的,一個就目前看來是微軟系統庫的問題。