如果您有一个在单个函数范围内出于某种目的临时创建的文件,并且其删除被推迟到函数结束时,那么您是否应该在删除临时文件之前关闭该临时文件,或者确实释放os.Remove()所有临时文件相关资源?
func foo() error {
tempFile, err := os.Create(filePath)
if err != nil {
return err
}
defer func() {
/* Is this necessary?
if err = tempFile.Close(); err != nil {
log.Error(err)
return
}
*/
if err = os.Remove(filePath); err != nil {
log.Error(err)
}
}()
// do something
return nil
}
Run Code Online (Sandbox Code Playgroud)
\n\n您应该在删除临时文件之前关闭它还是确实
\nos.Remove()处理它?
“这取决于”。
\n首先,os.Remove()是文件系统级别的操作;它修改文件系统上的目录条目,并且不知道要删除的文件在调用它的进程中可能有多少个打开的文件描述符。
\n是的,您可以多次打开同一个文件\xe2\x80\ x94this 仅受系统强加的限制的限制。
还要考虑到,在相当现代的文件系统上,存在“链接”的概念(NTFS 可能会以不同的方式称呼它们,上次我检查它们有几个概念,即您在类 Unix 上称为“指向目录的符号链接”)系统),因此,您可能会通过不同的路径名打开物理上相同的文件,并对os.Remove路径名进行操作。
除此之外,文件系统是一个活动对象:在文件系统上的某个路径名打开文件的时间和您要使用该路径名删除文件的时间之间,该路径名甚至可能不再存在(但请继续阅读)。
\n这应该向您保证,不会,os.Remove不会尝试查找并关闭os.File已知引用同一文件的所有实例。
其次,类 Unix 系统和 Windows 之间打开文件的处理行为存在巨大差异;POSIX兼容的文件系统需要将系统中任何进程中访问特定文件系统的任何打开的文件视为对该文件的实时引用。
\n文档中可能无法立即清楚这一点,但close(2)系统调用参考手册中对此进行了记录:
\n\n如果文件的链接计数为0,则当与该文件关联的所有文件描述符都关闭时,该文件占用的空间将被释放,并且该文件将不再可访问。
\n
基本上,这意味着即使引用文件系统上特定文件的所有路径名都被删除(因此该文件无法通过文件系统访问),其数据仍然在文件系统上,直到打开该文件的最后一个文件描述符在运行中关闭。过程。
\n这种“技巧”经常在 Unix 专用软件中用于存储临时数据:
\nmktemp(2)在 Go 中通常使用 ; io/ioutil.TempFile)。这在 Windows 上不起作用:在那里,不可能删除打开的文件,并且在某些情况下甚至不可能重命名它,因此上面的“技巧”不起作用。
\n那么,让我们用新知识重新考虑原来的问题。
\n最安全的选择可能是编写一个简单的帮助程序来清理临时文件,如下所示
\nfunc removeTempFile(fd *os.File) {\n for _, err := range [...]error{fd.Close(), os.Remove(fd.Name())} {\n if err != nil {\n log.Print("failed to remove temp file: ", err)\n // Note that we merely log errors, not blow up on them -\n // this is to report both errors if all operations have failed.\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n然后在defer removeTempFile(fd)打开每个新的临时文件后粘贴\n。
如果您确定您的程序只能在 Unix 兼容系统(基于 Linux 和 *BSD、Mac OS 等)上运行,您可以立即删除临时文件并仅推迟关闭它。
\n请注意,如果您实际上需要\n通过名称引用该文件\xe2\x80\x94,这显然不起作用,例如,您将其传递给正在执行的某个外部程序。
\n| 归档时间: |
|
| 查看次数: |
2272 次 |
| 最近记录: |