目錄
- 主要使用函式原型:
- 實現過程中幾個易錯細節小結
- 函式:每次讀寫一個字元
- 函式:每次讀寫一行字元
- 函式:每次讀寫一個塊字元
主要使用函式原型:
1.每次讀寫一個字元:
int fgetc(FILE *stream);
int fputc(int c, FILE *stream);
2.每次讀寫一行字元:
char *fgets(char *s , int size , FILE *stream);
char *fputs(const char *s ,FILE *stream);
3.每次讀寫一個塊字元:
size_t fread(void *ptr,size_t size,xize_t nmemb,FILE\*stream);
size_t fwrite(const void *ptr,size_t size,xize_t nmemb,FILE\*stream);
4.另外,每個函式也使用了一些輔助函式,主要列舉如下:
int feof(FILE *stream);
int ferror(FILE *stream);
long ftell(FILE *stream); //獲取當前的位置偏移量
實現過程中幾個易錯細節小結
-
幾個讀取函式的檔案指標偏移
int fgetc(FILE *stream),char *fgets(char *s , int size , FILE *stream),與size_t fread(void *ptr,size_t size,xize_t nmemb,FILE*stream)的每次讀取,都是從檔案的開始位置,向後讀取;在下一次迴圈到來之前,檔案內的當前位置,已經是已讀取的字元之後。
筆者一開始圖方便,將讀取函式fgetc()的返回值直接作為寫入函式fputc()的引數,寫了下面這行程式碼,就導致了一個比較低階的錯誤:
while (!feof(fp_src)) // 每次讀寫一個字元的第19~33行簡易實現 { fputc(fgetc(fp_src), fp_dst); }
導致複製出來的檔案末尾都有一個亂碼:
fclose(fp_dst); // 關閉並釋放檔案指標堆空間 fclose(fp_src); return 0; }�
因此,此處的迴圈結束條件必須加上fgetc(fp_src)==EOF。
-
行與塊的區別
行與塊的區別,影響到設計的函式結構。
行:即資料至多包含一個換行符“\n”,遇到換行符就進行下一次迴圈;因此,可以以fgets()是否為NULL為迴圈結束條件,即檔案stream到達檔案末尾即可。
塊:即一個固定的快取空間,當資料塊中出現換行符或字串結束標記符等都不會受影響。因此將一個檔案分為若干塊,將不滿一塊時的判斷條件作為迴圈結束條件,即:
*size_t fread(void ptr,size_t size,xize_t nmemb,FILE*stream)< NMEMB並將剩下的字元繼續輸入。
-
函式返回值
如同第二點,返回值非常重要,可以以此為切入口設計程式架構。
單字元 單行 塊 讀取函式 int fgetc(FILE *stream); char *fgets(char *s , int size , FILE *stream); size_t fread(void *ptr,size_t size,xize_t nmemb,FILE*stream); 成功/失敗 讀取到的字元/EOF(-1) 指標s/NULL nmemb/<nmemb 寫入函式 int fputc(int c, FILE *stream); char *fputs(const char *s ,FILE *stream); size_t fwrite(const void *ptr,size_t size,xize_t nmemb,FILE*stream); 成功/失敗 讀取到的字元/EOF(-1) true/NULL nmemb/<nmemb
函式:每次讀寫一個字元
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
if (3 != argc) // 判斷使用者輸入的引數是否有效。
{
perror("argument is invalid.\n");
exit(1);
}
// 分別開啟待複製和目標複製檔案
FILE *fp_src = fopen(argv[1], "rb"); // 以二進位制形式讀取第一個檔案
FILE *fp_dst = fopen(argv[2], "wb"); // 以二進位制形式追加寫入第二個檔案
if (!fp_dst || !fp_src) // 如果開啟錯誤,則直接列印錯誤資訊並退出.
{
perror("fopen()");
exit(1);
}
int data = fgetc(fp_src); // 設定變數,存放fgetc得到的字元
while (1)
{
if (feof(fp_src) && data == EOF) // 如果當前游標已經到檔案尾,則退出迴圈
{
printf("Copy completed.\n");
break;
}
else if (ferror(fp_src)) // 如果出現未知錯誤,則退出
{
perror("fgetc()");
exit(1);
}
fputc(data, fp_dst);
data = fgetc(fp_src); // 繼續存放fgetc得到的字元
}
fclose(fp_dst); // 關閉並釋放開啟檔案申請的堆空間
fclose(fp_src);
return 0;
}
函式:每次讀寫一行字元
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#define BUFSIZE 100 // 設定每一個緩衝區,即每一行能複製的最大位元組數
int main(int argc, const char *argv[])
{
if (3 != argc) // 判斷使用者輸入的引數是否有效。
{
perror("argument is invalid.\n");
exit(1);
}
// 分別開啟待複製和目標複製檔案
FILE *fp_src = fopen(argv[1], "rb"); // 以二進位制形式讀取第一個檔案
FILE *fp_dst = fopen(argv[2], "wb"); // 以二進位制形式追加寫入第二個檔案
if (!fp_dst || !fp_src) // 如果開啟錯誤,則直接列印錯誤資訊並退出.
{
perror("fopen()");
exit(1);
}
char buf[BUFSIZE] = {0}; // 定義緩衝區變數,利用陣列實現
while (1)
{
bzero(buf, BUFSIZE); // 每次操作前,進行清空緩衝區操作,以免內容洩露
if (!fgets(buf, BUFSIZE, fp_src)) // 獲取原始檔資料,並判斷是否為NULL,如果為NULL有兩種情況判斷
{
if (feof(fp_src)) // 如果當前游標已經到檔案尾,則表示複製完成並退出迴圈
{
printf("Copy completed.\n");
break;
}
else if (ferror(fp_src)) // 如果出現未知錯誤,則退出
{
perror("fgetc()");
exit(1);
}
}
fputs(buf, fp_dst); // 複製完成後,進行貼上操作
}
fclose(fp_dst); // 關閉並釋放開啟檔案申請的堆空間
fclose(fp_src);
return 0;
}
函式:每次讀寫一個塊字元
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#define SIZE 100 // 設定每一塊能容納的最大位元組數
#define NMEMB 5 // 設定塊數
int main(int argc, const char *argv[])
{
if (3 != argc) // 判斷使用者輸入的引數是否有效。
{
perror("argument is invalid.\n");
exit(1);
}
// 分別開啟待複製和目標複製檔案
FILE *fp_src = fopen(argv[1], "rb"); // 以二進位制形式讀取第一個檔案
FILE *fp_dst = fopen(argv[2], "wb"); // 以二進位制形式追加寫入第二個檔案
if (!fp_dst || !fp_src) // 如果開啟錯誤,則直接列印錯誤資訊並退出.
{
perror("fopen()");
exit(1);
}
char buf[SIZE * NMEMB] = {0}; // 定義緩衝區變數,利用陣列實現
long pre, cur;
while (1)
{
bzero(buf, SIZE * NMEMB); // 每次操作前,進行清空緩衝區操作,以免內容洩露
pre = ftell(fp_src); // 記錄當前的偏移量;
if (fread(buf, SIZE, NMEMB, fp_src) < NMEMB) // 獲取原始檔資料,並判斷異常情況,並進行異常情況判斷
{
if (feof(fp_src)) // 如果當前游標已經到檔案尾,則需要把剩餘的內容進行復制,這裡利用pre,cur實現
{
fread(buf, cur - pre, 1, fp_src);
fwrite(buf, cur - pre, 1, fp_dst);
printf("Copy completed.\n");
break;
}
else if (ferror(fp_src)) // 如果出現未知錯誤,則退出
{
perror("fgetc()");
exit(1);
}
}
fwrite(buf, SIZE, NMEMB, fp_dst); // 複製完成後,進行貼上操作
}
fclose(fp_dst); // 關閉並釋放開啟檔案申請的堆空間
fclose(fp_src);
return 0;
}