是否应该将临时文件保存到/ tmp或当前工作目录?


76

我有一个需要生成临时文件的程序。它是为集群计算机编写的。

如果我将这些文件保存到系统范围的临时目录(例如:)/tmp,则一些用户抱怨该程序失败,因为他们没有对/ tmp的正确访问权限。但是,如果我将这些文件保存到工作目录中,这些用户还抱怨说,他们不想看到那些神秘的文件。

哪个是更好的做法?我是否应该坚持认为保存/tmp是正确的方法,并以“按预期方式工作”来捍卫任何失败(例如,请问您的管理员适当的许可/访问权)?


3
检查程序是否具有访问权限,以及是否找不到另一个临时目录
棘手怪胎

24
如果您的管理员搞砸了访问权限,他肯定应该修复它。如果管理员忘记为程序添加执行权限,该怎么办?
布朗

7
在大多数Windows系统上都找不到/ tmp,但是有一个OS调用会告诉您将临时文件放在哪里。
伊恩

28
如果某些人无法访问/tmp类Unix系统,则会配置错误。超级用户应执行类似的操作chmod 1777 /tmp
musiphil '16

12
请注意,$ TMPDIR可能指向的路径不同于/tmp/,您应该使用。查看一些答案;)
marcelm '16

Answers:


141

出于以下几个原因,临时文件必须存储在操作系统的临时目录中:

  • 操作系统使创建这些文件变得非常容易,同时确保它们的名称是唯一的

  • 大多数备份软件都知道包含临时文件的目录是什么,并跳过它们。如果使用当前目录,那么如果频繁进行备份,则它可能会对增量备份的大小产生重要影响。

  • 临时目录可能位于其他磁盘上,也可能位于RAM中,从而使读写访问快得多

  • 临时文件通常在重新引导过程中被删除(如果它们位于ramdisk中,则只会丢失)。如果您的应用并非总是正确地删除临时文件(例如,崩溃后),则可以降低无限增长的风险。

    如果将临时文件与应用程序和用户文件一起存储,则从工作目录中清除临时文件很容易变得混乱。您可以通过在当前目录中创建一个单独的目录来缓解此问题,但这可能会导致另一个问题:

  • 在某些平台上,路径长度可能太长。例如,在Windows上,某些API,框架和应用程序的路径限制非常糟糕,这意味着如果当前目录已经在树层次结构中很深并且临时文件的名称太长,则可以轻松达到此限制。

  • 在服务器上,通常会立即监视临时目录的增长。如果使用其他目录,则可能无法对其进行监视,因此监视整个磁盘将无助于轻松地确定临时文件所占的位置越来越多。

至于拒绝访问错误,请确保让操作系统为您创建一个临时文件。例如,操作系统可能知道,对于给定的用户,应使用除/tmpC:\Windows\temp应使用的目录以外的目录;因此,通过直接访问这些目录,您确实可能会遇到拒绝访问错误。

如果即使在使用操作系统调用时您都拒绝访问,那也就意味着这台机器配置错误。Blrfl已经对此进行了解释。由系统管理员来配置机器。您不必更改应用程序。

创建临时文件在许多语言中都很简单。一些例子:

  • 重击:

    # The next line will create a temporary file and return its path.
    path="$(mktemp)"
    echo "Hello, World!" > "$path"
    
  • 蟒蛇:

    import tempfile
    
    # Creates a file and returns a tuple containing both the handle and the path.
    handle, path = tempfile.mkstemp()
    with open(handle, "w") as f:
        f.write("Hello, World!");
    
  • C#:

    // Creates a file and returns the path.
    var path = Path.GetTempFileName();
    File.WriteAllText(path, "Hello, World!");
    
  • PHP:

    # Creates a file and returns the handle.
    $temp = tmpfile();
    fwrite($temp, "Hello, World!");
    fclose($temp);
    
  • 红宝石:

    require "tempfile"
    
    # Creates a file and returns the file object.
    file = Tempfile.new ""
    file << "Hello, World!"
    file.close
    

请注意,在某些情况下,例如在PHP和Ruby中,关闭句柄时会删除文件。这是使用与语言/框架捆绑在一起的库的另一个好处。


2
您的意思是“确保让操作系统为您创建一个临时文件”。因此,而不是例如fopen("/tmp/mytmpfile", "w");我应该进行一些系统调用来处理临时文件?
simon

30
@gurka:您应该调用tmpfile(3)来生成临时文件,或者至少调用mktemp(3)来创建文件名。
TMN

3
@TMN:它们只是在用户空间中运行的库函数,它们没有任何魔术可以绕过操作系统给出的权限错误。
musiphil

25
@musiphil tmpfile和mktemp都使用外部变量来确定临时文件的路径。这些目录可能已设置为指向/ tmp /以外的其他目录,也许是每个用户的目录。尝试在/ tmp /中手动创建文件名可能会失败,而tmpfile和mktemp将返回有效路径。
管道

2
@musiphil:我从来没有说过要解决权限问题,我是在回答他有关使用系统调用来创建文件的问题。
TMN 2016年

33

我是否应该坚持保存到/ tmp是正确的方法,并为任何失败辩护为“按预期工作”(即,请您的管理员进行适当的权限访问)?

有标准,并且您能做的最好就是遵守它们。

POSIX(几乎所有可能具有任何重要意义的每个非大型机操作系统都紧随其后)提供了使用默认值在目录中创建名称唯一的临时文件的规定,这些默认值可以由环境重新配置:

  • C stdio.h标头可以选择包含一个P_tmpdir宏,该宏为系统的临时目录命名。
  • TMPDIR是用于更改临时文件位置的规范环境变量。在POSIX之前,还使用了其他变量,因此我倾向于使用第一个或TMPTEMPDIR并且TEMP该变量具有一个值,如果不存在这些变量,则使用系统默认值即可。
  • mkstemp()tempfile()功能将产生唯一的临时文件。

如果您的用户被拒绝创建临时文件的能力,则说明系统配置错误或管理员没有明确说明他们在此类事情上的政策。在这些情况下,您会非常坚定地说您的程序符合公认的可移植性标准,并且可以使用标准指定的环境变量来更改其行为。


P_tmpdir不是stdio.hC语言规范所定义的一部分。它可能由POSIX或SVID定义。
musiphil '16

1
@musiphil :(已澄清)答案暗示,它是POSIX的一部分。(在技术上,它是POSIX并入的X /开启系统扩展见。pubs.opengroup.org/onlinepubs/009695399/basedefs/stdio.h.html。
Blrfl

完全同意以上所有内容。一个很好的例子是Linux系统,它具有pam_tmpdir-这个设置,TMPDIR并且TMP对于每个用户来说都是不同的,以确保健壮性和私密性。能够TMPDIR为单个命令设置也是有用的-如果为了提高速度在RAM文件系统中具有通常的临时目录,则可能需要对生成大量临时文件(例如,巨人sort)的命令执行此操作。不要忽视用户期望的标准/惯例!
Toby Speight

绝对检查环境中临时文件的位置,而不要硬编码/ tmp。因为共享的tmp存在安全问题,所以我经常看到的一种缓解方法是创建每个用户的/ tmp目录,并且没有其他任何人的读写权限。它消除了可能的竞争条件和符号链接攻击。
Zan Lynx

9

临时文件目录高度依赖于操作系统/环境。例如,出于安全原因,web-servers-temp目录与os-temp-dir是分开的。

在ms-windows下,每个用户都有自己的temp-dir。

如果可以使用此功能,则应为此使用createTempFile()


1
请注意Windows中隐藏的OS限制。我们发现很难将文件夹中文件的最大数量限制为65565。当然,这是一个很大的文件,并且确信,你永远不应该可以想象有很多周围铺设。但是,您确定每个应用程序都会及时且行为良好地进行清理吗?
Mike Hofer

啊,我看你的评论太晚了。我只是在上面写了同样的东西。顺便说一句,该限制主要是由于GetTimeFileName()函数的机制而不是NTFS引起的。您提到的文件夹限制仅适用于FAT32
JensG '16

9

先前的答案虽然正确,但不适用于大多数大型计算机集群。

通常,出于良好的原因,计算机集群并非总是遵循计算机的标准约定,因此与sysadmins讨论它没有意义。

您当前的目录是指通过网络访问的中央文件系统。这不仅很慢,而且还会给其余用户带来系统负载,因此,除非您写得不多,否则您不应该使用它,如果作业崩溃,您可以从中恢复。

计算节点具有自己的硬盘驱动器,这是可用的最快的文件系统,并且应该使用什么。集群文件应该告诉你它是什么,典型的/scratch/tmp/[jobid]或者一些非标准的环境变量($SNIC_TMP在我经常使用的一个)。

因此,我建议使它成为用户可配置的。默认值可以是您拥有写权限的第一个:

  • $TMPDIR
  • tmpfile
  • /tmp
  • .

但是,这种方法的成功率会很低,并确保发出严重警告。

编辑:我将添加另一个原因来强制它是用户设置的。我的集群之一已$TMPDIR设置为/scratch,用户可写并且位于本地硬盘驱动器上。但是,文档说,您在外部编写的所有内容都/scratch/[jobid]可能在任何时候被删除,即使在运行过程中也是如此。因此,如果您遵循标准并信任$TMPDIR,您将遇到随机崩溃,很难调试。因此,您可以接受$TMPDIR,但不信任它。

其他一些集群确实已正确配置了此变量,因此您可以添加一个选项以显式信任$TMPDIR,否则,将发出严重警告。


1
先前的答案到底是哪一个?
TulainsCórdova'16

2
因此,您在这里要说的是,因为某些集群没有采取微不足道的步骤,即遵循一个公认的标准来告诉程序将临时文件写入何处,所以这是每个程序需要进行的另一项特定于集群的自定义。如果你问我,那茶就很弱。
Blrfl

@Blrfl,您可以随意更改标准,并编写完全符合标准的代码,并且总是崩溃;您可以尝试与使用的每个群集的系统管理员进行斗争;或者您可以接受自己的信念并使之可配置。另外,在HPC中,通常无论如何都需要使代码适应集群的具体要求(可用RAM,文件系统的相对速度,MPI实现,资源的一般可用性...),没有“一刀切”的选择。
Davidmh '16

@Davidmh:理解了,但不是重点。该标准使其能够以非惊人的方式进行配置。如果我将符合标准的代码带到未遵循标准的集群中,则必须将其设置在一个确切的位置,例如在入口点。在其余的代码中,审核,修改和冒错的风险少了一点。
Blrfl '16

1

对于许多应用程序,应考虑将临时文件放入$XDG_RUNTIME_DIR$XDG_CACHE_HOME(其他XDG目录用于非临时文件)。有关在环境中未明确传递它们的情况下有关计算它们的说明,请参见基于XDG的规范或查找已经实现该部分的库。

但是请注意,这$XDG_RUNTIME_DIR是新增功能,由于安全方面的考虑,较旧的系统没有标准的备用。

如果这些都不适合,那么/tmp正确的地方是。您永远不要以为当前目录是可写的。


-2

这更像是一种替代方法,但是您可以在fopen()之后立即取消链接()文件。它取决于库的使用模式。

如果可以的话,取消链接文件有以下几种帮助:

  • 看不到文件-用户看不到。
  • 从其他进程看不到文件-其他进程没有机会错误地修改文件。
  • 如果程序崩溃,很容易清理。

必须在/ tmp中创建文件。如果用户无权在此处创建文件,则表示系统配置错误。

无法在用户主目录中创建文件。许多用户,例如“ nobody”,“ www-data”和许多其他用户,无权在其主目录中编写,或者甚至是chroot()-ed。请注意,即使在chroot环境中,/ tmp仍然存在。


虽然这可能是一般的好主意,它并不能帮助缺乏谁的目录写权限的文件中的用户是被创造。
5gon12eder

4
它还没有回答问题,即在哪里放置临时文件。
Blrfl

我相信我的回答在某种程度上很重要。我做了编辑,也许这样更清晰。
尼克
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.