Home Python 14 - File 1
Post
Cancel

Python 14 - File 1

File I/O

  • 전에 I/O에서 짧게 썼었는데
    찾아보니까 좀 많이 나와서
    전반적으로 다시 써봄

open / close

open

  • open자체는 많은데

    1
    2
    3
    4
    5
    6
    7
    
    open(file: _OpenFile, mode: OpenTextMode = ..., buffering: int = ..., encoding: str | None = ..., errors: str | None = ..., newline: str | None = ..., closefd: bool = ..., opener: _Opener | None = ...) -> TextIOWrapper
    open(file: _OpenFile, mode: OpenBinaryMode, buffering: Literal[0], encoding: None = ..., errors: None = ..., newline: None = ..., closefd: bool = ..., opener: _Opener | None = ...) -> FileIO
    open(file: _OpenFile, mode: OpenBinaryModeUpdating, buffering: Literal[-1, 1] = ..., encoding: None = ..., errors: None = ..., newline: None = ..., closefd: bool = ..., opener: _Opener | None = ...) -> BufferedRandom
    open(file: _OpenFile, mode: OpenBinaryModeWriting, buffering: Literal[-1, 1] = ..., encoding: None = ..., errors: None = ..., newline: None = ..., closefd: bool = ..., opener: _Opener | None = ...) -> BufferedWriter
    open(file: _OpenFile, mode: OpenBinaryModeReading, buffering: Literal[-1, 1] = ..., encoding: None = ..., errors: None = ..., newline: None = ..., closefd: bool = ..., opener: _Opener | None = ...) -> BufferedReader
    open(file: _OpenFile, mode: OpenBinaryMode, buffering: int = ..., encoding: None = ..., errors: None = ..., newline: None = ..., closefd: bool = ..., opener: _Opener | None = ...) -> BinaryIO
    open(file: _OpenFile, mode: str, buffering: int = ..., encoding: str | None = ..., errors: str | None = ..., newline: str | None = ..., closefd: bool = ..., opener: _Opener | None = ...) -> IO
    

    다 볼것같진 않고..

    1
    
    f = open('test.txt', 'r', encoding='utf-8')
    

    보통은 이렇게 씀.

  • 맨 먼저 파일 위치.
  • 다음은 OpenTextMode를 명시하는데

    CharacterMeaning
    ‘r’읽기(기본값)
    ‘w’쓰기. 파일 무조건 새로생성
    ‘x’생성. 이미 존재하는 경우 exception
    ‘a’쓰기. 존재하는 경우 파일 끝에 추가
    ‘b’바이너리 모드
    ‘t’텍스트 모드(기본값)
    ’+’읽기, 쓰기

    모드중 하나 선택하고 +는 선택

    기본은 명시 안하면 자동임.
    따라서 open(filepass)만 하면
    text로 read만.

  • 다음은 인코딩을 쓴다.

close

1
f.close() 

끝나면 꼭 닫도록하자.


r(read)

  • 읽기. 'r'로 연다.
  • 읽는 방법으로
    read(), readline(), readlines()가 있다.

read()

  • 파일 전체를 str로 읽는다.

    1
    
    print(f.read())
    
    1
    2
    3
    4
    5
    
    1111111111
    2222222222
    3333333333
    4444444444
    5555555555
    
  • 읽어올 size를 지정할 수 있다.

    1
    
    print(f.read(15))
    
    1
    2
    
    1111111111
    2222
    

    주의할점은 \n도 포함된 숫자임.

    따라서 각 줄 끝에있는 \n을 생각해야함.

    읽어서 나온 str의 길이라
    한글도 한글자는 1로 쳐줌.
    이 방식이 아마 b모드에서는 다를것같은데
    일단 넘어감.

  • 읽은 후 다시 읽을 때
    이 전 읽은 위치부터 시작

    1
    2
    
    print(f.read(15))
    print(f.read(15))
    
    1
    2
    3
    4
    
    1111111111
    2222
    222222
    33333333
    
  • read자체는 그리 어려울게 없어보이는데
    위에 쓴 몇가지 이유들때문에
    주의할필요가 있어보임.

readline()

  • 파일 한줄을 읽어 str로 반환

    1
    
    print(f.readline())
    
    1
    
    1111111111
    
  • 역시 size를 지정할 수 있음

    1
    
    print(f.readline(3))
    
    1
    
    111
    

    해당 line에서의 size인데
    line size보다 큰 수가 들어가는경우
    그냥 다 읽어오고
    이후 readline에는 영향이 없음.

    readline는 해당 line를 다 읽어오고
    받아볼 buffer크기를 지정한다고 하면
    이해가 빠를듯

  • 역시 읽은 후 다시 읽을 때
    이 전 위치부터 시작.
  • 한줄만 읽기때문에 전체를 읽을라면

    1
    2
    3
    4
    5
    
    while True:
        line = f.readline()
        if not line:
            break
        print(line, end='')
    

    이렇게 해야함.

readlines()

  • 파일을 line별로 읽어
    str list로 반환

    1
    
    print(f.readlines())
    
    1
    
    ['1111111111\n', '2222222222\n', '3333333333\n', '4444444444\n', '5555555555']
    
  • 해서, 제일 좋은방법아닐까싶음.

    1
    2
    3
    
    for line in f.readlines():
        print(line, end='')
        print(line[1:3])
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    1111111111
    11
    2222222222
    22
    3333333333
    33
    4444444444
    44
    555555555555
    

Note 1

  • read하는 방법 3가지 모두
    한번 읽으면 다음은 그 뒤부터 읽는다.
  • 쉽게, header같은게 위치를 갖고 돌다다니면서
    그 위치를 읽는다고 보면 됨.
  • 따라서 파일을 한번 끝까지 읽으면
    다시 처음으로 가서 읽을 수 없다.
  • 아직까진.

w(write)

  • w로 연다.
  • 단순히 r로 열면 쓰기가 안된다.
  • 파일이 없으면 새로 만드는데 주의할점은 이미 파일이 있어도
    해당 파일 이름으로 새로 만든다.

write()

1
2
3
4
5
6
7
8
f = open('test.txt', 'w', encoding='utf-8')

f.write('Hello, world!\n')

slist = ['1\n', '2\n', '3\n', '4\n']

for s in slist:
  f.write(s)

test.txt에는

1
2
3
4
5
Hello, world!
1
2
3
4

일단, w로만 생성한다고 하고,
한번 열린(생성한) 파일에서는
write는 append로 동작하는것처럼 보임.

그러니까 open에서 새 파일이 만들어지고
이후 write는 append처럼 보이는데
쓰는 위치는 무조건 마지막에 쓴 위치기 때문.
이게 open직후에는 그냥 처음으로.
위에서 for을 보면.

writelines()

  • readlines를 반대로
    str list를 file에 써준다.

    1
    2
    3
    4
    5
    6
    7
    
    f = open('test.txt', 'w')
    line = 'string\n'
    lines = ['string1\n', 'string2\n', 'string3\n']
      
    f.write(line)
      
    f.writelines(lines)
    
    1
    2
    3
    4
    
    string
    string1
    string2
    string3
    

Node 2

  • read와 마찬가지로 header가 있다고 하고,
    동작때마다 header의 위치에 적고 뒤로 밀려난다.
  • append로 동작하는건 아니지만 일단
    여기에서 그렇게 보이는건 이런이유때문.
  • 따라서 파일을 읽고 쓰는 모든 작업은
    header가 움직이면서 그 자리에 작업하고
    그만큼 뒤로 밀려나는식이라고 보여진다.
  • 이 특성은 모든 read/write에 적용되기때문에
    이걸 염두해야 좀 보기 편할거임.

a(append)

  • a로 연다.
  • 파일이 없음면 새로 만드는데
    w랑 다른점은
    이미 파일이 있으면 생성하지 않는다.
  • 쓰는 방법도 write()이고,
    쓰는 위치도 똑같다…
    는 같은함수니까…

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    f = open('test.txt', 'a', encoding='utf-8')
      
    f.write('Hello, world!\n')
      
    f.close()
      
    f = open('test.txt', 'a', encoding='utf-8')
      
    slist = ['1\n', '2\n', '3\n', '4\n']
      
    f.writelines(slist)
    

    test.txt에는

    1
    2
    3
    4
    5
    6
    7
    8
    
    Hello, world!1
    2
    3
    4
    Hello, world!1
    2
    3
    4
    

    이렇게 남음.


x(Exclusive Creation)

  • x로 연다.
  • write mode인데
    파일이 없는경우 생성하고
    쓰기모드가 가능.
  • 파일이 이미 있는경우 exception.
  • 이미 파일이 있는경우
    체크하기위해?
  • append면 안됨?

+

  • 기능을 추가한다.
  • 이러나 저러나 OpenTextMode가 뭐가 오건
    read 또는 write였다.
  • 앞에 썼던 기능에 +를 하면
    반대기능이 생긴다.
    다시말해 read랑 write가 가능해진다.
  • 다만 처음 썼던 동작에 의해
    파일을 생성하거나, 그대로 두거나 한다.

r+

  • read하고 쓰기모드인데
    read로 file을 열면
    header위치는 파일내용과 상관없이
    맨 앞으로 된다.
  • 따라서 단순히 read는
    문제가 안된다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    f = open('test.txt', 'w', encoding='utf-8')
      
    f.write('Hello, world!\n')
      
    f.close()
      
    f = open('test.txt', 'r+', encoding='utf-8')
      
    print(f.read())
    
    1
    
    Hello World!
    
  • 조금 다르게 해보자.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    f = open('test.txt', 'w', encoding='utf-8')
      
    f.write('Hello, world!\n')
      
    f.close()
      
    f = open('test.txt', 'r+', encoding='utf-8')
      
    f.write('Good!')
      
    f.close()
      
    f = open('test.txt', 'r+', encoding='utf-8')
      
    print(f.read())
    
    1
    
    Good! World!
    
    • 내용은 바뀔수 있다.
    • 특이한건 open하고 별다른 조작없이
      write를 했는데 앞에부터 바뀜
    • 이건 위에 썼던 열고난직후
      파일 header의 위치에 관한 문제인데
      r+는 open후 파일 header가
      파일의 맨 앞에 위치함.
      이상태에서 write를 하니
      그 위에 덮어쓰게됨.
    • 이걸보면 write는 애초에
      header위치에 그냥 덮어쓰는거였음.
    • 또 위에 코드에서
      close()를 안하고 바로 read()를 하면

      1
      
        World!
      

      가 나와서 Note2에서 쓴게 맞음.

    • 다르게, r+상태에서
      read()를 하고 write()를 하면

      1
      
      Hello World!Good!
      

      가 되었을 것이다.

w+

  • 이 경우 r+보다
    알아보기 쉬운데
    w는 파일을 새로 만들기때문.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    f = open('test.txt', 'w+')
      
    f.write('Good!')
      
    f.close()
      
    f = open('test.txt', 'r')
      
    print(f.read())
    
    1
    
    Good!
    

    그래서 원래 파일에 뭐가 있었건
    위 코드 결과는 무조건 저 하나만 나온다.

a+

  • 기본적으로 파일 생성 기준은 w와 같은데
    파일 header는 open()이후 파일의 맨 끝에 있다.
  • 그래서 특이한점은
    a+는 읽기가 안된다.

    정확히는 안되는것처럼 보인다.
    open()직후부터 header은 맨 뒤로가있고
    write()도 header을 뒤로 보내므로
    read()할 내용이 없기때문이다.

difference

  • + 붙은 옵션에 따라 동작이 다르긴 했는데
    결국엔 header같은게 돌아다니면서
    해당 위치의 데이터를 읽어오는걸
    볼 수 있었다.
  • 최종적으로는 read, write이지만 세부적으로
    header의 위치에 따라 조금씩 차이나는점,
    read(), write()는 header의 위치를
    계속해서 뒤로 밀어낸다는점이
    주의할점으로 보인다.
  • header의 위치에 관해 조금더 보자.

tell

  • 현재 header 위치를 알려준다.

    1
    2
    3
    4
    5
    6
    7
    8
    
    f = open('test.txt', 'w')
    slist = ['a', 'b', 'c','\n']
      
    print(f.tell())
      
    for s in slist:
        f.write(s)
        print(f.tell())
    
    1
    2
    3
    4
    5
    
    0
    1
    2
    3
    5
    
  • 예생했던것처럼
    시작은 0에서 write때마다
    쓰는만큼 늘어난다.
    read도 같을것이다.
  • 좀 특이한건 \n인데
    보이지도 않으면서 2개를 먹음
    쓸때 2글자긴하잖?
    근데 읽을때는 1개로침?

seek

  • header을 움직인다.
  • 설명엔

    1
    
    (method) seek: (__cookie: int, __whence: int = ..., /) -> int
    

    이러는데 __whence는 binary에서만 된다

  • 아무튼 header을 옮기고
    그 위치부터 작업할 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    f = open('test.txt', 'w+', encoding='utf-8')
      
    f.write('Hello, world!\n')
      
    print(f.tell())
      
    print(f.read())
      
    f.seek(0)
      
    print(f.tell())
      
    print(f.read())
    
    1
    2
    3
    4
    
    15
      
    0
    Hello, world!
    

    open-write 까지하면 당연히 read할 내용이 없음
    seek로 header를 옮기고 다시 읽을 수 있음.

  • 다만, 이게 a일때 좀 특이한데

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    f = open('test.txt', 'w', encoding='utf-8')
      
    f.write('Hello, world!\n')
      
    f.close()
      
    f = open('test.txt', 'a+', encoding='utf-8')
      
    print(f.tell())
      
    f.seek(0)
      
    print(f.tell())
      
    f.write('Good!')
      
    f.seek(0)
      
    print(f.read())
    
    1
    2
    3
    4
    
    15
    0
    Hello, world!
    Good!
    

    위에서보면 seek로 header를
    처음으로 돌려놓고 write를 했는데
    끝지점부터 쓰는걸 보면
    appendwrite할 때
    header를 맨 끝으로 강제이동한다.
    다만, readseek 위치부터.

This post is licensed under CC BY 4.0 by the author.

Python 13 - Class 2

Python 15 - File 2

Comments powered by Disqus.