假設一個純文本檔案foo.txt,和兩個行程:
- 行程 A,一個 shell 腳本,定期覆寫檔案
$ echo "example" > foo.txt - 行程 B,一個 C 程式,定期從檔案中讀取
fopen("foo.txt", "r"); getline(buf, len, fp); fclose(fp);
在 C 程式中,FILE* fp在初始之后保持打開fopen(),執行 arewind()并再次讀取似乎并不能反映在此期間檔案發生的更改。是通過fclose()andfopen()回圈查看更新內容的唯一方法,還是有辦法重新使用已經打開的FILE句柄,但讀取最近寫入的資料?
對于背景關系,我只是想找到最有效的方法。
uj5u.com熱心網友回復:
在 Unix/Linux 上,當您創建一個名稱已經存在的檔案時,舊檔案不會被洗掉或以任何方式更改。創建了一個新檔案,并且更新了目錄以指向新檔案而不是舊檔案。
舊檔案將繼續存在,只要它的某些目錄入口點(Unix檔案系統允許多個目錄指向同一個檔案)或某些程式具有該檔案的打開檔案句柄,這與您更相關問題。
只要您不關閉fp,它就會繼續參考原始檔案,即使檔案系統不再參考該檔案。當您關閉fp時,該檔案將自動進行垃圾收集,并且在您下次打開foo.txt時,您將獲得一個檔案描述符,該描述符在該時間點恰好具有該名稱的任何檔案。
簡而言之,使用您指定的 shell 腳本,您的 C 程式必須關閉并重新打開檔案才能看到新內容。
從理論上講,shell 腳本可以覆寫同一個檔案而不洗掉它,但是 (a) 這很難正確處理;(b) 容易出現競爭條件;(c) 關閉和重新打開檔案并不那么耗時。但如果你這樣做了,你就會看到變化。[注1]
特別是,附加到現有檔案很常見(也很容易),如果您有一個執行此操作的 shell 腳本,您可以保持檔案描述符打開并查看更改。但是,在這種情況下,您通常會在添加新資料之前讀取到檔案末尾,并且標準 C 庫將feof()指標視為粘性;一旦設定好,您將繼續從新讀取中獲得 EOF 指示。如果您懷疑某些行程會將更多資料寫入檔案,則應fseek(fp, 0, SEEK_CUR);在重試讀取之前重置 EOF 指示。
筆記
- 正如@amadan在評論中指出的那樣,也有競爭條件
echo text > foo.txt,盡管視窗有點短。但是你絕對可以通過使用 idiom 來避免競爭條件echo text > temporary_file; mv -f temporary_file foo.txt,因為重命名操作是原子的。當然,這肯定需要您關閉并重新打開檔案。但這是一個好主意,特別是如果正在撰寫的內容很長或很關鍵,或者如果經常創建新檔案。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/463868.html
上一篇:使用systemD需要等待嗎
