File.Error 예외

File.Error 예외

파일 연산이 실패했을 때 발생하는 예외로, File 모듈에서 가장 기본이 되는 오류 예외예요. 존재하지 않는 파일을 읽으려는 것처럼 다양한 실패 상황에서 이 예외가 나와요.

예를 들어 없는 파일을 강제로 읽으려고 하면 다음처럼 에러가 떠요.

iex> File.read!("nonexistent_file.txt")
** (File.Error) could not read file "nonexistent_file.txt": no such file or directory

출처: File.Error exception

본문

File.read!/1처럼 느낌표가 붙은 함수들은 실패하면 이 예외를 던져요. 반대로 File.read/1 같은 함수는 {:ok, content} 또는 {:error, reason} 튜플을 돌려주고요. 느낌표가 붙은 "강제" 버전을 쓰면 이 예외를 만나게 되는 거죠.

이 예외도 문제를 파악하기 위한 공개 필드를 제공해요.

  • :path (Path.t/0) — 오류를 일으킨 파일의 경로예요.
  • :reason (File.posix/0) — 오류의 원인이 된 이유예요.

File.posix/0은 파일 시스템이 돌려주는 POSIX 스타일의 오류 이유를 나타내는 타입이에요. :enoent(no such file or directory), :eacces(권한 없음) 같은 아톰 값들을 생각하면 돼요. 필드에 들어 있는 이유를 그대로 로그에 남기거나, 사용자에게 어떤 파일에서 무슨 문제가 생겼는지 알려줄 수 있어요.

특히 여러 파일을 순회하며 작업하는 코드라면, 이 예외의 :path 필드가 어떤 파일에서 실패했는지를 정확히 짚어주기 때문에 디버깅에 큰 도움이 돼요.

실무에서 이 예외의 쓰임새를 좀 더 구체적으로 보면, 두 가지 흐름으로 나뉘어요. 첫째는 **"없어도 되는 파일"**을 다루는 경우예요. 이때는 File.read/1 같은 튜플 반환 함수를 써서 {:error, reason}을 받고, reason을 보고 분기하는 게 자연스러워요. 둘째는 **"반드시 있어야 하는 파일"**을 다루는 경우로, 설정 파일이나 필수 리소스를 읽을 때가 대표적이에요. 그럴 때는 File.read!/1을 써서 파일이 없으면 곧바로 File.Error가 터지게 만들어, "이 파일은 없으면 안 되는 파일이라서 프로그램이 계속되면 안 된다"는 의도를 드러내는 게 좋아요.

또 하나 기억할 점은 :reason이 항상 단순한 실패만 뜻하는 건 아니라는 거예요. 예를 들어 파일이 디렉터리인 경우 :eisdir이 나올 수 있고, 파일 이름의 어떤 구성 요소가 디렉터리가 아닌 경우 :enotdir이 나올 수 있어요. 모두 File.posix/0에 속하는 값들이니, 에러를 세밀하게 다뤄야 한다면 이 타입의 값들에 익숙해지는 게 도움이 돼요.

더 알아보기

  • File.read/1File.read!/1처럼 튜플을 돌려주는 버전과 예외를 던지는 버전의 차이를 비교해 보세요.
  • 오류 이유의 종류는 File.posix/0 타입 문서에서 자세히 확인할 수 있어요.
  • 파일을 안전하게 다루는 방법은 File 모듈 본문 문서를 참고해 보세요.