Go의 표준 라이브러리에는 파일이 존재하는지 여부를 확인하는 기능 (Python 's 등 os.path.exists)이 없습니다. 그것을 하는 관용적 방법 은 무엇입니까 ?
Go의 표준 라이브러리에는 파일이 존재하는지 여부를 확인하는 기능 (Python 's 등 os.path.exists)이 없습니다. 그것을 하는 관용적 방법 은 무엇입니까 ?
답변:
파일이 존재하지 않는지 확인하려면 Python과 같습니다 if not os.path.exists(filename).
if _, err := os.Stat("/path/to/whatever"); os.IsNotExist(err) {
// path/to/whatever does not exist
}
파일이 존재하는지 확인하려면 Python과 같습니다 if os.path.exists(filename).
편집 : 최근 댓글 당
if _, err := os.Stat("/path/to/whatever"); err == nil {
// path/to/whatever exists
} else if os.IsNotExist(err) {
// path/to/whatever does *not* exist
} else {
// Schrodinger: file may or may not exist. See err for details.
// Therefore, do *NOT* use !os.IsNotExist(err) to test for file existence
}
NOTEXIST하는 경우, 예를 들어, /etc/bashrc존재의이 /etc/bashrc/foobar돌아갑니다ENOTDIR
!os.IsNotExist(err). 파일이 존재하지만 os.Stat다른 이유로 실패 할 수 있습니다 (예 : 권한, 디스크 실패). err == nil조건으로 사용하면 "파일이 없습니다"와 같은 오류가 잘못 분류됩니다.
의해 답변을 Caleb Spare gonuts mailing list에 게시했습니다 .
[...] 실제로는 자주 필요하지 않으며 [...] 사용
os.Stat이 필요한 경우에 충분히 사용 하기 쉽습니다.[...] 예를 들어 파일을 열 경우 파일이 먼저 존재하는지 확인할 이유가 없습니다. 파일은 확인과 열기 사이에 사라질 수 있으며, 어쨌든
os.Open오류 를 확인해야합니다 . 따라서os.IsNotExist(err)파일을 열려고 시도한 후 호출 하고 존재하지 않는 파일을 처리합니다 (특별한 처리가 필요한 경우).[...] 당신은 전혀 존재하지 않는 경로를 확인할 필요가 없습니다.
os.MkdirAll경로가 이미 존재하는지 여부에 관계없이 작동합니다. (또한 해당 호출에서 오류를 확인해야합니다.)을 사용하는 대신을
os.Create사용해야합니다os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666). 이렇게하면 파일이 이미 있으면 오류가 발생합니다. 또한 이것은 존재 여부를 미리 확인하는 버전과 달리 파일을 만드는 다른 것과 경쟁 조건이 없습니다.
출처 : https://groups.google.com/forum/#!msg/golang-nuts/Ayx-BMNdMFo/4rL8FFHr8v4J
다음 예제 os.Stat()와 os.IsNotExist()같이 및 기능을 사용해야합니다 .
// Exists reports whether the named file or directory exists.
func Exists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
return false
}
}
return true
}
user11617 의 예제 가 올바르지 않습니다. 파일이 존재하지 않는 경우에도 파일이 존재한다고보고하지만 다른 종류의 오류가 발생했습니다.
서명은 Exists (string) (bool, error) 여야합니다. 그런 다음 호출 사이트가 더 나아지지 않습니다.
그가 작성한 코드는 다음과 같이 더 좋습니다.
func Exists(name string) bool {
_, err := os.Stat(name)
return !os.IsNotExist(err)
}
그러나 나는 이것을 대신 제안한다.
func Exists(name string) (bool, error) {
_, err := os.Stat(name)
if os.IsNotExist(err) {
return false, nil
}
return err != nil, err
}
err != nil대신에 반환 err == nil? 오류가 있으면 파일이 존재하지 않을 수 있습니까?
다른 답변이 놓친 것은 함수에 주어진 경로가 실제로 디렉토리 일 수 있다는 것입니다. 다음 함수는 경로가 실제로 파일인지 확인합니다.
func fileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
지적해야 할 또 다른 사항 :이 코드는 fileExists 함수가 실행되는 동안 다른 스레드 또는 프로세스가 지정된 파일을 삭제하거나 작성하는 경쟁 조건으로 이어질 수 있습니다.
이 문제가 걱정되면 스레드에서 잠금을 사용하거나이 기능에 대한 액세스를 직렬화하거나 여러 응용 프로그램이 관련된 경우 프로세스 간 세마포를 사용하십시오. 다른 응용 프로그램이 통제 범위를 벗어나면 운이 좋지 않을 것입니다.
기능 예 :
func file_is_exists(f string) bool {
_, err := os.Stat(f)
if os.IsNotExist(err) {
return false
}
return err == nil
}
먼저 os패키지 측면에서 제공하는 기능 golang은 유틸리티가 아니라 오류 검사기라는 몇 가지 측면을 살펴 보겠습니다. 즉, 크로스 플랫폼에서 오류를 처리하기위한 래퍼 일뿐입니다.
따라서 기본적 os.Stat으로이 함수가 오류를 제공하지 않으면 파일이 존재한다는 것을 의미하는 경우 어떤 종류의 오류인지 확인 해야하는 경우 여기 에이 두 함수 os.IsNotExist와 의 사용 이옵니다 os.IsExist.
이것은 Stat파일 던지기 오류가 존재하지 않기 때문에 또는 파일이 존재하기 때문에 오류가 발생하는 것으로 이해 될 수 있으며 문제가 있습니다.
이 함수가 취하는 매개 변수는 유형 error이지만 전달할 수는 nil있지만 의미가 없습니다.
이것은 또한 IsExist is not same as !IsNotExist두 가지 다른 방법 이라는 사실을 지적합니다 .
이제 주어진 파일이 있는지 알고 싶다면 가장 좋은 방법은 다음과 같습니다.
if _, err := os.Stat(path/to/file); !os.IsNotExist(err){
//TODO
}
다른 답변에서 언급했듯이와 다른 플래그를 사용하여 필요한 동작 / 오류를 구성 할 수 있습니다 os.OpenFile. 실제로, os.Create그렇게하는 것이 현명한 기본값입니다.
// Create creates or truncates the named file. If the file already exists,
// it is truncated. If the file does not exist, it is created with mode 0666
// (before umask). If successful, methods on the returned File can
// be used for I/O; the associated file descriptor has mode O_RDWR.
// If there is an error, it will be of type *PathError.
func Create(name string) (*File, error) {
return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
}
관심있는 동작을 얻으려면이 플래그를 직접 결합해야합니다.
// Flags to OpenFile wrapping those of the underlying system. Not all
// flags may be implemented on a given system.
const (
// Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified.
O_RDONLY int = syscall.O_RDONLY // open the file read-only.
O_WRONLY int = syscall.O_WRONLY // open the file write-only.
O_RDWR int = syscall.O_RDWR // open the file read-write.
// The remaining values may be or'ed in to control behavior.
O_APPEND int = syscall.O_APPEND // append data to the file when writing.
O_CREATE int = syscall.O_CREAT // create a new file if none exists.
O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist.
O_SYNC int = syscall.O_SYNC // open for synchronous I/O.
O_TRUNC int = syscall.O_TRUNC // truncate regular writable file when opened.
)
선택한 내용에 따라 다른 오류가 발생합니다.
다음은 쓰기 위해 파일을 열고 자하는 예입니다. 그러나 사용자가 정상이라고 말한 경우에만 기존 파일을 자릅니다.
var f *os.File
if truncateWhenExists {
// O_TRUNC - truncate regular writable file when opened.
if f, err = os.OpenFile(filepath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644); err != nil {
log.Fatalln("failed to force-open file, err:", err)
}
} else {
// O_EXCL - used with O_CREATE, file must not exist
if f, err = os.OpenFile(filepath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0644); err != nil {
log.Fatalln("failed to open file, err:", err)
}
}