2017-04-09 63 views
2

一般來說,一旦文件句柄打開,文件就會打開,並且沒有人更改目錄結構可以更改文件 - 文件可以移動,重新命名或放置其他東西 - 它仍然是通過構建打開的,因爲在Linux/Unix中沒有真正的文件刪除,但只有unlink,它不一定刪除文件 - 它只是從目錄中刪除鏈接。結果:無論文件發生什麼情況,文件句柄都將保持有效。在文件打開時檢查文件指針在C中的有效性

但是,如果底層設備消失(例如,文件位於從系統中移除的USB存儲棒上),則該文件將不再可用。

我有一個程序,在開始時打開一個巨大的二進制文件(> 4 GB)的其他應用程序。此後,這手錶更改文件,通過查詢

long int pos = fseek(filepointer, 0L, SEEK_END); 

經常(每隔幾毫秒),並恢復到以前的位置,如果結果是pos_before不同。在這種情況下,fgets用於從文件中讀取新數據。

因此,只掃描文件尾部的變化,使整個過程相當輕量級。但是,它受潛在問題的影響,即如果文件系統發生更改(如上所述),始終打開的文件指針可能會失效。

該代碼不需要可移植到任何非Linux/Unix系統。

問:

  • 我如何檢測文件指針仍然有效已經成功打開該文件後(此事件可能是星期前)?我已經看到可以使用fcntl(fileno(filepointer), F_GETFD)進行測試。

替代問題:

  • 難道是檢測以另一種方式在文件大小的變化是否可行?我能想到用定期
    • fseek(filepointer, 0L, SEEK_END);的(可能會很慢,造成大量的I/O),或
    • _filelength(fileno(filepointer));(不清楚這是否會導致大量的I/O)
    • stat(filename, &st); st.st_size;(不清楚這是否會導致任何 I/O)
+1

我沒有Linux,但在Windows中,您無法刪除或移動已被另一個進程打開的文件,如果'nix系統不是這種情況,我也會感到驚訝。至於刪除打開文件的介質,這就是您應該始終檢查I/O操作結果的一個原因。 (並詢問系統是否允許刪除媒體)。 –

+0

@WilliamPursell我沒有這樣說,你可以(例如對捲進行碎片整理)。我說你不能刪除已經打開的文件,原因很明顯。 –

+0

@WeatherVane「mov [ing]文件」和更改名稱之間的區別是什麼? –

回答

2

嘛,通常是一個打開的文件會阻止卸載文件系統,因此它不應該只是在你消失了。儘管使用USB盤等,當然用戶不用詢問系統就可以拉動設備。

但它會很好的過程到不是防止乾淨卸載。 這需要兩件事情:

  1. 不要把文件打開
  2. 不要將其所包含的目錄作爲工作目錄的過程。

定期在路徑上運行stat(2)將是做到這一點的方法。您可以檢測文件修改爲mtime,ctime(文件大小)的更改。 inode號碼或包含設備(st_dev)中的錯誤和更改可能表示該文件不再可訪問,或者不再是同一個文件。根據應用要求做出反應。

(也就是說,假設你有興趣目前指向該,而不是在同一的inode你打開的文件中。)

至於I/O,很可能是定期將內存中的inode緩存起來,所以這個問題會比I/O更關於內存使用情況。 (直到你做到這一點足夠的文件不能緩存它們,這會導致垃圾,存儲器和I/O的問題...)尋求到文件的結尾也將類似地要求加載的長度該文件,我看不出爲什麼會導致任何重要的I/O。

另一種選擇是在文件或整個目錄上使用inotify(7)來檢測更改而不進行輪詢。它也可以檢測卸載事件。

+0

在我的情況下,特定的問題是,打開的文件(取決於嵌入式系統的安裝)可能會放置在一段時間後會發生硬重置的虛擬硬盤上。這是既不友善也不受我的申請控制。我已經嘗試過'inotify',但是它給了我一些'arm'目標的高CPU負載,所以我放棄了它。我只關心一個文件可能會變得很大(在/ var/log中的一個日誌文件)。我會嘗試使用'stat'。 – MrD

2

我怎樣才能檢測是否已經打開該文件後,文件指針仍然是有效的成功

如果FILE*沒有明確fclose() d通過打開(或繼承)的過程中它如果所涉及的過程未調用Undefined Behaviour,則FILE*根據定義有效。

在情況下,任何底層不能(或直接通過執行例如read(fileno(fp))通常經由電話間接升高到LIBC像fread()fwrite()fseek())發生故障的功能滿足由FILE* fp的過程發出的請求應返回指示錯誤條件並相應地設置errno,這通常將是EIO

只是執行完整的錯誤檢查和處理,你不會遇到任何問題。