创建临时文件——tmpnam,tmpfile,mktemp,mkstemp

本文介绍了几种创建唯一临时文件的方法,包括使用tmpfile、tmpnam、mktemp和mkstemp等函数。通过示例代码展示了如何正确使用这些函数来创建临时文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

创建名字唯一的临时文件:推荐使用tmpfile和mkstemp,因为这两个函数创建文件的同时并打开文件,总的来说安全又可靠。tmpfile返回的是文件流指针FILE*,mkstemp返回的是文件描述符。 

 

tmpnam,tmpfile


表头文件 #include <stdio.h>

函数定义 FILE *tmpfile(void);

函数描述 创建唯一的临时文件,并打开文件

返回值  成功返回文件流,失败返回NULL

 

表头文件 #include <stdio.h>

函数定义 char *tmpnam(char *s);

函数描述 创建唯一的临时文件

返回值  成功返回文件名字指针,失败返回NULL


#include <stdio.h>
#include <stdlib.h>

int main()
{
    char tmpname[L_tmpnam];
    char *filename;
    FILE *tmpfp;

   
    if((filename = tmpnam(tmpname)) != NULL)    //方式一:不推荐使用
    {
     printf("Temporary file name is: %s\n", filename);
        printf("Temporary  tmpnam   is: %s\n", tmpname);//在一次打开中filename 与 tmpnam相同
   
        open(tmpname);
        perror("open");

        open(filename);
        perror("open");
    }

    tmpfp = tmpfile();  //方式二:推荐使用
    if(tmpfp)
        printf("Opened a temporary file OK\n");
    else
        perror("tmpfile");
 
    exit(0);
}

 

mktemp

用法与tmpnam差不多,只是名字部分可以由template确定,template后面六个字符必须为X,例如tmpXXXXXX


示例:

#include <stdlib.h>
#include <stdio.h>
//char *mktemp(char *template);

int main(int argc,char *argv[])
{
        char filename[] = "temp-XXXXXX";
        char *name;
        if((name = mktemp(filename)) == NULL)
        {
                perror("mktemp");
                exit(1);
        }

        printf("name:%s,filename:%s\n",name,filename);
        exit(0);
}

mkstemp(建立唯一的临时文件) 

 相关函数 mktemp 
 表头文件 #include<stdlib.h> 
 定义函数 int mkstemp(char * template); 
 函数说明 mkstemp()用来建立唯一的临时文件。参数template 所指的文件名
          称字符串中最后六个字符必须是XXXXXX。Mkstemp()会以可读写模式
           和0600 权限来打开该文件,如果该文件不存在则会建立该文件。打
           开该文件后其文件描述词会返回。文件顺利打开后返回可读写的文
件描述词。

若果文件打开失败则返回NULL,并把错误代码存在errno中。 

 错误代码 EINVAL 参数template 字符串最后六个字符非XXXXXX。EEXIST 无法
           建立临时文件。 
 附加说明 参数template所指的文件名称字符串必须声明为数组,如: 
           char template[ ] =”template-XXXXXX”; 
           千万不可以使用下列的表达方式 
           char *template = “template-XXXXXX”;

与mktemp函数区别:mkstemp返回值为文件描述符,mktemp返回值为文件名指针。

 

示例:

#include <stdlib.h>

int main(int argc,char *argv[])
{
        int fd;
        char tmpfile[] = "temp-XXXXXX";

        if((fd = mkstemp(tmpfile))< 0)
        {
                perror("mkstemp");
                exit(1);
        }

        close(fd);
        exit(0);
}


http://blog.sina.com.cn/s/blog_63009a040100snyv.html


<think>我们面对的问题是如何在文件头部插入文本。在C语言中,使用标准库函数`write`(来自`unistd.h`)通常用于向文件描述符写入数据,但它并不直接支持在文件开头插入数据。这是因为文件在大多数操作系统中被视为字节流,插入操作需要移动现有数据。 然而,我们可以通过以下步骤实现: 1. 创建一个临时文件。 2. 将新内容写入临时文件。 3. 打开原文件,读取其内容,并将内容追加到临时文件中。 4. 用临时文件替换原文件。 但是,这种方法会重写整个文件。如果文件很大,效率可能较低。另一种方法是使用内存映射(mmap)来操作文件,但对于大文件可能受限于内存。 另外,我们也可以考虑将原文件内容读入内存,然后重新写入文件(先写新内容,再写原内容)。但同样,对于大文件,内存可能不足。 因此,我们根据文件大小选择不同的策略。 不过,用户要求使用`write`函数。我们需要注意的是,`write`函数是低层次的I/O,通常用于向文件描述符写入数据,且写入位置由文件偏移量决定。我们可以通过`lseek`函数调整偏移量,但插入操作需要移动后面的所有数据。 实际上,在文件开头插入文本的标准做法是: 1. 读取整个文件到内存(如果文件不大)。 2. 在内存中构建新内容(新文本+原内容)。 3. 将整个新内容写回文件。 如果文件很大,我们可以使用临时文件: 1. 打开原文件(用于读)。 2. 创建一个新的临时文件(用于写)。 3. 将新文本写入临时文件。 4. 将原文件的内容复制到临时文件。 5. 关闭文件,并将临时文件重命名为原文件。 下面我们使用第二种方法(临时文件)来实现,因为这样可以处理大文件(通过流式读写,避免一次性读入内存)。 步骤: 1. 打开原文件(读模式)。 2. 创建一个临时文件(写模式)。 3. 将需要插入的文本写入临时文件。 4. 从原文件读取数据,写入临时文件,直到结束。 5. 关闭两个文件。 6. 删除原文件,将临时文件重命名为原文件。 注意:在WindowsLinux下,创建临时文件重命名的函数可能不同。这里我们使用标准C库函数,以保持可移植性。 但是,标准C库没有直接提供创建临时文件并确保唯一性的安全函数?我们可以使用`tmpfile`函数,但是`tmpfile`创建临时文件在关闭后会自动删除,所以我们需要使用`tmpnam`或`mkstemp`(Linux)等,然后使用`rename`函数重命名。 考虑到跨平台,我们可以这样做: - 在Linux下,可以使用`mkstemp`创建临时文件,然后使用`rename`替换原文件。 - 在Windows下,可以使用`tmpfile`创建临时文件,但注意`tmpfile`创建临时文件在程序结束时会自动删除,所以我们需要在程序运行期间完成操作,然后使用`rename`(在Windows下,如果目标文件存在,`rename`可能失败,需要先删除原文件)。 另一种更简单的方法是:我们不需要使用系统临时文件,而是自己生成一个临时文件名(比如在原文件名后加后缀),然后写入,最后替换。 这里我们使用自定义临时文件名的方法,并注意错误处理。 具体步骤: 1. 生成临时文件名(例如,在原文件名前加一个点,或者后缀为.tmp)。 2. 打开原文件(读模式)。 3. 打开临时文件(写模式)。 4. 写入新内容到临时文件。 5. 从原文件读取内容,写入临时文件(使用缓冲区,避免大文件一次读入内存)。 6. 关闭两个文件。 7. 删除原文件(使用`remove`函数)。 8. 将临时文件重命名为原文件名(使用`rename`函数)。 注意:在Windows下,删除原文件可能会失败,如果原文件被其他进程打开,所以需要确保文件已经关闭。 下面我们写一个函数来实现这个功能: 函数原型: int insert_text_at_head(const char *filename, const char *text); 返回值:成功返回0,失败返回-1。 由于用户要求使用`write`函数,但我们这里使用标准C库的`fopen`、`fwrite`等,因为更便于文本操作(且用户没有指定必须用低级I/O)。如果用户坚持使用低级I/O(即文件描述符),我们可以用`open`、`read`、`write`等函数,步骤类似。 不过,用户的问题中提到了`write`函数,所以我们也可以使用低级I/O来实现。 下面分别给出两种方法: 方法一:使用标准I/O(fopen系列) 方法二:使用低级I/O(open、write、read等) 由于用户要求使用`write`,我们使用方法二。 低级I/O实现步骤(使用POSIX函数,在LinuxWindows的兼容性需要注意,Windows下也有类似的API,但这里我们假设在POSIX环境): 1. 打开原文件:`fd_old = open(filename, O_RDONLY);` 2. 创建临时文件:可以使用`tmpnam`生成临时文件名,然后使用`open`创建,但注意`tmpnam`不安全,推荐使用`mkstemp`(Linux)或`_mktemp_s`(Windows)。这里我们使用`mkstemp`(注意:`mkstemp`会创建文件并返回文件描述符,所以可以直接使用)。 3. 将新内容写入临时文件:`write(fd_new, text, strlen(text));` 4. 循环读取原文件内容并写入临时文件:使用一个缓冲区,反复调用`read``write`。 5. 关闭文件:`close(fd_old); close(fd_new);` 6. 删除原文件:`unlink(filename);` 7. 重命名临时文件:`rename(temp_filename, filename);` 但是,临时文件名由`mkstemp`生成,我们需要记住它。 注意:在Windows下,重命名时如果目标文件存在,可能需要先删除,而Linux的`rename`可以直接覆盖(如果目标存在)。为了跨平台,我们可以先删除原文件再重命名,或者使用相应的Windows API。 由于用户没有指定平台,我们以Linux环境为例。 代码示例(Linux环境): ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> int insert_text_at_head(const char *filename, const char *text) { int fd_old = open(filename, O_RDONLY); if (fd_old < 0) { perror("Failed to open source file"); return -1; } // 创建临时文件 char temp_filename[] = "/tmp/tempfileXXXXXX"; // 模板 int fd_new = mkstemp(temp_filename); if (fd_new < 0) { perror("Failed to create temporary file"); close(fd_old); return -1; } // 写入新内容 ssize_t text_len = strlen(text); if (write(fd_new, text, text_len) != text_len) { perror("Failed to write text to temporary file"); close(fd_old); close(fd_new); unlink(temp_filename); // 删除临时文件 return -1; } // 复制原文件内容到临时文件 char buffer[4096]; ssize_t n; while ((n = read(fd_old, buffer, sizeof(buffer))) > 0) { if (write(fd_new, buffer, n) != n) { perror("Failed to write to temporary file"); close(fd_old); close(fd_new); unlink(temp_filename); return -1; } } if (n < 0) { perror("Failed to read from source file"); close(fd_old); close(fd_new); unlink(temp_filename); return -1; } // 关闭文件 close(fd_old); if (close(fd_new) != 0) { perror("Failed to close temporary file"); unlink(temp_filename); return -1; } // 删除原文件 if (unlink(filename) != 0) { perror("Failed to remove original file"); unlink(temp_filename); return -1; } // 重命名临时文件 if (rename(temp_filename, filename) != 0) { perror("Failed to rename temporary file"); unlink(temp_filename); return -1; } return 0; } ``` 注意:这个函数在Linux下可以工作,但在Windows下,`unlink``rename`的行为可能不同,且`mkstemp`是POSIX函数,Windows下没有。在Windows下,我们可以使用`_mktemp_s``_open`,以及`_unlink``_rename`。 如果需要在Windows下使用,我们可以使用条件编译。 另外,我们也可以考虑使用标准C库的`tmpfile`函数,但`tmpfile`返回的是文件指针(FILE*),并且临时文件在程序结束时会自动删除,所以我们需要在程序运行期间完成重命名,但`tmpfile`创建临时文件没有名字,所以不能使用`rename`。因此,我们这里使用`mkstemp`(仅适用于POSIX系统)。 由于用户没有指定平台,我们给出一个适用于Linux的版本。如果用户需要在Windows下使用,可能需要修改。 另外,我们也可以不使用临时文件,而是将原文件内容读入内存,然后重写整个文件(先写新文本,再写原内容)。但这种方法对于大文件不太友好。 总结:在文件头部插入文本,没有直接的系统调用支持,通常需要重写文件。我们使用临时文件来避免内存不足的问题。 如果用户希望避免创建临时文件,也可以尝试使用内存映射(mmap)来操作文件,但这需要文件大小不超过内存可用空间(或者映射部分文件),而且实现起来更复杂。 因此,我们推荐使用临时文件的方法。 注意:在写入新内容后,我们复制了原文件的所有内容,所以新文件的内容是:新文本+原文件内容。 最后,我们提醒用户,这个操作在文件很大时可能会比较慢,因为需要复制整个文件。 相关问题: 1. 如何在文件中间插入文本? 2. 如何高效地在文件头部插入数据(避免复制整个文件)? 3. 在Windows下如何使用C语言实现文件头部插入文本? 4. 使用内存映射(mmap)在文件头部插入文本的方法是什么?</think>在C语言中,使用`write`函数在文件开头插入文本需要特殊处理,因为文件系统通常不支持直接插入操作。以下是两种常用方法及其实现原理: ### 方法1:临时文件法(推荐) ```c #include <fcntl.h> #include <unistd.h> int insert_text_at_head(const char* filename, const char* text) { // 创建临时文件 char tmp_name[] = "/tmp/tempfileXXXXXX"; int fd_tmp = mkstemp(tmp_name); if (fd_tmp == -1) return -1; // 写入新文本 ssize_t len = strlen(text); if (write(fd_tmp, text, len) != len) { close(fd_tmp); unlink(tmp_name); return -1; } // 复制原文件内容 int fd_orig = open(filename, O_RDONLY); if (fd_orig == -1) { close(fd_tmp); unlink(tmp_name); return -1; } char buf[4096]; ssize_t bytes; while ((bytes = read(fd_orig, buf, sizeof(buf))) > 0) { if (write(fd_tmp, buf, bytes) != bytes) { close(fd_orig); close(fd_tmp); unlink(tmp_name); return -1; } } // 替换原文件 close(fd_orig); close(fd_tmp); unlink(filename); // 删除原文件 return rename(tmp_name, filename); // 重命名临时文件 } ``` ### 方法2:内存缓冲法(适合小文件) ```c #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int insert_text_at_head(const char* filename, const char* text) { // 读取原文件内容 struct stat st; if (stat(filename, &st) == -1) return -1; char* content = malloc(st.st_size + 1); int fd = open(filename, O_RDONLY); if (fd == -1 || read(fd, content, st.st_size) != st.st_size) { free(content); close(fd); return -1; } close(fd); // 重新打开文件写入 fd = open(filename, O_WRONLY | O_TRUNC); if (fd == -1) { free(content); return -1; } ssize_t len = strlen(text); if (write(fd, text, len) != len || write(fd, content, st.st_size) != st.st_size) { free(content); close(fd); return -1; } free(content); close(fd); return 0; } ``` ### 关键原理 1. **文件系统限制**:传统文件系统只支持尾部追加或覆盖,不支持直接插入操作[^1] 2. **临时文件法**: - 创建临时文件 - 先写入新文本 - 追加原文件内容 - 原子替换原文件(`rename`系统调用) 3. **内存缓冲法**: - 将整个文件读入内存 - 清空原文件后写入新内容+原内容 - 仅适用于小文件(内存限制) ### 注意事项 - 使用`O_TRUNC`标志清空文件内容 - `rename()`是原子操作,避免数据损坏风险 - 大文件优先用临时文件法(避免内存耗尽) - 需要错误处理确保文件完整性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值