共筆
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Help
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 11.C File Processing ## 11.1 Introduction 儲存在變數和陣列裡的資料是暫時的,當程式結束後儲存的資料會全部遺失,所以程式會利用 ==**檔案(Files)**== 來長期保存大量資料。 > Files通常存放在輔助性儲存裝置 > ex:硬碟,固態磁碟(SSD),快閃儲存裝置和DVD ## 11.2 Files and Streams C將每個檔案視為連續的位元組串流(a sequential stream of bytes),不同的作業系統會有不同判斷檔案結尾的方法,像 **end-of-file marker**(檔案結尾記號)或是在系統維護管理結構中新增該檔案的總位,這些動作對我們來說是隱藏的。 ![](https://i.imgur.com/l1Cm9PX.png) #### Standard Streams in Every Program: 開啟一個檔案後,就會有一個stream和這個檔案結合在一起,同時有三個stream也會自動開啟 :::warning * standard input:從鍵盤讀取資料 * standard output:將資料印到螢幕上 * standard error:將錯誤訊息顯示到螢幕上 ::: #### Communication Channels(通訊通道): stream提供程式與檔案之間的通訊管道,讓程式可以正確的讀取資料或印出資料 #### ==FILE Structure:== 開啟檔案會回傳一個指向 **FILE結構** (定義在<stdio.h>中)的 **指標** ,這個指標通常含有處理這個檔案所需的資訊,某些作業系統的FILE結構中包含了一個 **file descriptor** (檔案描述子)也就是指到作業系統內 **open file table**(開啟檔案表)陣列的索引值,這個陣列的每一個元素都含有一個**file control block (FCB)** (程式控制區塊) 作業系統便是由FCB來管理某個檔案。標準輸入、標準輸出、標準錯誤會以下列指標進行操作:**stdin、stdout、stderr** > FCB:包含檔案位置+檔案的metadata->為了存取檔案所以需要FCB > metadata:資料屬性 #### fgetc(): ```c= fgetc("檔案指標") //如果打fgetc(stdin)會等同於getchar() ``` 有點像getchar,一次從檔案讀取一個字元 file.txt裡面: ``` 1234 555 000 ``` ```c= #include<stdio.h> int main(void){ FILE *ptr=fopen("file.txt","r"); char c; while((c=fgetc(ptr))!=EOF){ printf("%c",c); } } ``` 輸出: ``` 1234 555 000 ``` #### fputc(): ```c= fputc('要放進檔案的字元',"檔案指標") //如果打fputc('a',stdout)會等同於putchar('a') ``` 有點像putchar,一次寫入一個字元進檔案 ```c= #include<stdio.h> #include<string.h> int main(void){ FILE *ptr=fopen("file.txt","w"); char str[10]="1234567"; int i=strlen(str); while(i--){ fputc(str[i],ptr); } } ``` file.txt裡面: ``` 7654321 ``` #### fgets()&fputs(): ```c= fgets('要儲存檔案內容的字串','讀入的字串長度',"檔案指標") //fgets(str,10,stdin); //不管設定的毒入長度多長讀到換行或EOF都會停止 fputs('放進檔案的字串',"檔案指標") //fputs(str,fptr); ``` 也跟一般使用的$gets()$跟$puts()$差不多都是讀入跟寫入一行字 >fgets()會讀進換行字元,fputs()如果輸出的字串沒有換行的話不會自動換行 > >這兩個好像不能同時用在同一個檔案(?)我自己試失敗了,有人成功可以跟我說一下 >->應該是11.4提到的覆蓋資料問題 ## 11.3 Creating a Sequential-Access File ```c= // Fig. 11.2: fig11_02.c // Creating a sequential file #include <stdio.h> int main(void) { FILE *cfPtr;// cfPtr = clients.txt file pointer // fopen opens file. Exit program if unable to create file if ((cfPtr = fopen("clients.txt","w")) == NULL) { puts("File could not be opened"); } else { puts("Enter the account, name, and balance."); puts("Enter EOF to end input."); printf("%s", "? "); unsigned int account; // account number char name[30]; // account name double balance; // account balance scanf("%d%29s%lf", &account, name, &balance); // write account, name and balance into file with fprintf while (!feof(stdin)) { fprintf(cfPtr,"%d %s %.2f\n", account, name, balence); printf("%s", "? "); scanf("%d%29s%lf", &account, name, &balance); } fclose(cfPtr);// fclose closes file } } ``` ### 11.3.1 Pointer to a FILE 第7行的cfPtr表示指向FILE結構的指標。 ### 11.3.2 Using fopen to Open the File 每個開啟的檔案必須要有個別的FILE型別的指標。第10行說明程式要使用"client.txt"這個檔案。$fopen()$的使用方式: ```c= fopen("檔案名稱","檔案開啟模式")//檔案開啟模式在11.3.6 ``` >如果沒有指定檔案路徑會直接程式所在的目錄尋找 >如果用"w"來開啟某個已經存在的檔案,但使用者實際上希望保存這個檔案。將會在沒有警告的情況下刪除這個檔案[name=小蜜蜂] >在程式參考某個檔案之前,忘記先開啟這個檔案會發生邏輯錯誤[name=小蜜蜂] ### 11.3.3 Using feof to Check for the End-of-File Indicator 第22行的$feof()$是用來判斷**stdin**的檔案是否在檔案的結尾設定結尾信號。結尾信號會通知程式已經沒有資料要進行處理。$feof()$在遇到結尾信號$EOF$的時候會**傳回true(1),否則傳回flase(0)。** ```c= feof("檔案指標"); ``` |作業系統| EOF按鍵| |:-|:-| |Windows|Ctrl+z| |Linux/Mac OS X/UNIX|Ctrl+d| ### 11.3.4 Using fprintf to Write to the File 第26行使用$fprintf()$用來將測資傳送到檔案中 ```c= fprintf("要寫進的檔案指標","輸出格式","要輸出的資料"); //fprintf(stdout,"%d",10)跟printf("%d",10)的意義是一樣的 ``` ### 11.3.5 Using fclose to Close the File 第31行中,當輸入檔案結尾之後(feof),程式會使用 $fclose()$來關閉檔案clients.txt,若沒有呼叫函數$fclose()$ 當程式停止執行後,作業系統通常會自己關閉檔案 ```c= fclose("檔案指標"); ``` > 關閉一個檔案會釋放資源給其他正在等待這項資源的使用者或程式,因此應該確定檔案再也不使用就要關閉檔案,而非等到作業系統關閉[name=小蜜蜂] ### FILE指標&FILE結構&FCB之間的關係 當開啟一個檔案時,檔案的FCB會複製到記憶體中,程式中所使用的檔案必須具有唯一的名稱 ![](https://i.imgur.com/DI0B3P5.png) 上面的圖在說檔案指標跟FCB的連結關係,翻譯如下: * cfPtr=fopen("clients.dat","w"); &rarr;fopen回傳指向FILE結構的指標 * "clients.dat"的FILE結構包含一個描述子,也就是一個小的整數,代表指向開啟檔案表的索引 * 當程式發出I/O呼叫,像fprintf(ctPtr,"%d",account); 的指令,程式會在FILE結構中找到描述子(7),並使用描述子在開啟檔案表中找到FCB * 此程式會呼叫一個作業系統服務,此服務會使用FCB中的資料來控制所有到磁碟機真正檔案的輸入輸出(使用者不能直接存取FCB) * 當檔案開啟時,此項目會從磁碟機上FCB被複製出來 ### ==11.3.6 File Open Modes== :::warning |檔案開啟模式|說明| |:-|:--| |r|開啟用來讀取的檔案。(檔案不存在fopen()會回傳NULL)| |w|建立一個用來寫入的檔案。如果檔案已經存在,就會刪除已經存在的內容。| |a|附加;開啟或是建立一個用來將資料寫到檔案結尾的檔案。 |r+|開啟一個用來更新資料的檔案(可讀寫)。 |w+|建立一個用來更新資料的檔案。如果檔案已經存在,就會刪除已經存在的內容。 |a+|附加:開啟或是建立一個檔案,將資料寫到檔案結尾。 |rb|以二進位模式開啟一個用來讀取的檔案。 |wb|以二進位模式開啟一個用來寫入的檔案。如果檔案已經存在,程式就會刪除已經存在的內容。 |ab|以二進位模式附加、開啟或是建立一個用來將資料寫到檔案結尾的檔案。 |rb+|以二進位模式開啟一個用來更新資料的檔案(可讀寫)。 |wb+|以二進位模式開啟一個用來更新資料的檔案。如果檔案已經存在,程式就會刪除已經存在的內容。 |ab+|附加:以二進位模式開啟或是建立一個檔案,將資料寫到檔案結尾。 ::: 當使用w, w+, wb, wb+模式時,C11提供獨佔寫入模式。如果檔案已經存在或無法建立fopen會失效。如果成功開啟或建立一個檔案時,將只會有你的程式能夠進行檔案存取。如果任何模式開啟檔案時產生錯誤,fopen將會傳回NULL。 >以讀取模式開啟一個不存在的檔案會發生錯誤[name=小蜜蜂] >開啟一個用來讀取或寫入的檔案,但沒有設定正確的檔案存取權限(跟作業系統有關)會導致錯誤[name=小蜜蜂] >當沒有足夠的磁碟空間時,開啟檔案會導致執行錯誤[name=小蜜蜂] >用寫入模式("w")開啟一個必須使用更新模式("r+")開啟的檔案會導致原本檔案中的內容遺失[name=小蜜蜂] >如果不需要修改檔案內容請以唯讀方式(不會更新檔案)開啟檔案,這可以防止不小心修改到檔案。這是最小權限原則的另一個例子[name=小蜜蜂] ## 11.4 Reading Data from a SequentialAccess File 這章在討論如何循序讀取一個檔案 下面程式碼的重點(?: * fscanf()相當於scanf(),只是需要再加上一個檔案指標的引數 * 用fopen()的回傳值不等於NULL來判斷是否正確開啟這個檔案 * feof()判斷檔案是否結束 ![](https://i.imgur.com/zx4MEtS.png) ![](https://i.imgur.com/sVr70dS.png) ### 11.4.1 Resetting the File Position Pointer #### rewind(): ```c= rewind("檔案指標") ``` 將檔案位置指標 **(file postition pointer)** 重新指回檔案開頭,這樣就可以重複讀取檔案 * 檔案位置指標 **(file postition pointer)** -- FILE結構中的一員,並不是真的指標而是一個整數值,代表檔案中下一個讀取或寫入的位元組,通常也稱**檔案位移(file offset)** ```c= #include<stdio.h> #include<string.h> int main(void){ FILE *ptr=fopen("file.txt","r"); char str[100]; int i=2;//設定要讀兩次檔案 while(i){ fputs(str,stdout);//將讀到的結果放到標準輸出(=puts(str)) //如果檔案結束 if(fgets(str,100,ptr)==NULL){ fputs("\n",stdout); //排版(# rewind(ptr); //重置檔案位置指標 fgets(str,100,ptr);//重新讀進一行字,這時候str會等於檔案一開頭的那行字 i--; } } fclose(ptr); //關檔案 } ``` file.txt裡的東西: ``` 12345678 6666666 helloworld! 5555555 ``` 輸出樣子(檔案重複輸出了兩次): ``` 12345678 6666666 helloworld! 5555555 12345678 6666666 helloworld! 5555555 ``` ### 11.4.2 Credit Inquiry Program 下面的信用查詢程式有四種選項: :::info * 選項1:產生欠款餘額為零的帳戶清單 * 選項2:產生欠款餘額為負的帳戶清單 * 選項3:產生欠款餘額為正的帳戶清單 * 選項4:結束程式 ::: ![](https://i.imgur.com/PMNi4ma.png) ![](https://i.imgur.com/BUD66RI.png) ![](https://i.imgur.com/p4gisZP.png) ### Updating a Sequential File(更改循序檔案): 如果想要更改這種 **循序檔案(重複讀取的檔案)** 中的資料,可能會破壞檔案中的其他資料,像是如果<font color="3D88FA">新的紀錄比原本的紀錄長的話可能會導致新的資料覆蓋到下一個循序紀錄的開頭部分</font>。這個問題是因為在 **fprintf()&fscanf()的格式化輸入/輸出模式(formatted input/output model)** 中,欄位大小是可以改變的,像是100、14、2074這些數字都是儲存在相同位元組中的int,但在顯示到螢幕或是寫進檔案中他們的<font color="3D88FA">欄位寬度卻不一樣</font>。 因此,以 **fprintf()跟fscanf()** 來進行循序存取通常不會更改檔案中的紀錄,常見的更改方法就是將整個檔案重新寫過 <font color="9A9A9A"> &rarr;複製檔案並將更改的資料寫進新檔案中</font> * **更改一筆資料則需要處理當案中的每一筆資料** ## 11.5 Random-Access Files 因為$fprintf()$的長度不一定會一樣,所以可以創造一個random-access file(隨機存取檔案)來讓每一個紀錄有固定的長度。通常用於需要直接進行存去的資料(不需要在記憶體中搜尋) ## 11.6 Creating a Random-Access File ### fwrite: ```c= fwrite("要寫入資料的指標","要寫入的資料大小","寫入的資料個數","檔案指標"); //fwrite(&a,sizeof(int),1,ptr)有點像fprintf(ptr,"%d",a); ``` * $fwrite()$主要是以固定大小來存取資料,所以要修改資料時會較好修改 * 讀入資料大小通常以$sizeof()$來計算 * 檔案處理程式很少只寫一種資料進檔案中,通常會搭配$struct$來使用 * 第三個引數通常填1,若想要寫入一個陣列可以把第三個引數改成要寫入的陣列大小,前面則是一個指向陣列的指標 ## 11.7 Writing Data Randomly to a Random-Access File ```c= // Fig. 11.11: fig11_11.c // Writing data randomly to a random-access file #include <stdio.h> // clientData structure definition struct clientData{ unsigned int acctNum; // account number char lastName[15]; // account last name char firstName[10]; // account first name double balance; // account balance }; // end structure clientData int main(void) { FILE *cfPtr; // accounts.dat file pointer // fopen opens the file; exits if file cannot be opened if ((cfPtr = fopen("accounts.dat","rb+")) == NULL) { puts("File could not be opened."); } else { // create clientData with default information struct clientData client = {0, "", "", 0.0}; // require user to specify account number printf("%s", "Enter account number" " (1 to 100, 0 to end input): "); scanf("%d", &client.acctNum); // user enters information, which is copied into file while (client.acctNum != 0) { // user enters last name, first name and balance printf("%s", "\nEnter lastname, firstname, balance: "); // set record lastName, firstName and balance value fscanf(stdin, "%14s%9s%lf", client.lastName, client.firstName, &client.balance); // seek position in file to user-specified record fseek(cfPtr, (client.acctNum - 1) * sizeof(struct clientData), SEEK_SET); // write user-specified information in file fwrite(&client, sizeof(struct clientData), 1, cfPtr); // enable user to input another account number printf("%s", "\nEnter account number: "); scanf("%d", &client.acctNum); } fclose(cfPtr); // fclose closes the file } } ``` ### 11.7.1 Positioning the File Position Pointer with fseek 40-41行的$fseek$中的$(client.accountNum-1)*sizeof(struct clientData)$所計算出的稱為**offset(偏移量)以及displacement(位移)**。與陣列相同,對第一個而言,會被視為檔案中的位元組0。 ### fseek: ```c= fseek("檔案指標","資料位移量","符號常數(位移開始的位置)"); //fseek(fptr,10*size(int),SEEK_SET) ``` * offset(偏移量)為正往後移,為負的往前移 * **符號常數(定義在$<stdio.h>$中):** **SEEK_SET: 從檔案開頭開始位移** **SEEK_CUT: 從檔案目前位置開始位移** **SEEK_END: 從檔案結尾處開始位移** ### 11.7.2 Error Checking 可以藉由查看fseek、fscanf、fwrite的傳回值來判斷讀取資料時是否有出現錯誤 :::warning * $fsacnf()$:會回傳成功讀取的資料個數,若讀取錯誤會回傳EOF * $fseek()$:發生錯誤會回傳非0值 * $fwrite()$:回傳成功輸出的項目數量~(第三個引數)~ ::: ## 11.8 Reading Data from a Random-Access File ### fread: ```c= fread("要讀入資料的指標","讀入的資料大小","讀入的資料個數","檔案指標"); //fread(&a,sizeof(int),1,ptr)有點像fscanf(ptr,"%d",&a); ``` * 可參考$fwrite()$用法 * 會回傳成功讀入的資料數量,若發生錯誤則會傳值小於第三個引數 * 若要把資料讀入陣列可改第三個引數 ## 11.9 Case Study: Transaction-Processing Program ```c= // Fig. 11.15: fig11_15.c // Transaction-processing program reads a random-access file sequentially, // updates data already written to the file, creates new data to // be placed in the file, and deletes data previously stored in the file. #include <stdio.h> // clientData structure definition struct clientData{ unsigned int acctNum; // account number char lastName[15]; // account last name char firstName[10]; // account first name double balance; // account balance }; // prototypes unsigned int enterChoice(void); void textFile(FILE *readPtr); void updateRecord(FILE *fPtr); void newRecord(FILE *fPtr); void deleteRecord(FILE *fPtr); int main(void) { FILE *cfPtr; // accounts.dat file pointer // fopen opens the file; exits if file cannot be opened if ( ( cfPtr = fopen("accounts.dat","rb+"))== NULL) { puts("File could not be opened."); } else { unsigned int choice; // user's choice // enable user to specify action while ((choice = enterChoice()) != 5) { switch (choice) { // create text file from record file case 1: textFile(cfPtr); break; // update record case 2: updateRecord(cfPtr); break; // create record case 3: newRecord(cfPtr); break; // delete existing record case 4: deleteRecord(cfPtr); break; // display message if user does not select valid choice default: puts("Incorrect choice"); break; } } fclose(cfPtr); // fclose closes the file } } // create formatted text file for printing void textFile(FILE *readPtr) { FILE *writePtr; // accounts.txt file pointer // fopen opens the file; exits if file cannot be opened if (( writePtr = fopen("accounts.txt","w")) == NULL) { puts("File could not be opened."); } else { rewind(readPtr); // sets pointer to beginning of file fprintf(writePtr, "%-6s%-16s%-11s%10s\n", "Acct", "Last Name", "First Name","Balance"); // copy all records from random-access file into text file while (!feof(readPtr)) { // create clientData with default information struct clientData client = { 0, "", "", 0.0 }; int result = fread(&client, sizeof(struct clientData), 1, readPtr); // write single record to text file if (result != 0 && client.acctNum != 0) { fprintf(writePtr,"%-6d%-16s%-11s%10.2f\n" client.accNum, client.lastName, client.firstName, client.balance); } } fclose(writePtr); // fclose closes the file } } // update balance in record void updateRecord(FILE *fPtr) { // obtain number of account to update printf("%s", "Enter account to update (1 - 100): "); unsigned int account; // account number scanf("%d", &account); //move file pointer to correct record in file fseek(fPtr, (account-1) * sizeof(struct clientData), SEEK_SET); // create clientData with no information struct clientData client = {0, "", "", 0.0}; // read record from file fread(&client, sizeof(struct clientData),1,fPtr); // display error if account does not exist if (client.acctNum == 0) { printf("Account #%d has no information.\n", account); } else { // update record printf("%-6d%-16s%-11s%10.2f\n\n", client.acctNum, client.lastName, client.firstName, client.balance); // request transaction amount from user printf("%s", "Enter charge (+) or payment (-): "); double transaction; // transaction amount scanf("%lf", &transaction); client.balance += transaction; // update record balance printf("%-6d%-16s%-11s%10.2f\n", client.acctNum, client.lastName, client.firstName, client.balance); //move file pointer to correct record in file fseek(fPtr, (account - 1) * sizeof(struct clientData), SEEK_SET) //write updated record over old record in file fwrite(&client, sizeof(struct clientData), 1, fPtr); } } // delete an existing record void deleteRecord(FILE *fPtr) { // obtain number of account to delete printf("%s", "Enter account number to delete (1 - 100): "); unsigned int accountNum; // account number scanf("%d", &accountNum); // move file pointer to correct record in file fseek(fPtr, (accountNum - 1) * sizeof(struct clientData), SEEK_SET); struct clientData client; // stores record read from file // read record from file fread(&client, sizeof(struct clientData), 1, fPtr); // display error if record does not exist if (client.acctNum == 0) { printf("Account %d does not exist.\n", accountNum); } else { // delete record // move file pointer to correct record in file fseek(fPtr, (accountNum - 1) * sizeof(struct clientData), SEEK_SET); struct clientData blankClient = {0, "", "", 0}; // blank client // replace existing record with blank record fwrite(&blankClient, sizeof(struct clientData), 1, fPtr); } } // create and insert record void newRecord(FILE *fPtr) { // obtain number of account to create printf("%s", "Enter new account number (1 - 100): "); unsigned int accountNum; // account number scanf("%d", &accountNum); // move file pointer to correct record in file fseek(fPtr, (accountNum - 1) * sizeof(struct clientData), SEEK_SET); // create clientData with default information struct clientData client = { 0, "", "", 0.0 }; // read record from file fread(&client, sizeof(struct clientData), 1, fPtr); // display error if account already exists if (client.acctNum != 0) { printf("Account #%d already contains information.\n", client.acctNum); } else { // create record // user enters last name, first name and balance printf("%s", "Enter lastname, firstname, balance\n? "); scanf("%14s%9s%lf", &client.lastName, &client.firstName, &client.balance); client.acctNum = accountNum; //move file pointer to correct record in file fseek(fPtr, (client.accNum - 1) * sizeof(struct clientData), 1, fPtr); //insert record in file fwrite(&client, sizeof(struct clientData), 1, fPtr); } } // enable user to input menu choice unsigned int enterChoice(void) { // display available options printf("%s", "\nEnter your choice\n" "1 - store a formatted text file of accounts called\n" " \"accounts.txt\" for printing\n" "2 - update an account\n" "3 - add a new account\n" "4 - delete an account\n" "5 - end program\n? "); unsigned int menuChoice; // variable to store user's choice scanf("%u", &menuChoice); // receive choice from user return menuChoice; } ``` ![](https://i.imgur.com/IV1QNrt.png) * 選項一呼叫函式textFile,將所有的帳戶格式化清單存到一個稱為accounts.txt的文字檔當中。 * 選項二呼叫函式updatedRecord,可以將"已存在的帳戶"進行更改,再輸入帳號號碼的時候,城市會先使用fread來確定是否有此筆資料,如果此資料為0的話,就會跳出"此紀錄為空",如果有帳戶資料的話就會跳出欲修改的金額。 * 選項三呼叫函式newRecord,可以增加一個新的帳戶到這個檔案之中,若已有檔案的話,程式會提示已有資料。 * 選項四呼叫函式deletedRecord,可以在檔案當中刪除一筆資料,若本來沒有此資料,程式會提示沒有此筆資料。 * 選項五代表結束此程式 通常這種需要進行修改以及讀取的資料會使用"rb+"來開啟檔案 ## 11.10 Secure C Programmin ### fprintf_s&fscanf_s: 除了指定FILE指標參數來進行處理,其他與printf_s&scanf_s並無不同,若c編譯器標準函式庫包含這些函式則應該使用這兩個函式更為安全 ### CERT安全C撰寫標準的第9章: 第9章主要探討輸出入和規則,關於檔案處理的內容都在這章介紹 * FIO03-C: 當以非獨占檔案開啟模式來打開寫入檔案(沒有w的),若有此檔案,函式$fopen()$開啟檔案並擷取其內容,在$fopen()$呼叫前沒有跡象顯示檔案存在。要確認現有的檔案不適被開啟及擷取,可以使用C11新的獨佔模式(章節11.3),在檔案不存在時用$fopen()$開啟。 * FIO04-C: 一個好的程式碼必須確認檔案處裡函式的回傳值是否傳回錯誤代碼,這確認了函示是否被正確執行。 * FIO07-C: 函式$rewind()$不會回傳任何的值,因此無法確認運行是否正常,建議==使用$fseek()$替代==,因為發生錯誤後$fseek()$可回傳非0的值。 * FIO09-C: 本章介紹到文字檔案及二進制檔案,由於不同平台二進制資料的表示差異,以二進制寫入的檔案通常不可攜,若要更可攜的檔案描述,參考使用文字檔案和函式庫,可處理跨平台在二進制檔案表示上的差異。 * FIO14-C: 某些函式庫在文字檔案和二進制檔案的運作並非相同,像是在==函式$fseek()$中使用SEEK_END來位移的話不保證運行正確,建議使用SEEK_SET==。 * FIO42-C: 在許多平台一次只能開啟有限個檔案,所以在檔案不在被程式使用時就應該將其關閉。 簡單講就是用不到^^ ###### tags: `程設好難` `學校門口大樹石頭下` `他的課就很好睡阿` <style> .navbar-brand::after { content: " × 老葉的程式設計"; } </style>

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully