#include <stdio.h> char *tmpnam(char *ptr); /* 返回值:指向唯一路径名的指针 */ FILE *tmpfile(void); /* 返回值:若成功,返回文件指针;否则,返回 NULL */
tmpnam 函数产生一个与现有文件名不同的一个有效路径名字符串,其最多调用次数由 <stdio.h> 中的 TMP_MAX 来指定。若 ptr 是 NULL,则产生的路径名存放在一个静态区中,指向该静态区的指针作为函数值返回。后续再调用 tmpname 时会重写该静态区,这意味着如果调用此函数多次,而且想保存路径名,则应该保存路径名的副本,而非指针的副本。若 ptr 不是 NULL,则认为它应该是指向至少 L_tmpnam(在 <stdio.h> 中)个字符的数组。注意,该函数在 SUSv4 中被标记为弃用,但 ISO C 标准仍继续支持。
tmpfile 创建一个临时二进制文件(类型为 wb+),在关闭该文件或程序结束时将自动删除这种文件。该函数经常使用的标准 UNIX 技术是先调用 tmpnam 产生一个唯一的路径名,然后再用该路径名创建一个文件,并立即 unlink 它。因为对一个文件解除链接并不删除其内容,要关闭该文件时才会,而关闭文件可以是显式的,也可以在程序终止时自动进行。
下列程序说明了这两个函数的应用。
#include <stdio.h> #include <stdlib.h> #define MAXLINE 4096 int main(void){ char name[L_tmpnam], line[MAXLINE]; FILE *fp; printf("%s\n", tmpnam(NULL)); // first temp name tmpnam(name); // second temp name printf("%s\n", name); if((fp=tmpfile()) == NULL){ printf("tmpfile error\n"); exit(1); } fputs("one line of output\n", fp); rewind(fp); // read ti back if(fgets(line, sizeof(line), fp) == NULL){ printf("fgets error\n"); exit(1); } fputs(line, stdout); exit(0); }
运行结果如下:
$ ./tempfileDemo.out /tmp/fileTOHsu6 /tmp/filekmAsYQ one line of output
Single UNIX Specification 扩展中为处理临时文件定义了下面另外两个函数,它们是 XSI 的扩展部分。
#include <stdlib.h> char *mkdtemp(char *template); /* 返回值:若成功,返回指向目录名的指针;否则,返回 NULL */ int mkstemp(char *template); /* 返回值:若成功,返回文件描述符;否则,返回 -1 */
mkdtemp 使用权限集“S_IRUSR|S_IWUSR|S_IXUSR”创建了一个具有唯一名字的目录。而 mkstemp 创建一个具有唯一名字的文件,并以权限集“S_IRUSR|S_IWUSR”打开该文件,另外也不会自动删除该文件。这两个函数都是通过 template 字符串来创建目录或文件的,该字符串是后 6 位设置为“XXXXXX”的路径名,函数将这些占位符替换成不同的字符串来构建一个唯一的路径名。如果成功,这两个函数都将修改 template 字符串以反映临时文件的名字。
mkstemp 函数使用示例:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <sys/stat.h> void make_temp(char *template); int main(void){ char good_template[] = "/tmp/dirXXXXXX"; // right way char *bad_tempfile = "/temp/dirXXXXXX"; // wrong way printf("trying to create first temp file...\n"); make_temp(good_template); printf("trying to create seconde temp file...\n"); make_temp(bad_tempfile); exit(0); } void make_temp(char *template){ int fd; struct stat sbuf; if((fd=mkstemp(template)) < 0){ printf("can't create temp file"); return; } printf("temp name = %s\n", template); close(fd); if(stat(template, &sbuf) < 0){ if(errno == ENOENT) printf("file doesn't exist\n"); else printf("stat failed\n"); }else{ printf("file exists\n"); unlink(template); } }
运行结果示例:
$ ./mkstempDemo.out trying to create first temp file... temp name = /tmp/dir0wPp4L file exists trying to create seconde temp file... 段错误 (core dumped) $
两个模板字符串声明方式的不同带来了不同的运行结果。因为第一个模板使用了数组,名字是在栈上分配的。但第二个使用了指针,此时只有指针自身驻留在栈上。编译器把字符串存放在可执行文件的只读段,当 mkstemp 函数试图修改该字符串时,就会出现段错误。