4.4 临时文件
很多情况下,程序会利用一些文件形式的临时存储手段。这些临时文件可能保存着一个计算的中间结果,也可能是关键操作前的文件备份。例如,一个数据库应用程序在删除记录时就可能使用临时文件。该文件收集需要保留的数据库条目,然后在处理结束后,这个临时文件就变成新的数据库,原来文件则被删除。
临时文件的这种用法很常见,但也有一个隐藏的缺点。你必须确保应用程序为临时文件选取的文件名是唯一的。否则,因为Linux是一个多任务系统,另一个程序就可能选择同样的文件名,从而导致两个程序互相干扰。
用tmpnam函数可以生成一个唯一的文件名:
tmpnam函数返回一个不与任何已存在文件同名的有效文件名。如果字符串s不为空,文件名也会写入它。对tmpnam的后续调用会覆盖存放返回值的静态存储区,所以如果tmpnam要被多次调用,就有必要给它传递一个字符串参数了。这个字符串的长度至少要有L_tmpnam(通常为20)个字符。tmpnam可以被一个程序最多调用TMP_MAX次(至少为几千次),每次它都会返回一个不同的文件名。
如果遇到需要立刻使用临时文件的情况,你可以用tmpfile函数在给它命名的同时打开它。这点非常重要,因为另一个程序可能会创建出一个与tmpnam返回的文件名同名的文件。tmpfile函数则完全避免了这个问题的发生:
tmpfile函数返回一个文件流指针,它指向一个唯一的临时文件。该文件以读写方式打开(通过w+方式的fopen),当对它的所有引用全部关闭时,该文件会被自动删除。
如果出错,tmpfile返回空指针并设置errno的值。
实验tmpnam和tmpfile
让我们来看看这两个函数的用法:
编译并运行程序tmpnam.c,你可以看到tmpnam生成的唯一文件名:
实验解析
这个程序调用tmpnam为临时文件生成一个唯一的文件名。如果要用它,你必须尽可能快地打开它以减小另一个程序用同样的名字打开文件的风险。tmpfile调用同时创建和打开一个临时文件,这样就避免了这一风险。事实上,当编译一个使用tmpnam函数的程序时,GNU C编译器会对它的使用给出警告信息。
UNIX有另一种生成临时文件名的方式,就是使用mktemp和mkstemp函数。Linux也支持这两个函数,它们与tmpnam类似,不同之处在于可以为临时文件名指定一个模板,模板可以让你对文件的存放位置和名字有更多的控制:
mktemp函数以给定的模板为基础创建一个唯一的文件名。template参数必须是一个以6个X字符结尾的字符串。mktemp函数用有效文件名字符的一个唯一组合来替换这些X字符。它返回一个指向生成的字符串的指针,如果不能生成一个唯一的名字,它就返回一个空指针。
mkstemp函数类似于tmpfile,它也是同时创建并打开一个临时文件。文件名的生成方法和mktemp一样,但是它的返回值是一个打开的、底层的文件描述符。
你应该在程序中使用“创建并打开”函数tmpfile和mkstemp,而不要使用tmpnam和mktemp。