Go에 파일이 있는지 확인하는 방법


436

Go의 표준 라이브러리에는 파일이 존재하는지 여부를 확인하는 기능 (Python 's 등 os.path.exists)이 없습니다. 그것을 하는 관용적 방법 은 무엇입니까 ?


나는 그것을 정말로 얻지 못한다. 같은 순간에 표준 기능이 없다고 말하고 표준 기능으로 답을 작성하십시오. 내가 무엇을 놓치고 있습니까? 적어도 질문을 수정해서는 안됩니까?
Denys Séguret

@dystroy-질문을 수정했습니다.
Sridhar Ratnakumar

11
파일 존재를 묻지 않는 것이 좋습니다. 대답의 기발한 성격의 B / C, 얻은 정보는 실제로 요청 된 시간에 파일 위에 존재하는 유용한 정보가 없다고 말하지만 더 이상 존재하지 않을 수 있습니다. 권장되는 방법은 단순히 파일을 열고 실패 여부를 확인하는 것입니다.
zzzz

2
이것은 이미 대답했습니다 여기에
세르게이 Koulikov을

2
@ zzzz (몇 년이 지났다는 것을 알고 있습니다.이 의견은 새로운 독자를위한 것입니다) 나는 일반적인 경우에 동의합니다. 그러나 내 앱은 파일 경로를 초기화 데이터로 사용하지만 파일이 없으면 segfaults 인 타사 라이브러리를로드합니다. 내 코드가 파일 내용을 읽거나 파일에 직접 쓸 필요가 없으므로 치명적인 충돌없이 오류를보고 할 수 있도록 파일을 열지 않고 파일이 존재하는지 확인하는 데 유효한 시나리오라고 생각합니다.
Sergio Acosta

답변:


693

파일이 존재하지 않는지 확인하려면 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


}

3
때로는 대신 ENOTDIR을 반환 NOTEXIST하는 경우, 예를 들어, /etc/bashrc존재의이 /etc/bashrc/foobar돌아갑니다ENOTDIR
lidaobing

43
두 번째 스 니펫은 더 미묘하게 잘못되었습니다. 조건은이어야합니다 !os.IsNotExist(err). 파일이 존재하지만 os.Stat다른 이유로 실패 할 수 있습니다 (예 : 권한, 디스크 실패). err == nil조건으로 사용하면 "파일이 없습니다"와 같은 오류가 잘못 분류됩니다.
sqweek

9
파일이 존재하는지 확인하기 : 파일이 존재하면 err is nil
tangxinfa

1
~ 확인 확장하십시오 그렇지 않으면 거짓 ... 반환합니다 stackoverflow.com/questions/17609732/...을
마르첼로 드 판매

! os.IsNotExistant을 할 때 당신은 os.IsExist ()의 경우를 따라 사용할 수있는 이중 부정을 대신 더 관용구 될 수있다 ()
아리엘 모나코

126

의해 답변을 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


31

다음 예제 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
}

예제는 여기 에서 추출 됩니다 .


12
주의 : stackoverflow.com/a/22467409/712014에서 지적 했듯이이 코드는 파일이 존재하지 않더라도 (예 : Stat ()가 권한 거부를 반환 한 경우) true를 반환합니다.
Michael

19

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
}

7
예제 5 란 무엇입니까? 구체적으로 말씀해 주시겠습니까?
xlm

1
두 번째 예는 여러 반환 값을 구조화해야합니다 (예 : _, err : = os.Stat (name)
David Duncan

6
err != nil대신에 반환 err == nil? 오류가 있으면 파일이 존재하지 않을 수 있습니까?
idbrii

14

다른 답변이 놓친 것은 함수에 주어진 경로가 실제로 디렉토리 일 수 있다는 것입니다. 다음 함수는 경로가 실제로 파일인지 확인합니다.

func fileExists(filename string) bool {
    info, err := os.Stat(filename)
    if os.IsNotExist(err) {
        return false
    }
    return !info.IsDir()
}

지적해야 할 또 다른 사항 :이 코드는 fileExists 함수가 실행되는 동안 다른 스레드 또는 프로세스가 지정된 파일을 삭제하거나 작성하는 경쟁 조건으로 이어질 수 있습니다.

이 문제가 걱정되면 스레드에서 잠금을 사용하거나이 기능에 대한 액세스를 직렬화하거나 여러 응용 프로그램이 관련된 경우 프로세스 간 세마포를 사용하십시오. 다른 응용 프로그램이 통제 범위를 벗어나면 운이 좋지 않을 것입니다.


12
    _, err := os.Stat(file)
    if err == nil {
        log.Printf("file %s exists", file)
    } else if os.IsNotExist(err) {
        log.Printf("file %s not exists", file)
    } else {
        log.Printf("file %s stat error: %v", file, err)
    }

7

기능 예 :

func file_is_exists(f string) bool {
    _, err := os.Stat(f)
    if os.IsNotExist(err) {
        return false
    }
    return err == nil
}

1
중복되지 않습니까?
Ilia Choly 2018 년

6

먼저 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
} 

1

다른 답변에서 언급했듯이와 다른 플래그를 사용하여 필요한 동작 / 오류를 구성 할 수 있습니다 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) 
   }
}

0

파일이 존재하는지 확인하는 가장 좋은 방법 :

if _, err := os.Stat("/path/to/file"); err == nil || os.IsExist(err) {
    // your code here if file exists
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.