#include <stdio.h>
char*tmpnam(char*ptr);//返回指向唯一路径名的指针;
FILE*tmpfile(void);//成功则返回文件指针;失败返回NULL;
tmpnam
产生一个与现在文件名不同的一个有效路径名字符串。每次调用它时,它都产生一个不同的路径名,最多调用次数是
TMP_MAX
(
238328
)
。
TMP_MAX
定义在
<stdio.h>
中。
有时候在程序运行的时候,可能需要创建一个临时文件,保存一些数据,以后再用,在程序退出时希望这些文件能够被自动删除。而创建的时候有希望一次创建成功,不会覆盖可能重名的文件,这时需要使用临时文件。该函数的功能是产生一个唯一的文件名,结果存放在数组
sptr
中,该函数的主要用途是生成与目录中现有文件名不同的有效路径名字符串,其中
sptr
中保存了所产生的文件名。
若
ptr
是
NULL
,则所产生的路径名存放在一个静态区中,指向该静态区的指针作为函数值返回。下一次再调用
tmpnam
时,会重写该静态区。(
这意味着
,如果我们调用此函数多次,而且想保存路径名,则
我们应当保存该路径名的副本,而不是指针的副本
。)如若
ptr
是
NULL
,则认为它指向长度至少是
L_tmpnam
(
20
)
个字符的数组。(常数
L_tmpnam
定义在头文件
<stdio.h>
中。)所产生的路径名存放在该数组中,
ptr
也作为函数值返回。
tmpfile
创建一个临时二进制文件(类型
wb+
),在关闭该文件或程序结束时将自动删除这种文件。注意,
UNIX
对二进制文件不作特殊区分。
下述程序演示了两个函数的应用
#include <stdio.h>
#include <stdlib.h>
#define MAXLINE 1024
int main(void)
{
char name[L_tmpnam],line[MAXLINE];
FILE *fp;
printf("%s\n",tmpnam(NULL)); //first temp name
tmpnam(NULL); //second temp name
printf("%s\n",name);
if((fp = tmpfile()) == NULL) //create temp file
perror("tmpfile");
fputs("one line of output\n",fp); //write to temp file
rewind(fp); //then read it back
if(fgets(line,sizeof(line),fp) == NULL)
perror("fgets");
fputs(line,stdout); //print the line we write
exit(0);
}
该程序在编译的时候会有警告:
warning: the use of `tmpnam' is dangerous, better use `mkstemp'
。
`tmpnam' is dangerous,
原因:
l
Race conditions: tmpnam() generates a file name that is not in use at the moment of the call, but there's no guarantee that some other program might not create such a file two nanoseconds later, before you get a chance to use the name tmpnam() built for you.
l
Security holes: It's at least conceivable that the race condition mentioned above could be exploited as part of a penetration of privilege barriers.
l
Disk pollution: When you create a file using the name tmpnam() gave you, you must remember to remove() it when you're through (assuming you want it to be temporary). If your program crashes or is stopped by ^C or some such and you don't remove() the file, it will hang around on the disk and take up space. This could become troublesome, especially if the "temporary" files tend to be large.
l
mktemp() is dangerous, since it allows an attacker to guess names.
一个
mkstemp
的例子为
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(void)
{
FILE *pfile, *pfile2;
int fileSize, readSize;
char *fileBuff = NULL;
char buff[128] = { 0 };
char test[100] = "abcdefghijklmn";
/****************(1) tmpfile() *****************/
pfile2 = tmpfile();
if (pfile2 == NULL) {
fputs("creat temp file error", stderr);
exit(1);
}
if (EOF == fputs("tmpfile function create me !", pfile2)) {
fputs("write err.\n", stderr);
exit(1);
}
rewind(pfile2); // positions the stream stream at the beginning of the file
fgets(buff, sizeof(buff), pfile2);
puts(buff);
/********************(2) tmpnam() + unlink() *****************/
memset(buff, 0, sizeof(buff));
puts(tmpnam(buff));
/*************read or write file***************/
pfile = fopen(buff, "a+");
unlink(buff);
if (pfile == NULL) {
fputs("open error", stderr);
exit(1);
}
if (sizeof(test) !=
fwrite(test, sizeof(char),
sizeof(test) / sizeof(char), pfile)) {
fputs("write error", stderr);
exit(1);
}
//get the file size
fseek(pfile, 0, SEEK_END);
fileSize = ftell(pfile);
rewind(pfile);
printf("filesize:%d\n", fileSize);
fileBuff = (char *) malloc(sizeof(char) * fileSize);
if (fileSize !=
(readSize = fread(fileBuff, sizeof(char), fileSize, pfile))) {
fputs("Read error", stderr);
exit(3);
} else {
printf("readContent: %s \nreadsize:%d\n", fileBuff,
readSize);
}
fclose(pfile);
free(fileBuff);
/********************(3) fopen() and unlink() **************/
pfile = NULL;
pfile = fopen("/tmp/tempA.txt", "w+");
if (pfile == NULL) {
fputs("create file failed.", stderr);
exit(1);
}
fputs("fopen create me", pfile);
rewind(pfile);
if (fgets(buff, sizeof(buff), pfile) == NULL) {
fputs("read file error.\n", stderr);
exit(1);
}
fputs(buff, stdout);
fclose(pfile);
unlink("/tmp/tempA.txt");
puts("\nDONE.......\n");
return EXIT_SUCCESS;
}
关于
mkstemp
函数
int mkstemp(char *template);
mkstemp
函数在系统中以唯一的文件名创建一个文件并打开,而且
只有当前用户才能访问这个临时文件,并进行读、写操作
(这个就确保文件比较安全)。
建立唯一临时文件名
, template
须以数组形式声明而非指针形式
.
template
格式为
: template.XXXXXX.
最后
6
位必须为
XXXXXX,
前缀随意
函数返回一个文件描述符,如果执行失败返回
-1
。
在
glibc 2.0.6
以及更早的
glibc
库中这个文件的访问权限是
0666
,
glibc 2.0.7
以后的库这个文件的访问权限是
0600
。
由于
mkstemp
函数创建的临时文件不能自动删除,所以
执行完
mkstemp
函数后要调用
unlink
函数
,
unlink
函数删除文件的目录入口,但临时文件还可以通过文件描述符进行访问,直到最后一个打开的进程关闭文件操作符,或者程序退出后临时文件被自动彻底地删除。
下面是一个使用
mkstemp
的例子:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int fd;
char temp_file[] = "tmp_XXXXXX";
/*Creat a temp file.*/
if ((fd = mkstemp(temp_file)) == -1) {
printf("Creat temp file faile./n");
exit(1);
}
/*Unlink the temp file.*/
unlink(temp_file);
close(fd);
}
tmpfile
函数经常使用的标准
UNIX
技术是先调用
tmpnam
产生一个唯一的路径名,然后立即
unlink
它。
Single UNIX Specification
为处理临时文件定义了另外两个函数,它们是
XSI
的扩展部分,其中第一个是
tempnam
函数:
#include <stdio.h>
char* tempnam(const char*directory, const char*prefix);
返回值为指向唯一路径名的指针;
tempnam
是
tmpnam
的一个变体,它允许调用者为所产生的路径名指定目录和前缀。对于目录有四种不同的选择,按下列顺序判断条件是否为真,并且使用第一个为真的作为目录:
(1)
如果定义了环境变量
TMPDIR
,则用其作为目录。
(2)
如果参数
directory
非
NULL
,则用其作为目录。
(3)
将
<stdio.h>
中的字符串
P_tmpdir
用作为目录。
(4)
将本地目录,通常是
/tmp,
用作为目录。
如果
prefix
非
NULL
,则它应该是最多包含
5
个字符的字符串,用其作为文件名的头几个字符。该函数调用
malloc
函数分配动态存储区,用其存放所构造的路径名。当不再使用此路径名时就可释放此存储区。
tempnam
函数的应用
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
if (argc != 3)
perror("usage : a.out <directory> <prefix>");
printf("%s\n",
tempnam(argv[1][0] != ' ' ? argv[1] : NULL,
argv[2][0] != ' ' ? argv[2] : NULL));
exit(0);
}
XSI
定义的第二个函数是
mkstemp
。它类似于
tmpfile
,但是该函数返回的不是文件指针,而是临时文件的打开文件描述符。
#include <stdlib.h>
int mkstemp(char* template);
返回值:成功返回文件描述符,失败返回
-1
;
它所返回的文件描述符可用于读、写该文件。临时文件的名字是用
template
字符串参数选择的。该字符串是一个路径名,其最后
6
个字符设置为
XXXXXX
。该函数用不同字符代替
XXXXXX
,以创建一个唯一路径名。若
mkstemp
成功返回,它就会修改
template
字符串以反映临时文件的名字。
与
tmpfile
不同的是,
mkstemp
创建的临时文件不会自动删除,它需要我们自行
unlink
。
使用
tmpfile
和
tempnam
的不足之处
:在返回唯一路径名和应用程序用该路径名创建文件之间有一个时间窗口。
在该时间窗口期间,另一个进程可能创建一个同名文件。
tmpfile
和
mkstemp
函数则不会产生此种问题。可以使用它们代替
tmpnam
和
tempname
。