I want to generate unique filenames in Golang with extensions. Very much akin to ioutil.TempFile, which only takes prefixes.
This has been brought up many times in the forums https://groups.google.com/forum/#!topic/golang-nuts/PHgye3Hm2_0 and the Go goes seem pretty intent on not adding that functionality to TempFile.
So what's the suggested way to handle this? Should I just copy/paste the TempFile code and add in a suffix parameter?
Update (2020: the original answer is from 2015)
As noted in Lax's answer, Go 1.11 (Apr. 2018) has changed TempFile
prefix to a pattern.
See commit 191efbc from CL 105675 after issue 4896
Users of
TempFile
need to be able to supply the suffix, especially when using operating systems that give semantic meaning to the filename extension such as Windows.
Renaming the file to include an extension after the fact is insufficient as it could lead to race conditions.If the string given to
TempFile
includes a "*
", the random string replaces the "*
".For example "
myname.*.bat
" will result in a random filename such as "myname.123456.bat
".If no "
*
' is included the old behavior is retained, and the random digits are appended to the end.If multiple "
*
" are included, the final one is replaced, thus permitting a pathological programmer to create filenames such as "foo*.123456.bat
" but not "foo.123456.*.bat
"
Original Answer (2015)
Should I just copy/paste the TempFile code and add in a suffix parameter?
That would be one way.
Other way is to make a quick -- crude -- implementation, as in this project:
// 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)
}
As James Henstridge comments below, this is a crude function:
That function can return file names that already exist, for instance. Such an API should be creating the file by opening it with
O_CREAT | O_EXCL
to ensure that no one else creates the file between deciding on the name and creating the file.
That crude function above illustrates only the use of rand.Read()
to generate a filename.
But the other checks are all in io/ioutil/tempfile.go
.
3of3 suggests to use a function in math.rand
instead of copying the random number generator in io/ioutil/tempfile.go
.
Starting with Go 1.16 (Feb 2021), you can use 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())
}
}
Result:
C:\Windows\TEMP\163991747.txt
.\2499233563.txt
https://godocs.io/os#CreateTemp
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With