16 분 소요

파이썬에서 파일을 만들어 데이터를 저장하고 파일을 열어 그 안의 데이터를 읽어들이는 방법에 대해서 알아보자.

파일 여는 방법

파일을 읽거나 쓰기 위해선 먼저 파일을 열어(open)야 한다. 파이썬에선 이 기능을 open() 함수를 통해 이용할 수 있다.

file_obj = open(파일이름, 모드)

open() 을 실행하면 그 반환값으로 파일 객체가 생성되어 변수에 할당된다. open()의 첫 번째 인자로 파일 이름을 쓴다. 가령 “제목없음.txt”와 같이 말이다. 두 번째 인자에는 원하는 파일 모드에 해당하는 문자열을 써주면 된다. 두 번째 인자로 들어갈 수 있는 문자열은 ‘rt’와 같이 영어 두 글자이다. 여러 파일 모드가 있는데 다음과 같다.

  • 첫 글자: 기능

  • 두 번째 글자: 파일 종류

문자 기능
r 읽기
w 쓰기. 해당 이름의 파일이 존재하지 않는 경우, 해당 파일을 새로 만든다. 이미 파일이 존재하는 경우 파일 안 내용을 덮어 쓴다.
x 쓰기. 해당 이름의 파일이 존재하지 않을 때만 파일을 생성하여 그 안에 데이터를 쓰도록 해준다.
a 이어 쓰기. 해당 파일이 존재할 경우 파일의 맨 끝 문자열부터 시작하여 이어 쓴다.
문자 종류
t 텍스트 파일 (.txt). 생략해도 해당 모드로 설정됨
b binary 파일

‘rt’의 경우 텍스트 파일을 읽기 모드로 사용하겠단 뜻이다. ‘r’로 해도 마찬가지 의미이다.

파일을 연 후에는 파일 객체의 여러 메서드를 통해 데이터를 읽거나 쓸 수 있다. 그 후, 모든 작업을 마쳤으면 파일을 닫아야 한다(close).

write() 메서드와 함께 텍스트 파일 쓰기

다음은 영어 명언 모음집을 파일에 저장하고자 하는 예제이다.

sayings = '''If you're going through hell, keep going. - Winston Churchill
It does not matter how slowly you go as long as you do not stop. - Confucius
Our greatest weakness lies in giving up.
The most certain way to succeed is always to try just one more time. - Thomas A. Edison'''

file_obj = open('some_sayings.txt', 'wt')  #1
print(file_obj)  #2
print(type(file_obj))  #3
file_obj.write(sayings)  #4
file_obj.close()  #5
<_io.TextIOWrapper name='some_sayings.txt' mode='wt' encoding='cp949'>
<class '_io.TextIOWrapper'>
If you're going through hell, keep going. - Winston Churchill
It does not matter how slowly you go as long as you do not stop. - Confucius
Our greatest weakness lies in giving up.
The most certain way to succeed is always to try just one more time. - Thomas A. Edison

코드를 보면, #1에서 some_sayings.txt란 텍스트 파일을 열 것이며, ‘wt’를 통해 해당 파일을 텍스트 파일에 쓰기 모드로 열 것을 명시하고 있다. 지금은 처음 open() 메서드를 사용하는 것이라 해당 텍스트 파일이 없을 것이므로 해당 코드를 실행시키면 some_sayings.txt란 이름의 텍스트 파일을 새로 생성하고 이를 “쓰기” 모드로 열 것이다. 이렇게 open() 으로 생성된 파일 객체를 file_obj란 변수에 대입하고 있다.

#2, #3에서는 파일 객체를 출력해보고 무슨 자료형인지를 알기 위해 일부러 해당 코드를 삽입해보았다. 실행결과를 보면 알겠지만, name=some_sayings.txt를 통해 해당 이름으로 파일을 생성했다는 것을 알 수 있고, mode=’wt’를 통해 어떤 모드로 파일을 열었는지 확인할 수 있다. 그리고 인코딩 방식도 나타나 있는 것을 확인할 수 있다.

#4에서는 본격적으로 sayings에 할당되어 있던 기나긴 문자열을 파일 객체의 write() 메서드를 이용하여 인자로 삽입하고 있다. 이 메서드가 인자로 들어온 문자열을 텍스트 파일에 쓰는 역할을 한다.

파일과 관련된 일을 다하였다면 마지막에 이 열린 상태의 파일을 꼭 닫아줘야 한다. 이를 수행하는 코드가 #5의 close() 메서드이다.

해당 파이썬 코드를 실행하고 나면 some_sayings.txt란 파일이 생성되고 이 파일 안에 sayings 변수에 있던 문자열이 입력된다. 파일을 open()을 통해 열 때 some_sayings.txt 이름 앞에 어떤 디렉터리 이름을 따로 명시하지 않았기에 해당 텍스트 파일 생성 위치는 위 파이썬 코드 파일과 같은 디렉터리 안이다.

앞서 w 모드는 이미 파일이 존재할 경우 덮어쓴다고 하였다. 이를 확인해보자.

sayings = '어떤 명언이든 당신 자신의 생각이 제일 중요하다.'

file_obj = open('some_sayings.txt', 'wt')
file_obj.write(sayings)
file_obj.close()
� �����̵� ��� ڽ��� ������ ���� �߿��ϴ.

예제 1-2에서 새로운 문자열을 sayings 변수에 할당하고 이를 아까와 똑같은 과정을 거쳐 똑같은 텍스트 파일에 저장하였다. 해당 텍스트 파일을 열어보면 알겠지만 이전에 썼던 문자열들은 사라지고 전혀 다른 문자열들이 저장된 것을 알 수 있다. 그런데 위에서 볼 수 있듯 한 가지 문제가 발생하였다. 한글 문자열을 썼는데 해당 파일에선 깨져보인다. 이는 앞서 예제 1-1의 실행결과를 보면 알 수 있듯 해당 파일의 인코딩 방식은 cp949이었다. 이를 통해 알 수 있는 것은 해당 인코딩 방식은 한글을 지원하지 않는다는 사실이다. 이를 해결하기 위해 open() 메서드에 세 번째 인자로 encoding=’utf-8’을 삽입하고 다시 실행시켜보자.

sayings = '어떤 명언이든 당신 자신의 생각이 제일 중요하다.'

file_obj = open('some_sayings.txt', 'wt', encoding='utf-8') # 인코딩 방식 변경
file_obj.write(sayings)
file_obj.close()
어떤 명언이든 당신 자신의 생각이 제일 중요하다.

이제 텍스트 파일에서 한글도 잘 나옴을 알 수 있다. 이를 통해 알 수 있는 것은 open() 메서드에 따로 인코딩 방식을 명시하지 않는 한 디폴트 값은 cp949란 것을 알 수 있고, 다른 인코딩 방식으로 파일을 열고자 한다면 위 예제처럼 open() 메서드에 encoding=’인코딩’ 형식으로 문자열 형태로 인자를 넣어줘야 한다는 것을 알 수 있다.

파일에 쓸 문자열이 너무 길 경우 문자열을 여러 개의 청크로 나눠 파일에 써도 된다. 다음 예제에서 이를 실행하고 있다.

sayings = '''If you're going through hell, keep going. - Winston Churchill
It does not matter how slowly you go as long as you do not stop. - Confucius
Our greatest weakness lies in giving up.
The most certain way to succeed is always to try just one more time. - Thomas A. Edison'''
size = len(sayings)  #1
print('string size:', size)
offset = 0
chunk = 100  #2
file_obj = open('some_sayings.txt', 'wt')
while True:
    if offset > size:
        break  #2
    file_obj.write(sayings[offset:offset+chunk])  #3
    offset += chunk  #4
    print(offset)

file_obj.close()
string size: 267
100
200
300

#1에서 먼저 해당 문자열의 길이를 확인하고 있다. 실행결과를 보면 알겠지만 총 길이는 267이다. 이제 이 긴 문자열을 여러 개의 동일한 청크로 쪼갤 것이다. 한 청크에 담길 문자열은 100으로 설정하였다. 즉, 267의 길이를 갖는 이 문자열을 100개씩 쪼개어 하나씩 파일에 쓸 것이란 의미이다.

while 반복문 안에서 #3을 보면 한 청크에 해당하는 길이를 문자열에서 슬라이싱하여 write() 메서드에 넘김으로써 파일에 한 청크씩 문자열을 쓰는 모습이다. 처음에는 offset 변수를 0으로 할당하였으므로 0번째 문자부터 99번째 문자까지가 슬라이싱 되어 한 청크가 되고, 이 청크가 파일에 쓰여질 것이다. 그 다음 청크를 지정하기 위해 #4에서 offset 변수에 chunk, 즉 100을 더한다. 이로써 현재 offset을 0에서 100으로 지정하였다. 그러면 다음 반복에서 if문을 거칠 것이고, 아직 문자열 전체 크기 size를 넘지 않았기에 #3 코드를 또 실행시킬 것이다. 이 때는 인덱스 100부터 199까지의 문자열이 슬라이싱되어 파일에 이어서 저장이 될 것이다. 이를 문자열 모두 저장될 때까지 반복되고, offset이 size를 넘어설 때 비로소 반복문이 끝나며 파일 쓰기도 모두 완료하게 된다.

앞선 예제들에선 write() 메서드로 텍스트 데이터들을 텍스트 파일에 쓰는 것을 확인하였다. 그런데 사실 write() 메서드 말고도 print() 함수만으로도 텍스트 파일에 데이터를 입력할 수 있다. print() 함수에 file=파일객체 를 써주면 해당 텍스트 파일에 문자열을 쓸 수 있다.

sayings = '''If you're going through hell, keep going. - Winston Churchill
It does not matter how slowly you go as long as you do not stop. - Confucius
Our greatest weakness lies in giving up.
The most certain way to succeed is always to try just one more time. - Thomas A. Edison'''

file_obj = open('some_sayings.txt', 'wt')
#file_obj.write(sayings)
print(sayings, file=file_obj)
file_obj.close()
If you're going through hell, keep going. - Winston Churchill
It does not matter how slowly you go as long as you do not stop. - Confucius
Our greatest weakness lies in giving up.
The most certain way to succeed is always to try just one more time. - Thomas A. Edison

write() 메서드와의 차이점은 print() 함수 사용시 전체 문자열 맨 끝에 개행 문자 \n을 추가해서 맨 마지막에 빈 줄이 생성된다는 것이다. 그리고 지금 예제에서는 기나긴 문자열을 하나로 묶어 인자로 전달하였지만, print() 함수 사용 시 기나긴 문자열을 여러 개로 쪼개서 파일에 쓸 경우 각 줄마다 공백문자 ‘ ‘가 추가된다고 한다. 만약 이런게 싫다면 어떻게 해야 할까? print() 함수에 sep과 end 매개변수를 이용하면 된다.

  • sep: seperator, 공백 문자 ‘ ‘가 디폴트 값으로 설정되어 있다.
  • end: 전체 문자열의 끝 부분 처리. 개행 문자 ‘\n’가 디폴트 값으로 설정되어 있다.

위 사실을 이용하여 이번에는 print() 함수를 써도 공백문자나 개행 문자가 자동으로 추가되지 않도록 해보자.

sayings = '''If you're going through hell, keep going. - Winston Churchill
It does not matter how slowly you go as long as you do not stop. - Confucius
Our greatest weakness lies in giving up.
The most certain way to succeed is always to try just one more time. - Thomas A. Edison'''

file_obj = open('some_sayings.txt', 'wt')
print(sayings, file=file_obj, sep='', end='')
file_obj.close()
If you're going through hell, keep going. - Winston Churchill
It does not matter how slowly you go as long as you do not stop. - Confucius
Our greatest weakness lies in giving up.
The most certain way to succeed is always to try just one more time. - Thomas A. Edison

직접 파이썬 코드를 실행하여 생성된 텍스트 파일을 직접 보면 차이점을 알 수 있을 것이다.

read(), readline(), readlines() 메서드로 텍스트 파일 읽어오기

이제 앞서 작성한 파일을 읽어오도록 해보자. 파일을 읽는 파일 객체 메서드로 다음이 존재한다.

method 기능
read() 파일 내 전체 문자열을 읽어온다.
readline() 파일 내 한 줄의 문자열만을 읽어온다.
readlines() 파일 내 전체 문자열을 읽어오되, 각 줄을 요소로 갖는 list로 반환한다.

read() : 한꺼번에 전체 문자열 읽어오기

먼저 read() 메서드를 예제로 살펴보자.

file_obj = open('some_sayings.txt', 'rt')
sayings = ''
count = 0
while True:
    line = file_obj.read()
    if not line:
        break
    sayings += line
    count += 1
file_obj.close()
print(sayings)
print('count:', count)
If you're going through hell, keep going. - Winston Churchill
It does not matter how slowly you go as long as you do not stop. - Confucius
Our greatest weakness lies in giving up.
The most certain way to succeed is always to try just one more time. - Thomas A. Edison 
count: 1

실행결과에 count: 1을 보면 알 수 있듯, read() 메서드는 한 번에 파일 내 모든 문자열을 읽어들여 반환하는 것을 알 수 있다.

위 예제의 코드 구조를 설명하자면, while True 무한 루프를 이용하여 파일 내 모든 문자열을 여러 번 걸리더라도 모두 읽어오도록 설계하였다. 그 후 무한 루프 첫 줄에 read() 메서드를 통해 파일 내 문자열을 읽어들여 이를 line 변수에 할당하도록 하였다. 그 후 이를 sayings란 변수에 뒤에 이어 붙이는 형식으로 문자열을 대입하고 있다. 이 무한 루프를 실행하면 read() 메서드를 통해 파일 내 모든 문자열을 읽어온 후에는 read() 메서드는 빈 문자열 ‘’을 읽어온다. 빈 문자열은 False이고, 이제 더 이상 파일로부터 읽어올 데이터가 없다는 뜻이므로 이를 이용하여 if문을 구성하여 break문을 통해 무한 루프를 빠져나가도록 설계하였다.

read() 메서드에 숫자를 인자로 넣으면 앞서 write()에서 전체 문자열을 여러 청크로 쪼개서 파일에 저장했던 것처럼 전체 문자열을 여러 개로 나눠서 파일로부터 읽어들여올 수 있다. 위 예제에서 read() 메서드에 100을 넣어서 전체 문자열을 100개로 쪼개서 읽어들이도록 해보자.

file_obj = open('some_sayings.txt', 'rt')
sayings = ''
count = 0
while True:
    line = file_obj.read(100)
    if not line:
        break
    sayings += line
    count += 1
file_obj.close()
print(sayings)
print('count:', count)
If you're going through hell, keep going. - Winston Churchill
It does not matter how slowly you go as long as you do not stop. - Confucius
Our greatest weakness lies in giving up.
The most certain way to succeed is always to try just one more time. - Thomas A. Edison 
count: 3

실행결과 마지막 줄을 보면 알 수 있듯 이번에는 파일로부터 총 3번에 걸쳐 문자열을 읽어온 것을 확인할 수 있다. 위 예제에서는 파일에 있는 문자열을 변형없이 그대로 읽어오려는 목적으로 sayings += line 코드를 삽입하였기에 언뜻보면 차이를 못 느낄 것이다. 다음 예제를 보면 read()에 숫자를 인자로 넘김으로서 전체 문자열 중 일부만 읽어오는 것을 더 확실히 알 수 있다.

file_obj = open('some_sayings.txt', 'rt')
sayings = file_obj.read(100)
file_obj.close()
print(sayings)
If you're going through hell, keep going. - Winston Churchill
It does not matter how slowly you go a

readline() : 한 줄만 읽어오기

file_obj = open('some_sayings.txt', 'rt')
sayings = ''
count = 0
while True:
    line = file_obj.readline()
    if not line:
        break
    sayings += line
    count += 1
file_obj.close()
print(sayings)
print('count:', count)
If you're going through hell, keep going. - Winston Churchill
It does not matter how slowly you go as long as you do not stop. - Confucius
Our greatest weakness lies in giving up.
The most certain way to succeed is always to try just one more time. - Thomas A. Edison 
count: 4

이번에는 readline() 메서드를 이용하였다. 특징은 한 번에 한 줄만 읽어온다는 것이다. 이러한 특징을 다음 예제에서 더 잘 보여주고 있다.

file_obj = open('some_sayings.txt', 'rt')
sayings = file_obj.readline()
file_obj.close()
print(sayings)
print(len(sayings))
If you're going through hell, keep going. - Winston Churchill

62

readline()은 파일 내 전체 문자열 중 한 줄만 가져오므로 위 실행결과처럼 문자열의 맨 끝에 개행문자 \n도 포함되어 있음을 알 수 있다.

한 편, readline() 메서드에도 숫자를 인자로 넘길 수 있다. 한 줄을 읽어올 때 몇 개의 문자까지만 읽어올 것인지를 제한시켜주는 기능을 한다.

file_obj = open('some_sayings.txt', 'rt')
sayings = file_obj.readline(20)
file_obj.close()
print(sayings)
print(len(sayings))
If you're going thro
20

readlines() : 전체 문자열을 한 줄씩 나눠 list로 반환

file_obj = open('some_sayings.txt', 'rt')
sayings = file_obj.readlines()
file_obj.close()
print(sayings)
print(len(sayings))
["If you're going through hell, keep going. - Winston Churchill\n", 'It does not matter 
how slowly you go as long as you do not stop. - Confucius\n', 'Our greatest weakness lies in giving up.\n', 'The most certain way to succeed is always to try just one more time. - Thomas A. Edison']
4

readlines()는 위에서 알 수 있듯, 파일 내 전체 문자열을 읽어온 뒤, 각 줄을 하나의 요소로 하는 list로 반환한다.

file_obj = open('some_sayings.txt', 'rt')
sayings = file_obj.readlines()
file_obj.close()
for line in sayings:
    print(line, end='')
If you're going through hell, keep going. - Winston Churchill
It does not matter how slowly you go as long as you do not stop. - Confucius
Our greatest weakness lies in giving up.
The most certain way to succeed is always to try just one more time. - Thomas A. Edison

위 예제는 파일에 있던 문자열을 원래대로 복원하여 출력하는 코드이다. 예제 5-1의 실행결과를 보면 알겠지만, 각 줄의 맨 끝에 개행문자 \n이 있으므로 위 예제에서는 print() 에 end=’’를 넣어 print() 함수로 인해 더해지는 개행문자를 방지하였다.

readlines() 메서드에 숫자를 인자로 넘기면 어떻게 될까?

file_obj = open('some_sayings.txt', 'rt')
sayings = file_obj.readlines(1)
file_obj.close()
print(sayings)
print(len(sayings[0]))
["If you're going through hell, keep going. - Winston Churchill\n"]
62

1을 대입한 결과, 첫 번째 줄만 읽어온 것을 알 수 있다.

file_obj = open('some_sayings.txt', 'rt')
sayings = file_obj.readlines(62)
file_obj.close()
print(sayings)
print(len(sayings[0]))
["If you're going through hell, keep going. - Winston Churchill\n", 'It does not matter 
how slowly you go as long as you do not stop. - Confucius\n']
62

이번에는 첫 줄의 길이인 62를 그대로 대입해보았다. 그 결과 두 번째 줄까지 읽어온 것을 알 수 있다. 이를 통해 추측할 수 있는 것은, readlines() 메서드로 대입된 숫자만큼의 길이를 읽어온다는 것이다. 이 때 첫 줄의 길이보다 짧은 숫자를 대입하면 첫 줄만 읽어오고, 첫 줄의 길이보단 크나 첫 줄과 두 번째 줄을 합친 길이보단 작은 숫자를 대입하면 두 번째 줄까지 읽어오는 형식이다. (근데 이 기능은 실무에서 쓰일 일이 있을 지 의문이다. 메서드에 대입한 숫자만큼만 읽어오는 것도 아니라서 이 기능을 어떻게 활용할지가 애매해보인다)

파일 객체로부터 직접 문자열 읽어오기

한 편, 어떠한 메서드를 사용하지 않고 파일 객체로부터 직접 문자열을 읽어올 수 있다. 이를 위해 for문을 이용할 수 있다.

sayings = ''
say_list = []
file_obj = open('some_sayings.txt', 'rt')
for line in file_obj:
    sayings += line
    say_list.append(line)
file_obj.close()
print(sayings)
print(say_list)
If you're going through hell, keep going. - Winston Churchill
It does not matter how slowly you go as long as you do not stop. - Confucius
Our greatest weakness lies in giving up.
The most certain way to succeed is always to try just one more time. - Thomas A. Edison 
["If you're going through hell, keep going. - Winston Churchill\n", 'It does not matter 
how slowly you go as long as you do not stop. - Confucius\n', 'Our greatest weakness lies in giving up.\n', 'The most certain way to succeed is always to try just one more time. - Thomas A. Edison']

위 예제에서 say_list는 문자열을 읽어오는 과정을 이해하기 위해 의도적으로 넣은 변수이다. 위 예제로부터 추측할 수 있는 점은, file_obj라는 파일 객체로부터 직접 한 줄씩 문자열을 읽어올 수 있다는 점이다.

with 구문을 이용하여 파일 자동으로 닫기

파일을 열 때마다 항상 마지막엔 close() 메서드를 코드에 삽입해서 파일을 닫아야 했다. 해당 메서드를 직접 코드에 작성하지 않고도 자동으로 파일을 닫게 해주는 방법이 있으니, with 구문이다.

with open('some_sayings.txt', 'rt') as file_obj:
    sayings = file_obj.read()

print(sayings)
If you're going through hell, keep going. - Winston Churchill
It does not matter how slowly you go as long as you do not stop. - Confucius
Our greatest weakness lies in giving up.
The most certain way to succeed is always to try just one more time. - Thomas A. Edison

with 구문을 벗어나면 파일은 자동으로 닫힌다.

파일 내 커서 위치: tell(), seek()

파일을 읽거나 쓸 때 파이썬은 내가 파일의 어느 위치에서 읽거나 쓰는지를 계속 파악한다. 글이 쓰여진 메모장에 현재 커서가 어디에 위치해 있는지를 파악한다는 것이다. 파이썬에서는 이와 관련하여 파일 속 현재 커서 위치를 알려주는 tell() 함수와, 현재 커서 위치를 바꿔주는 seek() 함수를 제공한다.

tell() 함수는 현재 커서 위치를 반환해준다. 다음은 예제 3-2 코드를 조금 가공하였고, tell() 함수를 넣어 파일 내 문자열을 100개씩 읽을 때마다 그 때의 커서가 어디있었는지를 파악하고 있다.

with open('some_sayings.txt', 'rt') as file_obj:
    sayings = ''
    count = 0
    while True:
        line = file_obj.read(100)
        if not line:
            break
        sayings += line
        count += 1
        print(file_obj.tell())

print(sayings)
print('count:', count)
101
203
270
If you're going through hell, keep going. - Winston Churchill
It does not matter how slowly you go as long as you do not stop. - Confucius
Our greatest weakness lies in giving up.
The most certain way to succeed is always to try just one more time. - Thomas A. Edison 
count: 3

위 실행결과의 첫 3줄이 바로 파일 속 커서가 있던 위치이다. 파일을 읽어들일 때 마치 인터넷 기사글에서 몇 번째 줄의 몇 번째 문자부터 몇 번째 문자까지 마우스로 드래그하고 복사하여 다른 곳에 붙여넣기 하는 것마냥(?) 현재 위치로부터 100개의 문자열을 읽어들이는 것이다. 그 후 커서는 100개의 문자 뒤에 위치할 것이다.

때로는 파일의 맨 첫 문자열부터 읽어들이는 게 아니라 내가 원하는 중간 지점부터 읽어들이고 싶을 때도 있을 것이다. 마치 인터넷 기사에서 특정 위치의 글을 마우스로 드래그하고 복사, 붙여넣기 할 때 글의 맨 처음부터 드래그 하진 않듯이 말이다. (기사 전체를 복사할 게 아니라면 말이다) 또는 글을 작성할 때 가끔 글의 중간 부분을 고쳐쓰듯이 내가 원하는 위치에서 문자를 첨삭하고자 할 때도 있을 것이다. 이럴 때 현재 커서 위치를 변경시켜주는 seek() 함수를 쓸 수 있다.

다음은 현재 커서 위치를 100으로 설정한 뒤에 예제 8-1를 실행시킨 모습이다.

with open('some_sayings.txt', 'rt') as file_obj:
    sayings = ''
    count = 0
    file_obj.seek(100)  # seek() 메서드 추가
    while True:
        line = file_obj.read(100)
        if not line:
            break
        sayings += line
        count += 1
        print(file_obj.tell())

print(sayings)
print('count:', count)
202
270
as long as you do not stop. - Confucius
Our greatest weakness lies in giving up.
The most certain way to succeed is always to try just one more time. - Thomas A. Edison 
count: 2

예제 8-1과 달리 이번에는 글의 중간부터 읽어들였음을 알 수 있다. 예제 8-1에서는 파일의 첫 시작 위치인 0부터 시작하였기에 파일 내 모든 문자열을 읽어들일 수 있었던 것이었다.

seek() 함수의 더 자세한 사용법은 다음과 같다.

  • seek(offset, origin)
origin에 들어갈 숫자 기능
0 (디폴트 값) 파일의 시작 위치로부터 offset만큼 뒤로 간다.
1 파일 내 현재 커서 위치로부터 offset만큼 뒤로 간다. (텍스트 파일이 아닌 binary 파일에서만 가능)
2 파일의 맨 끝 위치로부터 offset만큼 앞으로 간다.

0, 1, 2처럼 숫자로 표현하면 해당 숫자가 seek() 함수 내에서 어떤 기능을 할지 잘 감이 안잡힐 수 있다. 이를 명시적으로 하기 위해 os모듈을 import하여 다음과 같이 대체할 수 있다.

  • os 모듈
이름 대응되는 숫자
os.SEEK_SET 0
os.SEEK_CUR 1
os.SEEK_END 2

이를 예제로 활용해보자. 먼저 두 번째 인자로 0을 넣을 때이다.

with open('some_sayings.txt', 'rt') as file_obj:
    file_obj.seek(100, 0)
    sayings = file_obj.read()

print(sayings)
as long as you do not stop. - Confucius
Our greatest weakness lies in giving up.
The most certain way to succeed is always to try just one more time. - Thomas A. Edison

앞서 언급했듯 사실 seek(100)과 다를 바 없다. 위 예제에서 import os를 첫 줄에 쓰고 0대신 os.SEEK_SET을 넣어도 똑같은 결과를 낳는다.

1, 2 옵션은 텍스트 파일이 아닌 binary 파일 모드일 때에만 사용 가능하다. 해당 옵션을 텍스트 파일에서 실행시키면 오류가 발생한다. 그래서 다음 예제에서는 우선 같은 파일을 ‘rb’를 통해 binary 파일로 읽어들인 후에 실행시킬 것이다. 다음 예제는 1 옵션을 사용한 경우이다.

import os
with open('some_sayings.txt', 'rb') as file_obj:
    file_obj.seek(100, os.SEEK_SET)
    file_obj.seek(50, os.SEEK_CUR)
    latest_cursor = file_obj.tell()
    sayings = file_obj.read()

print(sayings)
print(latest_cursor)
b'est weakness lies in giving up.\r\nThe most certain way to succeed is always to try just one more time. - Thomas A. Edison'
150

실행결과의 맨 앞에 b가 붙은 것은 해당 데이터가 byte 데이터임을 명시한다.

다음은 2 옵션을 사용하는 경우이다.

import os
with open('some_sayings.txt', 'rb') as file_obj:
    file_obj.seek(-100, os.SEEK_END)
    latest_cursor = file_obj.tell()
    sayings = file_obj.read()

print(sayings)
print(latest_cursor)
b' giving up.\r\nThe most certain way to succeed is always to try just one more time. - 
Thomas A. Edison'
170

해당 옵션은 파일의 맨 끝을 가리키도록 하기 때문에 맨 끝에서 앞의 문자들을 읽어들이고자 하는 경우 seek() 메서드의 첫 번째 인수에 - (마이너스) 기호를 붙여야 한다.


References

[1] Bill Lubannovic, “Introducing Python” (O’REILLY, 2015)

[2] 파일 읽고 쓰기, 점프 투 파이썬

점프 투 파이썬

[3]

https://stackoverflow.com/questions/53001901/unsupportedoperation-cant-do-nonzero-cur-relative-seeks-python

This content is licensed under CC BY-NC 4.0

댓글남기기