§12. Текстовые и бинарные файлы. Файловый ввод/вывод

Что такое файл?

После окончания работы программы и вывода результатов на дисплей данные будут утрачены безвозвратно, если они не будут записаны и сохранены в долговременной памяти. Для сохранения данных в долговременной памяти используются файлы. Файл (от англ. file) — это именованная область памяти на носителе информации. В программировании различают два типа файлов: текстовые и двоичные (бинарные). Вне зависимости от организации данных в файлах, данные в них представлены в двоичном формате, так что это деление условное. В текстовых файлах данные интерпретируются как последовательность символьных кодов. Специальные последовательности используются для указания признака конца строки. Это позволяет отвлечься от двоичного представления и рассматривать файл, как поток символов, аналогичный стандартному потоку.

Режимы работы с файлом

Для работы с файлами используется специальный объект файла, который содержит в себе функции для открытия, закрытия файлов, чтения и записи данных. Функция open() создает файловый объект (дескриптор) для работы с файлами. Синтаксис функции:

open(file[, mode='r', buffering=-1, encoding=None, errors=None, 
newline=None, closefd=True, opener=None])

Функция принимает следующие аргументы:

  • file – обязательный аргумент строку, содержащую путь к файлу (может быть абсолютным или относительным)
  • mode – режим открытия файла. Режим открытия файла определяет допустимые операции доступа к файлу (см. список ниже)
  • buffering – политика буферизации. Буфер – это область памяти в которой накапливается информация для последующего вывода (или чтения) на стандартное устройство, поскольку данные считываются и записываются блоками.
  • encoding – указание кодировки, если кодировка не указана, то используется кодировка платформы
  • errors – указание как обрабатывать ошибки кодирования/декодирования
  • newline – по умолчанию включен режим универсальной новой строки: любой завершающий символ сводится к '\n'
  • closefd – по умолчанию при закрытии файла, файловый дескриптор будет доступен, иначе – нет
  • opener – указание иной функции открытия файла
Подробнее необязательные аргументы освещаются в документации здесь.
Примечание. Нельзя открывать бинарные файлы (такие как jpeg, exe, doc) в текстовом режиме! Это может привести к тому, что файлы будут испорчены.

Режимы работы с файлом
Режим Описание
w Открыть файл для записи. Если такой файл уже существует, то его содержимое удаляется (если это возможно)
r Открыть файл только для чтения
a Открыть файл для добавления, т.е. записи в конец файла. Предыдущее содержимое файла сохраняется
r+ Открыть файл для записи/чтения, содержимое файла сохраняется
w+ Открыть файл для записи/чтения, содержимое файла удаляется (см. w)
r+b Открыть двоичный (если такие файлы поддерживаются операционной системой) файл для записи/чтения, содержимое файла сохраняется
w+b Открыть двоичный файл для записи/чтения, содержимое файла удаляется (см. w)
rb Открыть двоичный файл только для чтения
wb Открыть двоичный файл для записи. Если такой файл уже существует, то его содержимое удаляется (если это возможно)

Например:

f = open('/tmp/workfile', 'w')

Параметр “режим” необязателен: если он опущен — предполагается, что он равен 'r'.
Программа 12.1 В первой строке файла sum.in записаны два целых числа через пробел. Записать во второй файл (sum.out) сумму этих двух чисел.

fin  = open('sum.in',  'r') # объект связан с файлом из которого будем получать данные
fout = open('sum.out', 'w') # объект связан с файлом в который будем записывать
# Считываем строку файла при помощи метода readline(),
# результат разбиваем на поля по пробельным символам методом split()
# и записываем в список InputData
line = fin.readline().split()
# Теперь в элементах списка line[0] и line[1]
# записаны два входных числа в виде строк.
# Преобразуем их к типу int и запишем их сумму в переменную sum
sum = int(line[0]) + int(line[1])
# Выведем результат в файл, но перед этим преобразуем переменную sum в тип строки (str)
fout.write(str(sum))
# Закроем файлы
fin.close()
fout.close()

Файлы открытые методом open() должны быть закрыты методом close(). Закрывать файл необходимо сразу же после выполнения задач по чтению из файла или записи в файл для синхронизации файловых операций и освобождения системных ресурсов. Для организации кода, связанного с открытием и закрытием файловых объектов, удобно использовать блок try-finally, как показано в программе 12.2.
Другим (более удобным) способом гарантированного закрытия файла является использование инструкции менеджера контекста with-as:

with open('sum.in',  'r') as fin:
	line = fin.readline().split()
#...
with open('sum.out', 'w') as fout:
	fout.write(str(sum))

Файловые методы

С открытым файлом связывается указатель чтения/записи файла. С помощью указателя можно определять текущую позицию чтения файла или определять блок считываемых данных. С указателем работают специальные методы работы с файлом перечисленные ниже.

Методы работы с файлом
Метод Описание
read([число_байт]) Читает из файла, открытого для чтения число байтов, указанных в качестве аргумента. Если метод вызывается без параметров, то читается весь файл, если файл был прочитан до конца (встретился символ EOF), то метод read() возвращает пустую строку
readline() Читает одну строку файла до символа перевода строки (включая сам символ \n). Если строка состоит только из символа перевода строки, то метод readline() возвращает пустую строку. (Если в конце файла нет пустой строки с символом \n, то возвращаемый результат неопределён)
readlines([размер_строки]) Читает все строки файла в список. (Т. е., каждая строка является элементом списка). Читаются только законченные строки. Необязательный параметр размер_строки дополняет читаемую строку, и если она меньше указанной длины читает дальше, до достижения указанного числа символов
write(строка) Пишет в файл указанную строку, возвращая количество записанных символов
seek(на_сколько_байт[, откуда]) Перемещает указатель текущего положения файла на заданное количество байт от позиции, указанной вторым аргументом. (Значение 0 параметра “откуда” – смещение от начала файла, значение 1 применяется для текущей позиции в файле, а значение 2 в качестве точки отсчёта – конец файла. Параметр “откуда” может быть опущен и по умолчанию устанавливается в 0, используя начало файла в качестве точки отсчёта.)
tell() возвращает целое число – текущее положение файлового указателя представленного в виде числа байт от начала файла, если файл открыт в двоичном режиме и число символов, если в текстовом режиме.

Примечание. При работе с текстовыми файлами (открытыми без символа b в строке режима), выполнять позиционирование (seek) позволяется только от начала файла (за исключением прокрутки в конец файла с использованием seek(0, 2)).

Построчное чтение текстового файла

Существует несколько способов организовать построчное чтения файла.

  • Наиболее эффективный способ представлен в программе 12.2 (стр. 7). В цикле for в качестве итерируемого объекта выступает сам файловый дескриптор. Переменная цикла принимает очередную строку на каждом шаге.
    Программа 12.2 Записать в исходный файл input 10 строк в каждой из которых находится случайное число из отрезка [10, 99]. Получить из этого файла данные чтением построчно с суммированием и отправить среднее арифметическое в файл output. (Представить вещественное число в экспоненциальном формате).

    from random import randint
    fin = open('input1', 'w+')
    try:
        for j in range(10):
            fin.write(str(randint(10, 99)) + '\n')
        s = 0
        for j in fin:
            s += int(j)
    finally:
        fin.close()
    fout = open('output1', 'w')
    try:
        fout.write('{:e}'.format(s/10))
    finally:
        fout.close()
    
  • С помощью метода readlines() можно получить список строк файла непосредственно. Тогда перебрать строки можно обычным способом, итерацией по списку.
  • Построчное чтение можно получить и методом readline():
    f = open(file)
    while True:
        line = f.readline()
        if not line:
            break
        # Обработка строки
    f.close()
    

Модуль pickle

Для записи в файл сложных типов данных: кортежи, списки, множества, словари, функции и экземпляры классов можно использовать модуль pickle. Этот модуль позволяет избавить разработчика программы от написания сложных фрагментов кода для работы с файлами. Модуль реализует двоичные протоколы для “консервации” и “расконсервации” структуры объектов. Консервация представляет собой процесс, при котором объект преобразуется в поток байтов, а расконсервация – это обратная операция, в результате которой, поток байтов (из двоичного файла или байт-подобного объекта) преобразуется в объект. Для консервации объектов используется метод dump(). Обратную операцию обеспечивает метод load(). Файлы должны открываться в режимах r+b, w+b, rb и wb, т. е. в режимах бинарных файлов. Например:
Программа 12.3

from pickle import dump, load

data = [['!', '@', '#'],
		[200, 300, 900],
		b'qwertyuiopas',
		'йцукенгшщзхъф']

with open('data', 'wb') as f:
    dump(data, f)

with open('data', 'rb') as f:
    data = load(f)
    
for j in data:
	print(j)

◄ Предыдущий урок | ▲ Содержание | Это последний урок ►
Print Friendly, PDF & Email

Comments are closed