Чтение данных из файла и запись в файл

Создание файла

В Python, чтобы создать файл, надо его открыть в режиме записи ('w', 'wb') или дозаписи ('a', 'ab').

f2 = open("text2.txt", 'w')

Функция open() возвращает файловый объект.

Без 'b' создается текстовый файл, представляющий собой поток символов. С 'b' - файл, содержащий поток байтов.

В Python также существует режим 'x' или 'xb'. В этом режиме проверяется, есть ли файл. Если файл с определенным именем уже существует, он не будет создан. В режиме 'w' файл создается заново, старый при этом теряется.

>>> f1 = open('text1.txt', 'w')
>>> f2 = open('text1.txt', 'x')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
FileExistsError: [Errno 17] File exists: 'text1.txt'
>>> f3 = open('text1.txt', 'w')

Чтение данных из файла

Если в функцию open() не передается второй аргумент, файл расценивается как текстовый и открывается на чтение.

Попытка открыть на чтение несуществующий файл вызывает ошибку.

>>> f = open("text10.txt")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: 'text10.txt'

Перехватить возникшее исключение можно с помощью конструкции try-except.

>>> try:
...     f = open("text10.txt")
... except IOError:
...     print ("No file")
...
No file

Получить все данные из файла можно с помощью метода read() файлового объекта, предварительно открыв файл на чтение. При этом файловый объект изменяется и получить из него данные еще раз не получится.

>>> f = open("text.txt")
>>> f
<_io.TextIOWrapper name='text.txt' mode='r' encoding='UTF-8'>
>>> fd = f.read()
>>> fd1 = f.read()
>>> fd
'Hello\n\tOne\n   Two\nThree Four\nШесть!\n'
>>> fd1
''

Если файл был открыт в текстовом режиме, то метод read() возвращает строку. В случае бинарного режима возвращается объект типа bytes.

>>> f = open('text.txt', 'rb')
>>> content = f.read()
>>> type(content)
<class 'bytes'>
>>> content
b'HelloHello'
>>> content[0]
72
>>> chr(content[0])
'H'

Методу read() может быть передан один аргумент, обозначающий количество символов (если файл был открыт как текстовый) или байт (если файл был открыт как бинарный) для чтения.

>>> f = open("text.txt")
>>> fd = f.read(10)
>>> fd1 = f.read(5)
>>> fd
'Hello\n\tOne'
>>> fd1
'\n   T'

Метод readline() позволяет получать данные построчно.

>>> f = open("text.txt")
>>> f.readline()
'Hello\n'
>>> f.readline()
'\tOne\n'
>>> f.readline()
'   Two\n'

Принимает аргумент - число байт или символов.

>>> f.readline(3)
'Thr'
>>> f.readline(3)
'ee '
>>> f.readline(3)
'Fou'
>>> f.readline(3)
'r\n'
>>> f.readline(5)
'Шесть'
>>> f.readline(5)
'!\n'

Для построчного чтения данных из файла рекомендуется использовать цикл for:

>>> f = open('text.txt')
>>> for line in f:
...     print(line, end='')
...
Hello!
The second line.
>>> f.close()

Метод readlines() считывает все строки и помещает их в список.

>>> f = open("text.txt")
>>> fd = f.readlines()
>>> fd
['Hello\n', '\tOne\n', '   Two\n', 'Three Four\n', 'Шесть!\n']

Может принимать количество символов, но дочитывает строку до конца.

>>> f = open("text.txt")
>>> fd = f.readlines(3)
>>> fd
['Hello\n']
>>> fd1 = f.readlines(6)
>>> fd1
['\tOne\n', '   Two\n']

Запись данных в файл

Записать данные в файл можно с помощью метода write(), который возвращает число записанных символов или байтов.

>>> ft = open('text1.txt', 'w')
>>> fb = open('text2.txt', 'wb')
>>> t = 'Привет Мир!'
>>> b = b'Hello World!'
>>> type(t), type(b)
(<class 'str'>, <class 'bytes'>)
>>> ft.write(t)
11
>>> fb.write(b)
12
>>> ft.close()
>>> fb.close()
>>>
>>> import os.path
>>> os.path.getsize('text1.txt')
20
>>> os.path.getsize('text2.txt')
12
>>> open('text2.txt').read()
'Hello World!'

Если записываемые в текстовый файл данные не являются строкой, то их предварительно надо преобразовать в строку.

>>> a = [1, 2, 3, 4]
>>> sa = str(a)
>>> sa
'[1, 2, 3, 4]'
>>> f = open('mylist.txt', 'w')
>>> f.write(sa)
12
>>> f.close()
>>>
>>> with open('mylist.txt') as f:
...     sa = f.read()
...
>>> sa
'[1, 2, 3, 4]'
>>> list(sa)  # bad idea
['[', '1', ',', ' ', '2', ',', ' ', '3', ',', ' ', '4', ']']
>>> a = [int(i) for i in sa if i.isdigit()]
>>> a
[1, 2, 3, 4]

С помощью метода writelines() можно записать в файл итерируемую последовательность.

>>> a = [1,2,3,4,5,6,7,8,9,0]
>>> f = open("text2.txt",'w')
>>> f.writelines("%s\n" % i for i in a)
>>> f.close()
>>> open("text2.txt").read()
'1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n'
>>> print(open("text2.txt").read())
1
2
3
4
5
6
7
8
9
0

Смена позиции в файле

Метод tell() возвращает текущую позицию в файле. Позицию можно менять с помощью метода seek().

>>> f = open('text.txt')
>>> f.tell()
0
>>> f.readline()
'Hello!\n'
>>> f.tell()
7
>>> f.seek(5)
5
>>> f.read(1)
'!'
>>> f.tell()
6
>>> f.read()
'\nThe second line.\n'
>>> f.read()
''
>>> f.seek(0)
0
>>> f.read()
'Hello!\nThe second line.\n'

В случае бинарных файлов в метод seek() можно передавать второй аргумент, который указывает, с какого места выполняется смещение, указанное в первом аргументе: 0 (по умолчанию) - от начала файла, 1 - с текущей позиции, 2 - с конца.

>>> f = open('text.txt', 'rb')
>>> f.read()
b'Hello!\nThe second line.\n'
>>> f.seek(-6, 2)
18
>>> f.read(4)
b'line'
>>> f.seek(0)
0
>>> f.read(5)
b'Hello'
>>> f.seek(2, 1)
7
>>> f.read(3)
b'The'

Закрытие файла

В Python следует закрывать файл для высвобождения системных ресурсов. Делается это с помощью метода close() файлового объекта.

С помощью closed (не константа, а так называемый дескриптор, или описатель, данных) проверяют, закрыт файл или нет.

>>> f = open('text.txt')
>>> f.closed
False
>>> f.close()
>>> f.closed
True

Считается хорошей практикой использовать оператор with при обработке файловых объектов. После того как тело with завершит работу, файл автоматически будет закрыт. При работе with создается так называемый контекстный менеджер, представляющий собой особый объект. Благодаря ему сохраняются и восстанавливаются глобальные состояния, происходит блокировка и разблокировка ресурсов, закрываются открытые файлы и др.

>>> with open('text.txt') as f:
...     print(f.read())
...
HelloHello
>>> f.closed
True
>>> with open('text.txt') as fr, open('text2.txt', 'w') as fw:
...     fw.write(fr.read())
...
10
>>> fw.closed
True
>>> with (
...     open('text.txt') as fr,
...     open('text2.txt', 'w') as fw,
... ):
...     fw.write(fr.read())
...
10

Двоичные файлы

Пример копирования изображения:

>>> f1 = open('flag.png', 'rb')
>>> f2 = open('flag2.png', 'wb')
>>> f2.write(f1.read())
446
>>> f1.close()
>>> f2.close()

Модуль struct позволяет преобразовывать данные к бинарному виду и обратно.

>>> f = open('text3.txt', 'wb')
>>> f.write('3')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' does not support the buffer interface
>>> d = struct.pack('>i',3)
>>> d
b'\x00\x00\x00\x03'
>>> f.write(d)
4
>>> f.close()
>>> f = open('text3.txt')
>>> d = f.read()
>>> d
'\x00\x00\x00\x03'
>>> struct.unpack('>i',d)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' does not support the buffer interface
>>> f = open('text3.txt', 'rb')
>>> d = f.read()
>>> d
b'\x00\x00\x00\x03'
>>> struct.unpack('>i',d)
(3,)