2009-02-03 121 views
2

我用fopen打開了一個非常大的文件流。 在對該流執行任何讀取操作之前,我使用unlink()刪除了該文件。 而且,我仍然可以閱讀整個文件。文件被刪除後,fread可能嗎?

我猜測有一個與流相關的緩衝區,它保存着文件的數據。但顯然緩衝區會有一個限制。這就是我選擇大小爲551126688字節或526MB的a_big_file的原因。

我想知道背後的確切原因是什麼。 這是我使用的測試代碼。

#include <stdio.h> 
#include <unistd.h> 

int main(){ 

    FILE *fp; 
    long long int file_size = 0; 
    int bytes_read = 0; 
    char buf[1]; 

    fp = fopen("a_big_file", "r"); 

    unlink("a_big_file"); 

    while(0 != (bytes_read = fread(buf, 1, 1, fp))){ 
     file_size += bytes_read; 
    } 

    printf("file_size is %llu\n", file_size); 

    return 0; 
} 

輸出: FILE_SIZE是551126688

+0

哎呀......我的眼睛越來越不好。我認爲這說「FRED可能......」 – StingyJack 2009-02-03 13:51:22

+0

FRED是Macintosh Common Lisp的編輯,Digitool從未管理過遷移到OSX。令人遺憾的是,我不知道在現代Macintosh上它仍然是可能的,儘管許多MCL仍然存在。 – 2009-02-03 15:06:12

回答

17

在Unix和類Unix操作系統,該文件實際上並沒有離開,直到它最後一個打開的文件句柄被關閉。這對於臨時文件是一個非常有用的技巧 - 如果您在打開它時立即取消鏈接,則該文件對其他進程將不可見,並且只要程序關閉它就會從系統中刪除,結束或崩潰。這有助於防止孤兒臨時文件的擴散。

實際上(這裏略去一些技術細節)會發生什麼情況是Unix文件系統被引用計數。當您打開文件時,您實際上已連接到文件的inode(這是文件實際內容所在位置的真實指示)。但是,取消鏈接文件只是刪除目錄條目,所以文件不再有名稱。如果文件系統不在任何目錄條目中,文件系統只會回收文件空間(即inode),並且沒有人將其打開。其他進程無法以普通方式打開它,因爲它們無法將文件名映射到inode。

請注意,Unix文件系統允許多個目錄條目指向相同的inode - 我們稱之爲「硬鏈接」。如果你做了「ls -l」,其中一個字段就是同一個inode的硬鏈接的數量,如果你做了「ls -li」,你可以看到實際的inode地址。

+0

好的,這是一個快速的答案:),但我有興趣知道系統內發生了什麼。我很想知道爲什麼其他進程無法看到該文件。我的意思是內部發生了什麼,你能否說出一些光:) – 2009-02-03 13:55:54

+0

因爲不再有指向inode的文件名。所以如果你已經有一個文件句柄,你仍然可以使用它(在任何進程中),但是你不能再獲得新的文件句柄。 – puetzk 2009-02-03 14:08:50

9

從手冊頁之間的連結:

的unlink()刪除從 文件系統的名稱。如果該名稱是最後一個 指向文件的鏈接,並且沒有進程具有 ,則會刪除該文件的打開文件,並且將使用的空間爲 可供重用。

如果這個名字的最後一個環節,以 一個文件,但任何進程仍然有 文件打開該文件將保持在 存在,直到最後一個文件 描述指的是 關閉。

大膽的位說明行爲。 :-)

[編輯]順便說一句,你真的應該關閉該文件與return語句之前FCLOSE()... [/編輯]

0

Linux,文件實際上只是刪除時,它的最後一個打開的句柄關閉。

人們通常以這種方式使用臨時文件:mkstemp(3)然後立即unlink(2)。這樣只有你可以訪問文件的數據,沒有其他進程可以。

即使另一個進程創建具有相同名稱的其他文件,它們的新文件也與原始文件沒有任何共同之處。

3

在某些系統(如Linux)上,只要進程仍然打開文件系統,就可以輕鬆訪問文件系統上沒有名稱的文件。有文件描述符的

/proc/<pid>/fd 

編輯列表:根據Paul Tomblin的評論,你只能在這個目錄,如果你是相同的用戶進程或root訪問權限。

例如:

# Create a file with cat 
[email protected]:~$ cat > MYFILE 
Hello 

# Suspend the process and find its pid 
[1]+ Stopped     cat > MYFILE 
[email protected]:~$ ps waux | grep cat 
chris  1311 0.0 0.0 5088 668 pts/6 T 14:29 0:00 cat 
chris  1313 0.0 0.0 5168 840 pts/6 R+ 14:29 0:00 grep cat 

# Inspect the list of open files 
[email protected]:~$ cd /proc/1311/fd 
[email protected]:/proc/1311/fd$ ls -l 
total 0 
lrwx------ 1 chris chris 64 2009-02-03 14:29 0 -> /dev/pts/6 
l-wx------ 1 chris chris 64 2009-02-03 14:29 1 -> /home/chris/MYFILE 
lrwx------ 1 chris chris 64 2009-02-03 14:29 2 -> /dev/pts/6 

# View MYFILE from the symlink on the /proc pseudofilesystem. 
[email protected]:/proc/1311/fd$ cat 1 
Hello 

# Delete the filename /home/chris/MYFILE 
[email protected]:/proc/1311/fd$ rm /home/chris/MYFILE 
[email protected]:/proc/1311/fd$ cat /home/chris/MYFILE 
cat: /home/chris/MYFILE: No such file or directory 

# But the process still has it open. 
# The /proc system knows the original name was deleted 
[email protected]:/proc/1311/fd$ ls -l 
total 0 
lrwx------ 1 chris chris 64 2009-02-03 14:29 0 -> /dev/pts/6 
l-wx------ 1 chris chris 64 2009-02-03 14:29 1 -> /home/chris/MYFILE (deleted) 
lrwx------ 1 chris chris 64 2009-02-03 14:29 2 -> /dev/pts/6 

# We can still view the file, useful for debugging. 
[email protected]:/proc/1311/fd$ cat 1 
Hello