【问题标题】:How to delete a file in C using a file-descriptor?如何使用文件描述符删除 C 中的文件?
【发布时间】:2020-10-19 09:08:05
【问题描述】:

在我的代码中,我使用 mkstemp() 函数(我在 Linux 上)创建了一个具有随机名称的文件。这个函数返回的是一个int 是一个file descriptor

int fd;
char temp[] = "tempXXXXXX";

fd = mkstemp(temp);

稍后我可以通过int 文件描述符使用fdopen() 访问该文件。

FILE *file_ptr = NULL;

file_ptr = fdopen(fd);

但在我的程序结束时,我想看看该文件是否仍然存在,并使用我创建它时给出的随机名称(如果成功,程序应该更改该文件名)。如果在该文件上运行rename() 函数成功,我可以设置一个标志,但是当我只有它的文件描述符时,我仍然不知道如何删除它。

if rename files => remove the temp file

我该怎么做?或者如果我有file descriptor,有没有办法获取文件名?

【问题讨论】:

  • 这能回答你的问题吗? Retrieve filename from file descriptor in C
  • @KamilCuk unlink 需要文件名,mkstemp 不提供。
  • 我不认为你可以。名称被删除,而不是文件。一个文件可能有多个名称,或者没有 - Linux 如何知道要删除哪个名称?
  • mkstemp 已经有了文件名 - 它是 mkstemp(char *template)。只需mkstemp(template); unlink(template)
  • @John mkstemp 修改模板字符串以便返回文件名。

标签: c linux file file-descriptor


【解决方案1】:

C 和 POSIX(因为您使用的是 POSIX 库函数)都没有定义通过打开文件描述符删除文件的方法。这是有道理的,因为您所说的删除实际上是删除目录条目,而不是文件本身。同一个文件可以在多个位置以多个名称硬链接到目录树中。在从目录树中删除指向它的最后一个硬链接并且不再有任何进程打开它之后,操作系统会负责从存储中删除其数据,或者至少将其标记为可重复使用。

文件描述符与文件直接关联,而不是与任何特定路径关联,尽管在许多情况下,您可以通过路径获得一个。这有几个后果,其中一旦一个进程打开一个文件,就不能通过操作目录树从它下面拉出该文件。这是解决问题的标准方法之一的基础:在打开它后立即取消链接(删除)它,然后再失去它的名字。示例:

#include <stdlib.h>
#include <unistd.h>

int make_temp_file() {
    char filename[] = "my_temp_file_XXXXXX";
    int fd;

    fd = mkstemp(filename);
    if (fd == -1) {
        // handle failure to open ...
    } else {
        // file successfully opened, now unlink it
        int result = unlink(filename);
        // ... check for and handle error conditions ...
    }

    return fd;
}

这不仅(几乎)确保临时文件不会超过对它的需求,而且还可以防止拥有进程未明确授予访问权限的用户和进程访问内容。

【讨论】:

    【解决方案2】:

    尽管这不能完全回答您所询问的关于 mkstemp 的问题,但请考虑创建一个将自动删除的临时文件,除非您重命名它。

    您可以调用 open 和创建标志 O_TMPFILE 来代替 mkstemp 来创建一个临时的、未命名的文件,该文件在文件关闭时会自动删除。

    open(2):

    O_TMPFILE (since Linux 3.11)
        Create an unnamed temporary regular file.  The pathname argu‐
        ment specifies a directory; an unnamed inode will be created
        in that directory's filesystem.  Anything written to the
        resulting file will be lost when the last file descriptor is
        closed, unless the file is given a name.
    

    您可以使用您喜欢放置临时文件的路径调用 open,而不是文件名,例如:

    temp_fd = open("/path/to/dir", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
    

    如果您想给临时文件一个永久的位置/名称,您可以稍后致电linkat

    linkat(temp_fd, NULL, AT_FDCWD, "/path/for/file", AT_EMPTY_PATH);
    

    注意:O_TMPFILE 需要文件系统支持,但主流 Linux 文件系统确实支持。

    【讨论】:

    • 我不知道为什么它不识别O_TEMPFILE标志,也应该有什么东西而不是“AT_EMPTY_PATH”?
    • @John Well... s/e//
    【解决方案3】:

    readlink 如果您使用路径 /proc/self/fd/ 添加 fd,则根据文件描述符为您提供文件名。

    然后使用remove 删除传递名称readlink 给你的文件

    ssize_t readlink(const char *path, char *buf, size_t bufsiz);(同时加载ernno

    int remove(const char *filename);(成功返回零,否则非零)

    我希望这样的事情可以帮助你?


    ⚠ 请勿复制/粘贴此内容,您必须编辑“文件名”; _BUFFER, _BUFSIZE ⚠

    #include<stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    int delete_file(int fd) {
       char *str_fd = itoa(fd, str_fd, 10);
       char *path = strcat("/proc/self/fd/", str_fd);
       
       if (read_link(path, buffer, bufsize) == -1)
            return -1;
            
       int del = remove(filename);
       if (!del)
          printf("The file is Deleted successfully");
       else
          printf("The file is not Deleted");
       return 0;
    }
    

    (随意编辑,我没有测试代码,我让你处理缓冲区和缓冲区大小)

    【讨论】:

    • 应该有什么样的缓冲区?
    • 以下划线和大写字母开头的名称,如_BUFFER_BUFSIZE,是保留标识符,不应在您的代码中使用。见7.1.3 Reserved identifiers
    • @john 这是一个字符 *
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-15
    • 2010-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多