Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

os: Add comment on proper way to check if a file exists #8456

Closed
btracey opened this issue Jul 31, 2014 · 6 comments
Closed

os: Add comment on proper way to check if a file exists #8456

btracey opened this issue Jul 31, 2014 · 6 comments

Comments

@btracey
Copy link
Contributor

btracey commented Jul 31, 2014

There is no "os.Exists(filename string) bool" to check if a given file name
exists. 

One common description [0] on how to do it is

_, err := os.Open(filename)
if err == nil{
    fmt.Println("exists")
}

This code is wrong, because os.Open creates a file resource, and that resource will not
be closed. For example, http://play.golang.org/p/ANlrZUrsQK will panic with "panic:
open file.txt: too many open files" (I assume that this is correct behavior). 

It would be nice if there was a comment somewhere on the proper way to check if a file
exists (from what I gather os.Stat is the correct way) 


[0] http://stackoverflow.com/questions/12518876/how-to-check-if-a-file-exists-in-go  
(this is the top google result)
@cznic
Copy link
Contributor

cznic commented Jul 31, 2014

Comment 1:

The proper way to check if a file exists is to not check if a file exists as that
information is unavoidably racy.
os.Stat is not about file existence but about file metadata. Even though the error
possibly returned may mean the file didn't existed when os.Stat was executing, it does
not mean the file does not exists now, when os.Stat completed.
Use os.O_EXCL when creating a file which must not exists already and the err from
os.Open when a file must exist before opening.

@btracey
Copy link
Contributor Author

btracey commented Jul 31, 2014

Comment 2:

I don't understand your comment that "the information is unavoidably racy". Programs can
be structured such that the same goroutine that may create the file is also the same one
that checks if the file exists. Or, one can use channels to pass "ownership" of the
filename. Files don't magically appear on computers, and in many cases the file won't be
created outside the program.

@cznic
Copy link
Contributor

cznic commented Jul 31, 2014

Comment 3:

A process is typically not executing completely isolated. A user can type a shell
command/script which can create a file or delete a file at any time. Or any other
process can do the same. Sometimes it's the same program, still running in its previous
invocation (which one possibly forgot to kill), etc.

@ianlancetaylor
Copy link
Contributor

Comment 4:

There is no proper way to test if a file exists.  As 0xjnml says, any such test is
normally racy, because if you make any decision based on whether the file exists, the
file may have been created or deleted by some entirely independent process by the time
you execute that decision.  What you need are operations like "create this file, but
only if it does not exist" (which is done by using os.OpenFile with O_CREATE|O_EXCL).

Status changed to Invalid.

@btracey
Copy link
Contributor Author

btracey commented Jul 31, 2014

@ianlancetaylor
Copy link
Contributor

Comment 6:

Where would you suggest putting a comment about this?  To my mind it really has nothing
to do with Go, it has to do with the nature of multi-process machines.  Writing a
program that assumes that it can test whether a file exists can be a security issue, but
that too has nothing to do with Go.
It's fine to use os.Stat for the very rare cases where it's OK to simply test whether a
file exists.  That doesn't mean that we should document it as such.

@golang golang locked and limited conversation to collaborators Jun 25, 2016
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants