Best practice when creating temporary files

1,701 views
Skip to first unread message

Ondrej

unread,
Nov 18, 2016, 5:21:23 AM11/18/16
to golang-nuts
I have a tool that generates some HTML and launches a web browser to display it. For this to work, I need to save the HTML some place and I also need to handle the file afterwards. The app itself doesn't persist - it generates the content and exits. There are thus two issues I'm struggling with:

1. What is the best place for this? Do I create a folder in usr.HomeDir()/.appname/ and place HTML files there? Or do I just create tempfiles in os.TempDir? Does it make a difference?
2. How do I clean up? As I said, the app does not persist (so I can't defer os.Remove), so either I scan the folder in question (before my HTML generation) and remove all files older than, say, a day. Or is that done for me by the operating system if I use os.TempDir?

I thought I'd just use os.TempDir and let the OS handle it, but I'm not 100% sure the OS does clean this up on its own. (This will be used on Windows and Macs, maybe Linux.) Any insight on any of these would be greatly appreciated.

Thanks!

Tamás Gulácsi

unread,
Nov 18, 2016, 5:59:31 AM11/18/16
to golang-nuts
2016. november 18., péntek 11:21:23 UTC+1 időpontban Ondrej a következőt írta:
I have a tool that generates some HTML and launches a web browser to display it. For this to work, I need to save the HTML some place and I also need to handle the file afterwards. The app itself doesn't persist - it generates the content and exits. There are thus two issues I'm struggling with:

Can't the app wait a little bit (maybe a signal from the browser, or a safe 1 minute), delete the file and then exit?

On modern Linux, /run/user/$(id -u) persists only till the user is logged in.

Otherwise, maybe the browser's "Downloads" destination could be used.

Jan Mercl

unread,
Nov 18, 2016, 6:21:48 AM11/18/16
to Ondrej, golang-nuts
On Fri, Nov 18, 2016 at 11:21 AM Ondrej <ondrej...@gmail.com> wrote:

Not sure if it's correct, just an idea (error handling elided):

        func main() {
                ...
                exec.Cmd(browser, pathName).Start()
                syscal.Unlink(pathName)
        }

The temp file in pathName will be deleted when the browser closes the file.

--

-j

Tamás Gulácsi

unread,
Nov 18, 2016, 6:46:27 AM11/18/16
to golang-nuts, ondrej...@gmail.com

Only on normal fs, not on Windows (or you have to open the file with FILE_SHARE_DELETE flag...)

Val

unread,
Nov 18, 2016, 10:54:36 AM11/18/16
to golang-nuts
Obtain a new temp file :
  tmpfile, err := ioutil.TempFile("", "")

Obtain a new temp dir :
  dir, err := ioutil.TempDir("", "")

I suggest you don't bother with cleanup.  It should work on any OS.

Ondrej

unread,
Nov 21, 2016, 10:19:26 AM11/21/16
to golang-nuts
That's my current code, I just wanted to double check that it's the proper one (ie that the cleanup actually happens), since some of my temp files can be fairly large.

Val

unread,
Nov 21, 2016, 11:57:56 AM11/21/16
to golang-nuts
OK, I had overlooked the fact that cleanup is important to you, which makes sense for security and to save disk space early.
TempFile, TempDir don't do the cleanup, but the OS will sooner or later.
Here is my new suggestion for a file and for a dir :

tmpfile, err := ioutil.TempFile("", "")
checkerr(err)
defer os.Remove(tmpfile.Name())



dir, err := ioutil.TempDir("", "")
checkerr(err)
defer os.RemoveAll(dir)

Steven Hartland

unread,
Nov 21, 2016, 12:01:30 PM11/21/16
to golan...@googlegroups.com
That's a bad assumption, you should always clean up after yourself.
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Ondrej

unread,
Nov 21, 2016, 12:08:03 PM11/21/16
to golang-nuts
I already noted that in my very first post, "How do I clean up? As I said, the app does not persist (so I can't defer os.Remove)"

I guess I wasn't quite clear about my intentions, so never mind, I'll just handle it somehow. 

Thanks all for your suggestions.

Thomas Bushnell, BSG

unread,
Nov 21, 2016, 12:46:00 PM11/21/16
to Steven Hartland, golan...@googlegroups.com
It's fine to try, but you should design your entire system with the assumption that your program may crash at any moment and leave something around. This is why the OS cleans up /tmp.

Thomas

not...@google.com

unread,
Nov 21, 2016, 2:24:57 PM11/21/16
to golang-nuts
One approach that I use is to make new invocations of the program try to clean up after older ones.  For example, if you name your temp directories with a particular pattern, you can delete old directories on start up.  Ideally you _should_ try to clean up in the same process, but it isn't always possible.  Even cleaning up 99.99% of the time is still not 100%.  What I do is something like:

tmp := filepath.join(os.Tempdir(), "mydir")
os.RemoveAll(tmp) 
t, err := ioutil.TempFile(tmp, "prefix")
if err != nil {
  // ...
}
defer os.Remove(t.Name())
defer t.Close()



Some random other thoughts about temp files:

1.  If you are running on Windows, you have to make sure to close all references to the file before you can delete it.  
2.  If you press Ctrl-C in the middle of your program (or it terminates abnormally), none of the defers will be run.  You can try to catch this, but its kind of moot, since the signal handler is usually not in the same scope as the file access.

Steven Hartland

unread,
Nov 21, 2016, 7:41:23 PM11/21/16
to Thomas Bushnell, BSG, golan...@googlegroups.com
Where I was going was that's an assumption based on OS specifics; some do e.g. most Linux flavors but not all OS's do at least by default, so its best to avoid the assumption that it will happen.

Absolutely agree that crashes happen, but this thread was about standard cleanup after a program which creates transitory files that are required for a limited period after its run.

For something of this nature a design which attempts to clean up the last invocations files, for example, would be one solution to the OP's question.

I would certainly not advise relying on OS cleanup for standard process flow, as even those OS's that do only tend to do so on reboot, which may be significant time in the future.

Thomas

To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages