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를 명시하는데
Character Meaning ‘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를 했는데
끝지점부터 쓰는걸 보면
append는write할 때
header를 맨 끝으로 강제이동한다.
다만,read는seek위치부터.
Comments powered by Disqus.