File 클래스

File 클래스 (File)

File 객체는 기반 플랫폼에서 파일을 나타내는 표현이에요. File 클래스는 FileTest 모듈을 확장해서 File.exist? 같은 싱글턴 메서드들을 지원해요.

FileIO 클래스에서 상속하므로 파일 생성·읽기·쓰기 메서드들을 물려받고, 추가로 파일 경로/타입/시간 등을 다루는 메서드를 제공해요.

출처: Ruby 4.0 API

본문

예시에 쓰는 변수 (About the Examples)

많은 예시가 다음 변수들을 사용해요.

# English text with newlines.
text = <<~EOT
  First line
  Second line
  Fourth line
  Fifth line
EOT
# Russian text.
russian = "\u{442 435 441 442}" # => "тест"
# Text file.
File.write('t.txt', text)

접근 모드 (Access Modes)

File.newFile.open은 주어진 파일 경로에 대한 File 객체를 만들어요.

문자열 접근 모드 (String Access Modes)

mode 문자열은 1~2자리 읽기/쓰기 모드로 시작하고, 1자리 데이터 모드와 1자리 파일-생성 모드를 추가로 담을 수 있어요.

읽기/쓰기 모드 (Read/Write Mode) — 파일을 초기에 잘라낼지(truncate), 읽기가 허용되는지/안 되는지, 읽기·쓰기의 초기 위치가 어디인지를 결정해요.

모드 초기 잘라냄 읽기 초기 읽기 위치 쓰기 초기 쓰기 위치
'r' 아니오 아무데나 0 오류
'w' 오류 아무데나 0
'a' 아니오 오류 끝만
'r+' 아니오 아무데나 0 아무데나 0
'w+' 아무데나 0 아무데나 0
'a+' 아니오 아무데나 끝만

표의 아무데나(Anywhere)IO#rewind, IO#pos=, IO#seek으로 파일 위치를 바꿔 어디서든 읽기/쓰기가 가능하다는 뜻이에요. 끝만(End only)은 쓰기가 파일 끝에서만 일어나고, 위치 변경 메서드들이 쓰기에 영향을 주지 못한다는 뜻이에요. 오류(Error)는 허용되지 않는 읽기/쓰기를 시도하면 예외가 발생한다는 뜻이에요. 존재하지 않는 파일에는 'r''r+' 모드를 쓸 수 없어요(예외 발생).

예시로 'w' 모드는 파일을 초기에 잘라내고 초기 쓰기 위치가 0이에요. 그래서 다시 열면 내용이 비워져요.

path = 't.tmp'
File.write(path, text)
f = File.new(path, 'w')
f.size == 0 # => true

데이터 모드 (Data Mode) — 데이터를 텍스트로 다룰지 바이너리로 다룰지 정해요.

  • 't' — 텍스트. 기본 외부 인코딩을 Encoding::UTF_8로 설정. Windows에서는 EOL과 CRLF 변환을 켜고 0x1A를 파일 끝 마커로 해석.
  • 'b' — 바이너리. 기본 외부 인코딩을 Encoding::ASCII_8BIT로 설정. Windows에서 EOL/CRLF 변환을 끄고 0x1A 해석을 끔.

둘 다 주지 않으면 텍스트 데이터로 기본 설정돼요. 데이터 모드를 지정하면 읽기/쓰기 모드를 생략할 수 없고, 데이터 모드는 파일-생성 모드 앞에 와야 해요.

File.new('t.txt', 'rt')
File.new('t.dat', 'rb')
File.new('t.dat', 'b')   # Raises an exception.

파일-생성 모드 (File-Create Mode) — 쓰기 가능한 문자열 모드에 'x'를 붙일 수 있어요. 파일이 없으면 만들고, 있으면 예외를 발생시켜요.

File.new('t.tmp', 'wx')
File.new('t.dat', 'x')   # Raises an exception.

정수 접근 모드 (Integer Access Modes)

mode가 정수면 다음 상수들을 비트 OR(|)로 조합해요: File::RDONLY(읽기 전용), File::WRONLY(쓰기 전용), File::RDWR(읽기·쓰기), File::APPEND(추가 전용). 파일-생성 관련으로 File::CREAT(없으면 생성), File::EXCL(CREAT가 주어졌는데 파일이 있으면 예외)도 OR할 수 있어요.

File.new('t.txt', File::RDONLY)
File.new('t.tmp', File::RDWR | File::CREAT | File::EXCL)

데이터 모드는 정수로 지정할 수 없어요. 정수 모드에서는 항상 텍스트 모드예요. (File::BINARY 상수는 줄 코드 변환만 끌 뿐 외부 인코딩을 바꾸지 않아서, 정수 스트림 모드에 넣어도 효과가 없어요.)

인코딩 (Encodings)

문자열 모드에 콜론으로 외부 인코딩 또는 외부·내부 인코딩 둘 다를 지정할 수 있어요.

f = File.new('t.dat', 'rb')
f.external_encoding # => #<Encoding:ASCII-8BIT>
f.internal_encoding # => nil
f = File.new('t.dat', 'rb:UTF-16:UTF-16')
f.external_encoding # => #<Encoding:UTF-16 (dummy)>
f.internal_encoding # => #<Encoding:UTF-16>

외부 인코딩이 설정되면 읽는 문자열은 그 인코딩으로 태그되고, 쓰는 문자열은 그 인코딩으로 변환돼요. 둘 다 설정되면 읽기는 외부→내부로, 쓰기는 내부→외부로 변환돼요. 외부 인코딩이 'BOM|UTF-8', 'BOM|UTF-16LE', 'BOM|UTF16-BE'면 입력 문서에서 Unicode BOM을 확인해 인코딩을 결정해요. UTF-16 인코딩은 파일 열기 모드가 반드시 바이너리여야 해요. BOM 스타일 인코딩 옵션은 대소문자를 가리지 않아서 'bom|utf-8'도 유효해요.

파일 권한 (File Permissions)

File 객체는 권한(permissions)을 갖는데, 기반 플랫폼의 실제 파일 권한을 나타내는 8진수 정수예요. 파일 스트림의 mode(열기 모드)와는 다르다는 점을 주의하세요. mode라는 이름의 메서드도 권한을 돌려줘요.

f = File.new('t.txt')
f.lstat.mode.to_s(8) # => "100644"

Unix 계열에서 낮은 세 자리 8진수는 소유자(6), 그룹(4), 공개(4) 권한을 나타내고, 각 8진수의 비트는 읽기·쓰기·실행 권한이에요. 예를 들어 0644는 소유자에게 읽기·쓰기, 그룹과 공개에게 읽기만 허용해요. 디렉토리에서는 실행 비트의 의미가 바뀌어, 설정되면 디렉토리를 검색할 수 있게 돼요. 실제 플랫폼에 파일을 만드는 메서드는 권한을 지정할 수 있어요.

File.new('t.tmp', File::CREAT, 0644)
f = File.new('t.tmp', File::CREAT, 0444)
f.chmod(0644)

상수 (Constants)

  • SEPARATOR / Separator — 경로에서 디렉토리 부분을 나누는 구분자.
  • ALT_SEPARATOR — 플랫폼별 대체 구분자.
  • PATH_SEPARATOR — 경로 목록 구분자.

::absolute_path (Public Class Method)

absolute_path(file_name[, dir_string]) → abs_file_name — 경로 이름을 절대 경로로 변환해요. 상대 경로는 프로세스의 현재 작업 디렉토리를 기준으로 하고, dir_string을 주면 그걸 시작점으로 써요. ~로 시작하는 경로는 확장하지 않고 일반 디렉토리 이름으로 취급해요.

File.absolute_path("~oracle/bin") #=> "<relative_path>/~oracle/bin"

::absolute_path? (Public Class Method)

absolute_path?(file_name) → true 또는 false — file_name이 절대 경로면 true, 아니면 false.

::atime / ::birthtime / ::ctime / ::mtime (Public Class Method)

atime(file_name) → time — 마지막 접근 시간. birthtime(file_name) → time — 생성 시간(플랫폼 지원 안 하면 NotImplementedError). ctime(file_name) → time — 메타데이터 변경 시간(Windows NTFS에서는 생성 시간). mtime(file_name) → time — 내용의 최근 데이터 수정 시간. 모두 Time 객체로 돌려줘요.

::basename (Public Class Method)

basename(file_name[, suffix]) → base_name — 파일 이름의 마지막 구성 요소를 돌려줘요. suffix가 주어지고 파일 이름 끝에 있으면 제거하고, ".*"면 확장자를 제거해요.

File.basename("/home/gumby/work/ruby.rb")        #=> "ruby.rb"
File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby"
File.basename("/home/gumby/work/ruby.rb", ".*")  #=> "ruby"

::blockdev? / ::chardev? / ::directory? / ::executable? / ... (Public Class Method)

타입 관련 클래스 메서드들이에요. FileTest 모듈 문서에서 자세히 다뤘으니 여기선 요약만 볼게요.

  • blockdev?, chardev?, directory?, file?, pipe?, socket?, symlink? — 각각 해당 타입인지.
  • executable?, executable_real?, readable?, readable_real?, writable?, writable_real? — 유효/실제 사용자·그룹 기준 권한.
  • setgid?, setuid?, sticky?, grpowned?, owned?, world_readable?, world_writable? — 특수 비트나 소유권 관련.
  • exist?, zero?(별칭 empty?) — 존재 여부 / 크기가 0인지.
  • ftype — 파일 타입 문자열("file", "directory", "characterSpecial", "blockSpecial", "fifo", "link", "socket", "unknown" 중 하나).

::chmod (Public Class Method)

chmod(mode_int, file_name, ...) → integer — 지정된 파일(들)의 권한 비트를 mode_int 패턴으로 바꿔요. 효과는 OS에 따라 달라요. 처리된 파일 수를 돌려줘요.

::chown (Public Class Method)

chown(owner_int, group_int, file_name, ...) → integer — 파일(들)의 소유자와 그룹을 주어진 숫자 id로 바꿔요. 파일 소유자를 바꾸려면 superuser 권한이 필요해요. nil이나 -1인 소유자/그룹 id는 무시돼요. 처리된 파일 수를 돌려줘요.

delete(file_name, ...) → integer (별칭 unlink) — 이름이 붙은 파일들을 삭제하고, 인자로 넘긴 이름의 개수를 돌려줘요. 어떤 오류든 예외를 발생시켜요. 내부 구현이 unlink(2) 시스템 콜에 의존하므로 예외 타입은 그 오류에 달려 있어요(예: Errno::ENOENT).

::dirname (Public Class Method)

dirname(file_name, level = 1) → dir_name — 파일 이름에서 마지막 구성 요소를 제외한 모든 부분을 돌려줘요. level을 주면 하나가 아니라 마지막 level 개 구성 요소를 제거해요.

File.dirname("/home/gumby/work/ruby.rb")   #=> "/home/gumby/work"
File.dirname("/home/gumby/work/ruby.rb", 2) #=> "/home/gumby"

::expand_path (Public Class Method)

expand_path(file_name[, dir_string]) → abs_file_name — 경로를 절대 경로로 변환해요. ~로 시작하면 프로세스 소유자의 홈 디렉토리로, ~user는 그 사용자의 홈으로 확장해요.

File.expand_path("~oracle/bin")      #=> "/home/oracle/bin"
File.expand_path("ruby", "/usr/bin") #=> "/usr/bin/ruby"

::extname (Public Class Method)

extname(path) → string — 마지막 마침표부터의 확장자 부분을 돌려줘요. 도트파일이나 마침표로 시작하는 경로는 시작 도트를 확장자 시작으로 취급하지 않아요. 마침표가 마지막 문자이면 빈 문자열을 돌려줘요.

File.extname("test.rb")        #=> ".rb"
File.extname(".profile")       #=> ""
File.extname(".profile.sh")    #=> ".sh"

::fnmatch (Public Class Method)

fnmatch(pattern, path, [flags]) → true 또는 false (별칭 fnmatch?) — pathpattern과 일치하면 true. pattern은 정규식이 아니라 셸 파일명 글롭과 비슷한 규칙을 따르는 메타문자들을 포함할 수 있어요.

  • * — 어떤 파일이든 일치. c*는 c로 시작하는 모든 파일, *c는 c로 끝나는, *c*는 c를 포함하는 모든 파일.
  • ** — 디렉토리를 재귀적으로 또는 파일을 확장적으로 일치.
  • ? — 한 문자 일치.
  • [set] — 집합의 한 문자 일치. 부정([^a-z]) 포함.
  • \ — 다음 메타문자를 이스케이프.
  • {a,b}File::FNM_EXTGLOB 플래그가 켜지면 a 또는 b 패턴 일치.

flagsFNM_XXX 상수들의 비트 OR이에요 (FNM_DOTMATCH, FNM_CASEFOLD, FNM_PATHNAME, FNM_NOESCAPE, FNM_EXTGLOB 등). 같은 패턴·플래그가 Dir::glob에도 쓰여요.

File.fnmatch('cat',       'cat')                    #=> true
File.fnmatch('c{at,ub}s', 'cats', File::FNM_EXTGLOB) #=> true
File.fnmatch('c?t',       'cat')                    #=> true
File.fnmatch('ca[a-z]',   'cat')                    #=> true
File.fnmatch('cat', 'CAT', File::FNM_CASEFOLD)      #=> true

::join (Public Class Method)

join(string, ...) → string — 문자열들을 "/"로 이어붙인 새 문자열을 돌려줘요.

File.join("usr", "mail", "gumby") #=> "usr/mail/gumby"

::lchmod / ::lchown (Public Class Method)

lchmod(mode_int, file_name, ...) → integer — File::chmod와 같되 심볼릭 링크를 따라가지 않아요(링크가 가리키는 파일이 아니라 링크 자체의 권한을 바꿔요). lchownFile::chown과 같되 링크 자체를 대상으로 해요. 둘 다 없는 플랫폼이 많아요.

link(old_name, new_name) → 0 — 하드 링크를 사용해 기존 파일의 새 이름을 만들어요. new_name이 이미 존재하면 덮어쓰지 않고 예외(SystemCallError 서브클래스)를 발생시켜요. 모든 플랫폼에서 가능하진 않아요.

::lstat (Public Class Method)

lstat(filepath) → stat — File::stat과 같되 마지막 심볼릭 링크를 따라가지 않고, 링크 자체에 대한 File::Stat 객체를 돌려줘요.

File.symlink('t.txt', 'symlink')
File.stat('symlink').size  # => 47
File.lstat('symlink').size # => 5

::lutime / ::utime (Public Class Method)

lutime(atime, mtime, file_name, ...) → integer — 각 파일의 접근·수정 시간을 처음 두 인자로 설정해요. 파일이 심볼릭 링크면 링크 자체에 작용해요(File.utime과 반대). utime은 링크의 대상(referent)에 작용해요. 인자 목록의 파일 이름 수를 돌려줘요.

::mkfifo (Public Class Method)

mkfifo(file_name, mode=0666) → 0 — 이름이 file_name인 FIFO 특수 파일을 만들어요. mode는 권한을 지정하고, 프로세스의 umask로 변경돼요((mode & ~umask)).

::new (Public Class Method)

new(path, mode = 'r', perm = 0666, **opts) → file — 주어진 경로의 파일을 mode에 따라 열고 새 File 객체를 만들어 돌려줘요. 새 File 객체는 filename이 tty가 아니면 버퍼링 모드(또는 non-sync 모드)예요. IO#flush, IO#fsync, IO#fdatasync, IO#sync= 참고. mode(기본 'r')는 유효한 접근 모드여야 하고, perm(기본 0666)은 유효한 권한이어야 해요.

f = File.new('/etc/fstab')
f.close
f = File.new('t.tmp', 'w')
f.close
f = File.new('t.tmp', File::CREAT, 0644)
f.close

::open (Public Class Method)

open(path, mode = 'r', perm = 0666, **opts) → file 또는, 블록을 주면 open(path, ...) {|f| ... } → object — File.new로 새 File 객체를 만들어요. 블록이 없으면 File 객체를 돌려주고, 블록이 있으면 블록을 File 객체로 호출하고 블록의 값을 돌려줘요(블록 종료 시 파일이 닫혀요).

::path (Public Class Method)

path(path) → string — 경로의 문자열 표현을 돌려줘요. path가 문자열이 아니면 to_path 메서드가 있으면 그걸 호출해 변환하고, 그 결과도 문자열이 아니면 표준 to_str 변환을 써요. 변환된 문자열은 ASCII 호환 인코딩이어야 하고(Encoding::CompatibilityError), NUL 문자를 담으면 안 돼요(ArgumentError).

File.path(File::NULL)           #=> "/dev/null"
File.path(Pathname.new("/tmp")) #=> "/tmp"

readlink(link_name) → file_name — 주어진 링크가 가리키는 파일의 이름을 돌려줘요. 모든 플랫폼에서 가능하진 않아요.

File.symlink("testfile", "link2test") #=> 0
File.readlink("link2test")            #=> "testfile"

::realdirpath / ::realpath (Public Class Method)

realdirpath(pathname[, dir_string]) → real_pathname — 실제 파일시스템에서의 실제(절대) 경로명을 돌려줘요. 심볼릭 링크나 의미 없는 점(.)을 포함하지 않아요. 마지막 구성 요소는 존재하지 않아도 돼요. realpath는 모든 구성 요소가 존재해야 해요. dir_string을 주면 상대 경로 해석의 기준 디렉토리로 써요.

::rename (Public Class Method)

rename(old_name, new_name) → 0 — 주어진 파일을 새 이름으로 바꿔요. 바꿀 수 없으면 SystemCallError를 발생시켜요.

File.rename("afile", "afile.bak") #=> 0

::size / ::size? (Public Class Method)

size(file_name) → integer — 파일 크기. size?(file_name) → Integer 또는 nil — 파일이 없거나 크기가 0이면 nil, 그 외 크기 정수. 둘 다 file_name으로 IO 객체를 받을 수 있어요.

::split (Public Class Method)

split(file_name) → array — 문자열을 디렉토리와 파일 구성 요소로 나눠 2-요소 배열로 돌려줘요.

File.split("/home/gumby/.profile") #=> ["/home/gumby", ".profile"]

::stat (Public Class Method)

stat(filepath) → stat — filepath의 파일에 대한 File::Stat 객체를 돌려줘요.

symlink(old_name, new_name) → 0 — 기존 파일 old_name에 대한 심볼릭 링크 new_name을 만들어요. 심볼릭 링크를 지원하지 않는 플랫폼에서는 NotImplemented 예외를 발생시켜요.

::truncate (Public Class Method)

truncate(file_name, integer) → 0 — 파일 file_name을 최대 integer 바이트로 잘라요. 모든 플랫폼에서 가능하진 않아요.

::umask (Public Class Method)

umask() → integer 또는 umask(integer) → integer — 현재 프로세스의 umask 값을 돌려줘요. 선택 인자를 주면 그 값으로 umask를 설정하고 이전 값을 돌려줘요. umask 값은 기본 권한에서 빼지므로, umask 0222는 모든 사람에게 파일을 읽기 전용으로 만들 거예요.

File.umask(0006) #=> 18
File.umask       #=> 6

#atime / #birthtime / #ctime / #mtime (Public Instance Method)

atime → time — self의 마지막 접근 시간(접근된 적 없으면 epoch). birthtime → time — 생성 시간(지원 안 하면 NotImplementedError). ctime → time — 메타데이터 변경 시간(NTFS에서는 생성 시간). mtime → time — 수정 시간.

#chmod / #chown (Public Instance Method)

chmod(mode_int) → 0 — self의 권한 비트를 바꿔요. 심볼릭 링크를 따라가요. chown(owner_int, group_int) → 0 — 소유자와 그룹을 바꿔요. nil 또는 -1 id는 무시돼요.

#flock (Public Instance Method)

flock(locking_constant) → 0 또는 false — 주어진 상수에 따라 self를 잠그거나 풀어요. 모든 플랫폼에서 가능하진 않아요.

상수 잠금 효과
File::LOCK_EX 배타적 한 번에 한 프로세스만 self에 배타 잠금 보유
File::LOCK_NB 논블로킹 블로킹 없음. LOCK_SH/LOCK_EX와 OR로 조합
File::LOCK_SH 공유 여러 프로세스가 동시에 공유 잠금 보유 가능
File::LOCK_UN 해제 이 프로세스가 보유한 기존 잠금 제거

File::LOCK_NB가 지정됐는데 연산이 블로킹됐을 것 같으면 false, 그 외에는 0을 돌려줘요.

# Update a counter using an exclusive lock.
File.open('counter', File::RDWR | File::CREAT, 0644) do |f|
  f.flock(File::LOCK_EX)
  value = f.read.to_i + 1
  f.rewind
  f.write("#{value}\n")
  f.flush
  f.truncate(f.pos)
end

#lstat (Public Instance Method)

lstat → stat — File#stat과 같되 마지막 심볼릭 링크를 따라가지 않고 링크 자체의 File::Stat을 돌려줘요.

#size (Public Instance Method)

size → integer — self의 크기(바이트).

#truncate (Public Instance Method)

truncate(integer) → 0 — self를 최대 integer 바이트로 잘라요. 파일은 쓰기용으로 열려 있어야 해요. 모든 플랫폼에서 가능하진 않아요.

f = File.new("out", "w")
f.syswrite("1234567890") #=> 10
f.truncate(5)            #=> 0
File.size("out")         #=> 5