我想在 Golang 中生成带有扩展名的唯一文件名。 非常类似于ioutil。临时文件,仅接受前缀。
这在论坛 https://groups.google.com/forum/#!topic/golang-nuts/PHgye3Hm2_0 中被多次提出,Go似乎非常打算不将该功能添加到TempFile中。
那么建议的处理方法是什么? 我应该只复制/粘贴 TempFile 代码并添加后缀参数吗?
更新(2020:原始答案来自 2015 年)
正如Lax的回答中所指出的,Go 1.11(2018年4月)已将前缀TempFile
更改为模式。
请参阅问题 4896 之后从 CL 105675 提交 191efbc
TempFile
用户需要能够提供后缀,尤其是 当使用赋予语义意义的操作系统时 文件扩展名,例如视窗。
重命名文件以在事后包含扩展名是不够的,因为它可能会导致争用条件。如果给
TempFile
的字符串包含"*
",则随机字符串 替换"*
"。例如 "
myname.*.bat
" 将导致随机 文件名,如"myname.123456.bat
"。如果没有包含"
*
",则 保留旧行为,并将随机数字附加到 结束。如果包含多个"
*
",则替换最后一个,因此 允许病理程序员创建文件名,例如 "foo*.123456.bat
",但不是"foo.123456.*.bat
"
原始答案 (2015)
我应该只复制/粘贴 TempFile 代码并添加后缀参数吗?
那将是一种方式。
另一种方法是进行快速 - 粗略的 - 实现,如本项目所示:
// TempFileName generates a temporary filename for use in testing or whatever
func TempFileName(prefix, suffix string) string {
randBytes := make([]byte, 16)
rand.Read(randBytes)
return filepath.Join(os.TempDir(), prefix+hex.EncodeToString(randBytes)+suffix)
}
正如 James Henstridge 在下面评论的那样,这是一个粗略的函数:
例如,该函数可以返回已经存在的文件名。这样的 API 应该通过使用
O_CREAT | O_EXCL
打开文件来创建文件,以确保在决定名称和创建文件之间没有其他人创建文件。
上面的粗略函数仅说明了使用 rand.Read()
生成文件名。
但其他检查都在io/ioutil/tempfile.go
.
3of3 建议在 math.rand
中使用函数,而不是在 io/ioutil/tempfile.go
中复制随机数生成器。
从 Go 1.16(2021 年 2 月)开始,您可以使用os.CreateTemp
:
package main
import "os"
func main() {
dirs := []string{"", "."}
for _, dir := range dirs {
f, err := os.CreateTemp(dir, "*.txt")
if err != nil {
panic(err)
}
defer f.Close()
println(f.Name())
}
}
结果:
C:WindowsTEMP163991747.txt
.2499233563.txt
https://godocs.io/os#CreateTemp
看看 https://github.com/tink-ab/tempfile。它基本上是标准库提供的内容,但同时支持前缀和后缀。
对于任何最近阅读此线程的人来说,截至目前(2020 年 4 月),ioutil.TempFile
同时处理前缀和后缀。
从其文档中:
临时文件在目录目录中创建一个新的临时文件, 打开文件进行读取和写入,并返回生成的
*os.File
。 文件名是通过采用模式并添加随机生成的 字符串到最后。如果模式包含"*
",则随机字符串 替换最后一个"*
"。
因此,传递"prefix-*-suffix
"作为pattern
参数将产生预期的行为。