1 / 36

檔案二 - 二進位檔

檔案二 - 二進位檔. 二進位檔與本文檔的結構不同。在 Windows 作業系統的本文檔每一記錄之後均有返回字元( CR )及換列字元( LF ),「 CR 」以十六進位表示為「 0d 」, LF 以十六進位表示為「 0a 」。 C 程式輸入本文檔時將「 CR/LF 」轉換為只有「 LF 」字元,輸出本文檔時又將「 LF 」轉換為「 CR/LF 」兩個字元。但二進位檔之輸入、輸出都沒有這種轉換的動作。.

leyna
Download Presentation

檔案二 - 二進位檔

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 檔案二-二進位檔 • 二進位檔與本文檔的結構不同。在 Windows 作業系統的本文檔每一記錄之後均有返回字元(CR)及換列字元(LF),「CR」以十六進位表示為「0d」,LF 以十六進位表示為「0a」。 • C 程式輸入本文檔時將「CR/LF」轉換為只有「LF」字元,輸出本文檔時又將「LF」轉換為「CR/LF」兩個字元。但二進位檔之輸入、輸出都沒有這種轉換的動作。 正修科技大學計算機中心

  2. 開檔使用 fopen() 時,模式 mode 後附加「t」表示本文檔,附加「b」表示二進位檔。 二進位檔 mode 情形如下: rb 開啟二進位檔為唯讀。 wb 開啟二進位檔為唯寫。 ab 開啟二進位檔為附加。 rb+ 開啟二進位檔為更新,讀及寫。 wb+ 開啟二進位檔為唯寫更新。 ab+ 開啟二進位檔為附加更新。 二進位檔存取可對某一檔之資料做讀取及寫入之動作。 正修科技大學計算機中心

  3. 讀取可使用 fread() 函式,寫入可使用 fwrite() 函式,其語法說明如下: #include <stdio.h> size_t fread(void *ptr, size_t size, size_t n, FILE *f) 由指定檔 f 讀取 n 項資料,每一項為 size 個位元組,至 ptr 指標所指之記憶體位址。讀取成功時傳回 n 值,讀入失敗(或讀至檔尾)時傳回 0 值。size_t 為不帶符號的整數 unsigned int 型態。 正修科技大學計算機中心

  4. #include <stdio.h> size_t fwrite(const void *ptr, size_t size, size_t n, FILE *f); 將 ptr 指標所指處之 n 項資料,每項 size 個位元組,共 n*size 個位元組寫入 f 所指的檔案。寫入成功時傳回寫入項數,寫入失敗時傳回短缺之項數。 正修科技大學計算機中心

  5. #include <stdio.h> fseek(FILE *f, long offset, int whence); 對於指定檔案 f 設定檔案指標於偏離檔案指標 whence 處 offset 個位元組之位置。定位成功時傳回 0 值,定位失敗時傳回非 0 值。whence 之意義如下表 11.1 所示。 表 11.1 whence值及其意義表 whence值 whence識別字 常數檔案指標位置 -------------- -------------------- ------------------------ 0 SEEK_SET 檔案開頭 1 SEEK_CUR 目前檔案位置 2 SEEK_END 檔尾 正修科技大學計算機中心

  6. 檔案指標位置若置於檔案開頭,則開頭之位元組編號為 0,下一個位元組編號為 1,再下一個位元組編號為 2,等等。檔案指標位置若為目前檔案位置,則目前檔案位置位元組編號為「檔案指標位置+0」,下一個位元組編號為「檔案指標位置+1」,等等。 正修科技大學計算機中心

  7. 【例題binary】 將字串 "binary out" 輸出至二進位檔 "binary.dat",然後又從該檔讀 入記憶體後再行輸出。 【分析】 開啟 binary.dat 為輸出二進位檔,宣告如下: FILE *f=fopen("binary.dat", "wb"); 使用 fgets() 函數從鍵盤輸入 "binary out" 字串至 s 變數。 然後使用 fwrite() 函式將變數 s,共 strlen(s)+1 個位元組的一筆資 料輸出至 f 所指的二進位檔案 binary.dat。 fwrite(s, strlen(s)+1, 1, f); 正修科技大學計算機中心

  8. 整個輸出完畢後再將二進位輸出檔案 binary.dat 關閉,一定要關閉整個輸出的動作才算完成。關閉的動作先將在記憶體緩衝器中的資料輸出至二進位輸出檔案 binary.dat,然後在檔尾處加上一個檔案結束符號,在 Windows 作業系統檔案結束符號為十六進位「0x1a」。 fclose(f); 第二階段將剛剛建立的資料檔 binary.dat 重新開啟為二進位輸入檔案,檔案指標仍為 f,然後從 binary.dat 每次讀入一個位元組至不帶符號的字元變數 uc 位址處加於處理。 f = fopen("binary.dat", "rb"); fread(&uc, 1, 1, f); 正修科技大學計算機中心

  9. 【執行結果】 請輸入一個字串: binary out<Enter> 傾印binary.dat檔 62 69 6e 61 72 79 20 6f 75 74 0a 【二進位檔案binary.dat】 binary out 正修科技大學計算機中心

  10. 【例題dumpfile】 以十六進位印出已知檔名及指定每列位元組數之資料。測試資料檔名 為 fixout.txt,內定每列位元組數為 16,總共 64 位元組。 【分析】 已知檔可為任意型態之檔,如循序檔、二進位檔、或隨機檔,每次讀入一 個位元組,故均以二進位檔處理。 【說明】 本程式所要操作的檔案要執行時才會決定,如此才有彈性,因此檔名設計 執行時才從命令列輸入,每列所要列印的位元組數 bytesperline 以及共 要從檔案讀入多少個位元組 totalbytes 也是執行時才給的,這三個引數 都從命令列輸入,因此執行的格式如下: dumpfile 檔名 每列位元組數 總共讀入位元組數 <Enter> 正修科技大學計算機中心

  11. 主函式 main() 的簽名提供這些引數資料,簽名如下: int main(int argc, char *argv[]) 參數 argc 表示引數個數,若三個引數全部都提供的話引數個數為 4。 第零個引數存於 argv[0],為執行的程式名稱,本例為 dumpfile。 第一個引數存於 argv[1],為「檔名」,本例為 outfile.txt。 第二個引數存於 argv[2],為「每列位元組數」,本例為 16。 第三個引數存於 argv[3],為「總共讀入位元組數」,本例為 64。 FILE *f = fopen(argv[1],"rb"); 開啟 argv[1] 檔名為輸入二進位檔,檔案指標為 f。 ch=fgetc(f); 每次從 f 檔案讀取一個位元組,存入字元變數 ch。 if (feof(f) || count>=totalbytes) break; 若已讀至檔尾或已超過指定的總共位元組數,這時就跳出 while 無窮 迴圈,關閉 f 檔案後就結束了。 正修科技大學計算機中心

  12. printf("%02x ", ch); count++; if (count%bytesperline==0) printf("\n"); 將讀取的字元 ch 以十六進位二位數輸出,若沒有高位數則補零。位元組計數 count 增一。若讀取的位元組數是 bytesperline 的倍數,則跳至下一列繼續執行。 正修科技大學計算機中心

  13. /****************** dumpfile.c *****************/ #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int ch, count, bytesperline=16, totalbytes=64; FILE *f = fopen(argv[1],"rb"); if (argc>=3) bytesperline = atoi(argv[2]); if (argc>=4) totalbytes = atoi(argv[3]); count=0; while (1) { ch=fgetc(f); if (feof(f) || count>=totalbytes) break; printf("%02x ", ch); count++; if (count%bytesperline==0) printf("\n"); } fclose(f); return 0; } 正修科技大學計算機中心

  14. 【檔案fixout.txt】 39309101092100 39309103075008 39309105083095 39309107083087 39309109072086 【執行結果】 ch11> dumpfile fixout.txt 16 64 <Enter> 33 39 33 30 39 31 30 31 30 39 32 31 30 30 0d 0a 33 39 33 30 39 31 30 33 30 37 35 30 30 38 0d 0a 33 39 33 30 39 31 30 35 30 38 33 30 39 35 0d 0a 33 39 33 30 39 31 30 37 30 38 33 30 38 37 0d 0a 正修科技大學計算機中心

  15. 11.11 隨機檔 • 隨機存取檔其資料儲存之方式與循序存取大不相同。循序存取檔之資料每一筆長度不一且均以 CR 歸位鍵及 LF 換列結束,而隨機存取檔之資料每一筆均為定長,並不以 CR 及 LF 結束。循序存取檔之記錄,資料為變長,而隨機存取檔之記錄,其資料為定長。隨機存取檔適用於資料庫管理系統之設計,以考生之成績籍為例,每一個考生包含下列的資料: • 准考證號碼 為八位整數,欄名 id。 • 姓名 以英文字表示為十二位,以中文表示為六位, • 宣告為字元陣列,欄名 name。 • 性別 為一個字元,'1' 表男,'2' 表女,欄名 sex。 • 總分 為三位整數,欄名 score。 • 以結構表示如下: • struct stag • { • int id; • char name[13]; • char sex[2]; • int score; • } ; 正修科技大學計算機中心

  16. 【例題sfile】 設計一個程式從本文檔 sfile.txt 建立一個 stag 格式的隨機檔,命 名為 sfile.dat。 本文檔 sfile.txt 的內容如下: 23010001陳一心 1411 23010003林二聖 2533 23010005李三多 1455 23010007龔四維 2577 23010009蔡五福 1499 23010011丁六合 2511 23010013邱七賢 1433 23010015歐楊八德 2555 23010017張簡九如 1477 23010019高十全 2599 正修科技大學計算機中心

  17. 【分析】 本文檔 sfile.txt 對程式 sfile.c 而言是本文輸入檔,您可以使 用 "rt" 模式開啟,其檔案指標為 FILE 型態的指標變數 f。 FILE *f=fopen("sfile.txt", "rt"); 而考生資料庫 sfile.dat 可使用 "wb+" 開啟為輸出二進位檔如下: FILE *sfile; sfile=fopen("sfile.dat", "wb+"); 接著呼叫 fgets() 函式從本文檔讀入一筆記錄至 line 字串中,讀 至 '\0' 或 '\n' 時才會停止讀取的動作,因此記錄中含有空白字元 仍可讀取。 #include <stdio.h> char *fgets(char *s, int n, FILE *stream); 讀取由 stream 所指檔案 n-1 個字元存於 s。 字串以 '\0' 結束。讀至 '\n' 也會停止 fgets() 之執行。 成功時傳回 s 位址,失敗或讀至檔尾時傳回 NULL 值。 正修科技大學計算機中心

  18. 在字串 line 中可使用 sscanf() 函式依指定的格式取至指定的變數位址。 #include <stdio.h> int sscanf(const char *buffer, const char *format [, address] ...); 依格式 format 由 buffer 讀取相對應之資料送至相對應之位 址 address 處。成功時傳回輸入欄數,讀至 buffer 結 束 '\0' 時傳回 EOF 值。 snode 為 stag 結構型態的變數,定義於引入 stag.h 表頭檔。 sscanf(line,"%8d%12s%1s%3d", &snode.id, &snode.name, &snode.sex, &snode.score); 第一欄將八個數字的整數(%8d)讀取至變數 snode.id 位址處。 第二欄將十二個字元以字串的方式(%12s)讀取至 snode.name 位址。 第三欄將一個字元的字串(%1s)讀取至變數 snode.sex 位址。 第四欄將三個數字的整數(%3d)讀取至變數 snode.score 位址。 fwrite(&snode, sizeof(snode), 1, sfile); 然後將整個結構 snode 以二進位方式寫至 sfile.dat 隨機檔中。 正修科技大學計算機中心

  19. 【例題recshow】 設計一個程式將考生資料庫 sfile.dat 指定編號的記錄顯示出來。 【分析】 首先將考生資料庫 sfile.dat 開啟為二進位輸入檔, FILE *sfile; sfile=fopen("sfile.dat", "r+b"); 設 n 為輸入之記錄編號,sfile.dat 每一記錄長度為 sizeof(snode),本例為 24 個位元組,n 個記錄共偏移「n*24」個位元組,您可使用函 式 fseek() 將其定位於該記錄處。程式碼如下: offset = n * sizeof(snode); fseek(sfile, offset, SEEK_SET); 長整數型態的變數 offset 表示從 SEEK_SET 處偏移的位元組數。符號常數 SEEK_SET 表示檔案開始處。 fread(&snode, sizeof(snode), 1, sfile); 既已定位,就從該定位處呼叫 fread() 函式將該筆記錄讀入 snode 結構,就可處理了。 正修科技大學計算機中心

  20. 【執行結果】 請輸入記錄編號(0-9): 4 <Enter> 准考證號碼=23010009 姓名=蔡五福 性別=1 總分=499 請輸入記錄編號(0-9): 44 <Enter> 輸入記錄編號44超出範圍 執行recshow程式發生錯誤!! 正修科技大學計算機中心

  21. 【例題seqaccess】 將考生資料庫 sfile.dat 指定編號的區段記錄顯示出來。 【分析】 將上題的 recshow() 函式稍加修正為 shownode() 只顯示指定的記錄而已。 void shownode(long n, FILE *sfile) { long offset = n * sizeof(snode); fseek(sfile, offset, SEEK_SET); fread(&snode, sizeof(snode), 1, sfile); printf("准考證號碼=%8d\n", snode.id); printf(" 姓名=%-12s\n", snode.name); printf(" 性別=%1s\n", snode.sex); printf(" 總分=%3d\n", snode.score); } 因為很多程式都會用到這個函式,因此將它存入 stag.h 表頭檔裡,要用時再將它引入您的程式。在主函式 main() 裡開啟 sfile.dat 資料庫,輸入起迄記錄編號 n1、n2,然後將此區段的記錄逐一呼叫 shownode() 顯示出來。 正修科技大學計算機中心

  22. 【說明】 程式 seqaccess.c 中: printf("\n請輸入起迄記錄編號(0 %ld): ", totalnodes-1); scanf("%ld %ld", &n1, &n2); if (n1>=totalnodes || n2>=totalnodes) printf(" 輸入起迄記錄編號超出範圍!!\n"); else for (i=n1; i<=n2; i++) shownode(i,sfile); 輸入起迄記錄編號 n1 及 n2 之後,檢查是否超出檔案 sfile.dat 的範 圍,若在範圍內則逐一呼叫 shownode() 函式將 n1 至 n2(含)區段的 記錄逐一顯示出來。 正修科技大學計算機中心

  23. 【程式seqaccess.c】 /************************ seqaccess.c *****************/ #include <stdio.h> #include "stag.h" FILE *sfile; long totalbytes, totalnodes; int main() { long i, n1, n2; sfile=fopen("sfile.dat", "r+b"); fseek(sfile, 0L, SEEK_END); totalbytes = ftell(sfile); totalnodes = totalbytes/sizeof(snode); printf("\n請輸入起迄記錄編號(0 %ld): ", totalnodes-1); scanf("%ld %ld", &n1, &n2); if (n1>=totalnodes || n2>=totalnodes) printf(" 輸入起迄記錄編號超出範圍!!\n"); else for (i=n1; i<=n2; i++) shownode(i,sfile); fclose(sfile); return 0; } 正修科技大學計算機中心

  24. 【執行結果】 請輸入起迄記錄編號(0-9): 3 5 <Enter> 准考證號碼=23010007 姓名=龔四維 性別=2 總分=577 准考證號碼=23010009 姓名=蔡五福 性別=1 總分=499 准考證號碼=23010011 姓名=丁六合 性別=2 總分=511 請輸入起迄記錄編號(0-9): 0 99 <Enter> 輸入起迄記錄編號超出範圍!! 正修科技大學計算機中心

  25. 【例題addnode】 將一新考生資料加入考生資料庫 sfile.dat 的尾端。 【分析】 首先將考生資料庫 sfile.dat 開啟為二進位附加檔。 FILE *sfile; sfile=fopen("sfile.dat", "a"); 將新考生資料建立存於 snode 結構中後,使用 fwrite() 函式將該節點 附加於考生資料庫的尾端。 fwrite(&snode, sizeof(snode), 1, sfile); 然後關閉考生資料庫 sfile.dat。 【說明】 執行 addnode.c 後將准考證號碼 23010004 資料附加於 sfile.dat 尾 端。然後執行 seqaccess 程式將該筆資料顯示。 正修科技大學計算機中心

  26. 【程式addnode.c執行結果】 (1). 准考證號碼(8位整數) : 23010004 <Enter> (2). 姓名(12個字元之字串) : 李四 <Enter> (3). 性別(1個字元之字串) : 2 <Enter> (4). 總分(3位整數) : 444 <Enter> 23010004 記錄已經加入資料庫中! 請輸入起迄記錄編號(0 10): 10 10 <Enter> 准考證號碼=23010004 姓名=李四 性別=2 總分=444 正修科技大學計算機中心

  27. 【例題idfile】 從資料庫 sfile.dat 建立一個以准考證號碼為順序的索引檔 idfile.txt,每一個索引記錄包括兩欄: 准考證號碼 欄名為 id,整數型態,佔 4 個位元組。 索引 欄名為 nodenum,整數型態,佔 4 個位元組, 為該准考證號碼之記錄在資料庫 sfile.dat 中的 記錄編號。 【分析】 將資料庫 sfile.dat 中的記錄逐筆讀入記憶體中,逐筆輸出至索引本文檔 idfile.txt。 正修科技大學計算機中心

  28. 【說明】 在 idfile.c 程式中宣告兩個檔案 sfile 及 idfile 如下: FILE *sfile; sfile=fopen("sfile.dat", "r+b"); FILE *idfile=fopen("temp.txt", "w"); idfile 訂為輸出本文檔,檔名暫訂為 "temp.txt",這個檔案在程式執行完畢後會被刪除的。 for (n=0L; n<totalnodes; n++) { offset = n * sizeof(snode); fseek(sfile, offset, SEEK_SET); fread(&snode, sizeof(snode), 1, sfile); fprintf(idfile, "%08d%5ld\n", snode.id, n); } 逐筆讀入 snode 後,將准考證號碼 snode.id 及索引 n 輸出至索引本文檔 idfile。 正修科技大學計算機中心

  29. system("SORT temp.txt /o idfile.txt"); system("DEL temp.txt"); system("TYPE idfile.txt"); 將 temp.txt 本文檔依准考證號碼排序後存入 idfile.txt 本文檔,然後將 temp.txt 本文檔刪除,再將 idfile.txt 檔的內容顯示出來。這三個命令 SORT、DEL、TYPE 是 Windows 系統所提供的命令,您若使用 Linux 系統,其寫法會不同的。在 Windows 系統您要了解有那些命令可用,可在「命令提示視窗」輸入 HELP 命令就可以了。 C:\> HELP <Enter> 您想了解 SORT 的使用法,可輸入: C:\> SORT /? <Enter> 正修科技大學計算機中心

  30. 【程式idfile.c執行結果】 23010001 0 23010003 1 23010004 10 23010005 2 23010007 3 23010009 4 23010011 5 23010013 6 23010015 7 23010017 8 23010019 9 正修科技大學計算機中心

  31. 【例題query】 利用索引檔 idfile.txt,從鍵盤輸入一個准考證號碼,在索引檔中使用 二分搜尋法,找出該准考證號碼的考生在資料庫 sfile.dat 中的記錄編 號,然後列印出該考生的明細。 【分析】 因為 sfile.txt 檔已經依准考證號碼順序,所以可以使用二分搜尋法找尋指定的准考證號碼,取得其相對應的記錄編號(索引),從而取得該考生的明細。 為了提高搜尋速度,將 sfile.txt 讀入記憶體的 itag 結構裡,itag 結構宣告如下(本結構宣告存於stag.h表頭檔): 正修科技大學計算機中心

  32. struct itag { int id; int index; } ; struct itag inode, *ip; inode 為 struct itag 的結構型態變數,ip 為其指標。每一個結構包含兩欄,id 欄為准考證號碼,index 欄為相對應記錄編號(索引)。在程式裡您可宣告一個 inodes[] 陣列,將 sfile.txt 檔每筆記錄讀入陣列裡。 #define MAXNODES 300 struct itag inodes[MAXNODES]; 就可對該陣列使用 qsort() 加於排序或使用 bsearch() 搜尋了。 正修科技大學計算機中心

  33. 【說明】 程式 query.c 中設計一個 setupinodes() 函式負責從 idfile.txt 逐一 讀入至 inodes[] 陣列,並傳回總筆數,存入 idcount 變數。 qsort(inodes, idcount, sizeof(struct itag), comp); 將 inodes[] 陣列依准考證號碼由小至大排序。若 idfile.txt 已經排序 過了,那麼這個 qsort() 呼叫就可免了。 ip=(struct itag *)bsearch(&n, inodes, idcount, sizeof(struct itag), comp); 整數變數 n 是從鍵盤輸入的准考證號碼,在 inodes[] 裡依 comp() 的 比較方法搜尋,找到時 ip 為該 struct itag 節點的指標,找不到時其 指標值為 NULL。找到的話索引值為 ip->index,它是該 n 准考證號碼 在 sfile.dat 裡的記錄編號。 shownode((long)ip->index, sfile); 從 sfile 檔案讀取第 ip->index 筆記錄,並顯示。 正修科技大學計算機中心

  34. 【程式query.c執行結果】 請輸入准考證號碼(-1結束): 23010005 <Enter> 記錄編號=2 准考證號碼=23010005 姓名=李三多 性別=1 總分=455 請輸入准考證號碼(-1結束): 23010004 <Enter> 記錄編號=10 准考證號碼=23010004 姓名=李四 性別=2 總分=444 請輸入准考證號碼(-1結束): 23010001 <Enter> 記錄編號=0 准考證號碼=23010001 姓名=陳一心 性別=1 總分=411 請輸入准考證號碼(-1結束): -1 <Enter> 正修科技大學計算機中心

  35. 【例題update】 將指定的准考證號碼記錄從考生資料庫 sfile.dat 讀入,修改資料欄值後再輸出至同一個位置。 【說明】 將指定記錄編號的記錄使用 fread() 函式讀入至 snode 結構變數中,將每一欄的資料顯示出來後,再輸入各欄的值。更改後使用 fseek() 定位 於原來記錄位置後再將更改後的資料寫入。 正修科技大學計算機中心

  36. 【程式update.c執行結果】 請輸入准考證號碼(-1結束): 23010004 <Enter> 記錄編號=10 准考證號碼=23010004 姓名=李四 性別=2 總分=444 請輸入姓名: 李四雲 <Enter> 請輸入性別: 2 <Enter> 請輸入總分: 444 <Enter> 請輸入准考證號碼(-1結束): -1 <Enter> 請輸入准考證號碼(-1結束): 23010004 <Enter> 記錄編號=10 准考證號碼=23010004 姓名=李四雲 性別=2 總分=444 正修科技大學計算機中心

More Related