2009-02-03 64 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