Функция open. Чтение и запись текстовых файлов в Python
Большие объемы данных хранят не в списках или словарях, а в файлах и базах данных. В этом уроке изучим особенности работы с текстовыми файлами в Python. Такие файлы рассматриваются как содержащие символы и строки.
Бывают еще байтовые (бинарные) файлы, которые рассматриваются как потоки байтов. Побайтово считываются, например, файлы изображений. Работа с бинарными файлами несколько сложнее. Нередко их обрабатывают с помощью специальных модулей Python (pickle, struct).
Функция open
Связь с файлом на жестком диске выполняется с помощью встроенной в Python функции open() . Обычно ей передают один или два аргумента. Первый – имя файла или имя с адресом, если файл находится не в том каталоге, где находится сама программа. Второй аргумент – режим, в котором открывается файл.
Обычно используются режимы чтения ( ‘r’ ) и записи ( ‘w’ ). Если файл открыт в режиме чтения, то запись в него невозможна. Можно только считывать данные. Если файл открыт в режиме записи, то в него можно только записывать данные, считывать нельзя.
Если файл открывается в режиме ‘w’ , то все данные, которые в нем были до этого, стираются. Файл становится пустым. Если не надо удалять существующие в файле данные, тогда следует использовать вместо режима записи, режим дозаписи ( ‘a’ ).
Если файл отсутствует, то открытие его в режиме ‘w’ создаст новый файл. Бывают ситуации, когда надо гарантировано создать новый файл, избежав случайной перезаписи данных существующего. В этом случае вместо режима ‘w’ используется режим ‘x’ . В нем всегда создается новый файл для записи. Если указано имя существующего файла, то будет выброшено исключение. Потери данных в уже имеющемся файле не произойдет.
Если при вызове open() второй аргумент не указан, то файл открывается в режиме чтения как текстовый файл. Чтобы открыть файл как байтовый, дополнительно к букве режима чтения/записи добавляется символ ‘b’ . Буква ‘t’ обозначает текстовый файл. Поскольку это тип файла по умолчанию, то обычно ее не указывают.
Нельзя указывать только тип файла, то есть open(«имя_файла», ‘b’) есть ошибка, даже если файл открывается на чтение. Правильно – open(«имя_файла», ‘rb’) . Только текстовые файлы мы можем открыть командой open(«имя_файла») , потому что и ‘r’ и ‘t’ подразумеваются по-умолчанию.
Функция open() возвращает объект файлового типа. Его надо либо сразу связать с переменной, чтобы не потерять, либо сразу прочитать.
Чтение файла
С помощью файлового метода read() можно прочитать файл целиком или только определенное количество байт. Пусть у нас имеется файл data.txt с таким содержимым:
one - 1 - I two - 2 - II three - 3 - III four - 4 - IV five - 5 - V
Откроем его и почитаем:
>>> f1 = open(‘data.txt’) >>> f1.read(10) ‘one — 1 — ‘ >>> f1.read() ‘I\ntwo — 2 — II\nthree — 3 — III\nfour — 4 — IV\nfive — 5 — V\n’ >>> f1.read() » >>> type(f1.read())
Сначала считываются первые десять символов. Последующий вызов read() считывает весь оставшийся текст. После этого объект файлового типа f1 становится пустым.
Заметим, что метод read() возвращает строку, и что конец строки считывается как ‘\n’ .
Для того, чтобы читать файл построчно существует метод readline() :
>>> f1 = open('data.txt') >>> f1.readline() 'one - 1 - I\n' >>> f1.readline() 'two - 2 - II\n' >>> f1.readline() 'three - 3 — III\n'
Метод readlines() считывает сразу все строки и создает список:
>>> f1 = open('data.txt') >>> f1.readlines() ['one - 1 - I\n', 'two - 2 - II\n', 'three - 3 - III\n', 'four - 4 - IV\n', 'five - 5 - V\n']
Объект файлового типа относится к итераторам. Из таких объектов происходит последовательное извлечение элементов. Элементами в данном случае являются строки-линии файла. Поэтому считывать данные из файла можно сразу в цикле без использования методов чтения:
>>> for i in open('data.txt'): . print(i) . one - 1 - I two - 2 - II three - 3 - III four - 4 - IV five - 5 - V >>>
Здесь выводятся лишние пустые строки, потому что функция print() преобразует ‘\n’ в переход на новую строку. К этому добавляет свой переход на новую строку. Создадим список строк файла без ‘\n’ :
>>> nums = [] >>> for i in open('data.txt'): . nums.append(i[:-1]) . >>> nums ['one - 1 - I', 'two - 2 - II', 'three - 3 - III', 'four - 4 - IV', 'five - 5 - V']
Переменной i присваивается очередная строка файла. Мы берем ее срез от начала до последнего символа, не включая его. Следует иметь в виду, что ‘\n’ это один символ, а не два.
Запись в файл
Запись в файл выполняется с помощью методов write() и writelines() . Во второй можно передать структуру данных:
>>> l = ['tree', 'four'] >>> f2 = open('newdata.txt', 'w') >>> f2.write('one') 3 >>> f2.write(' two') 4 >>> f2.writelines(l)
Метод write() возвращает количество записанных символов.
Закрытие файла
После того как работа с файлом закончена, важно не забывать его закрыть, чтобы освободить место в памяти. Делается это с помощью файлового метода close() . Свойство файлового объекта closed позволяет проверить закрыт ли файл.
>>> f1.close() >>> f1.closed True >>> f2.closed False
Если файл открывается в заголовке цикла ( for i in open(‘fname’) ), то видимо интерпретатор его закрывает при завершении работы цикла или через какое-то время.
Практическая работа
- Создайте файл data.txt по образцу урока. Напишите программу, которая открывает этот файл на чтение, построчно считывает из него данные и записывает строки в другой файл ( dataRu.txt ), заменяя английские числительные русскими, которые содержатся в списке ( [«один», «два», «три», «четыре», «пять»] ), определенном до открытия файлов.
- Создайте файл nums.txt , содержащий несколько чисел, записанных через пробел. Напишите программу, которая подсчитывает и выводит на экран общую сумму чисел, хранящихся в этом файле.
Примеры решения и дополнительные уроки в pdf-версии курса
X Скрыть Наверх
Python. Введение в программирование
Организация ввода и вывода данных с использованием файлов
Внимание! Все тесты в этом разделе разработаны пользователями сайта для собственного использования. Администрация сайта не проверяет возможные ошибки, которые могут встретиться в тестах.
Тест для 10 класса по теме: «Организация ввода и вывода данных с использованием файлов». У вас есть 15 минут. Результаты отправлять не нужно.
Система оценки: 5 балльная
Список вопросов теста
Вопрос 1
Сколько байтов памяти занимает признак конца строки в текстовом файле?
Вопрос 2
Без пробелов запишите условие описанного цикла для считывания массива чисел из файла?
Вопрос 3
В каком виде хранятся данные на устройствах внешней памяти?
Варианты ответов
- В виде информационных структур
- В виде программ
- В виде файлов
- В виде текста
Вопрос 4
Какое количество памяти занимает один символ в текстовом файле?
Варианты ответов
- 1 бит
- 1 байт
- 6 байт
- 2 байта
Вопрос 5
Укажите верный порядок следования операторов в программе?
Укажите порядок следования всех 4 вариантов ответа:
Варианты ответов
- assign (f, s)
- reset (f)
- read (f, s)
- close (f)
Вопрос 6
Что будет записано в файл f при выполнении оператора writeln ( f )?
Выберите один из 4 вариантов ответа:
Варианты ответов
- Признак EOLN
- Пробел
- Ничего
- Признак EOF
Вопрос 7
Укажите соответствие между операторами и их описаниями.
Укажите соответствие для всех 4 вариантов ответа:
1) Назначает файловой переменной файл с указанным названием
2) Закрывает файл
3) Считывает данные из текстового файла, соответствующего переменной f
4) Открывает текстовый файл для чтения
Назначает файловой переменной файл с указанным названием
Считывает данные из текстового файла, соответствующего переменной f
Открывает текстовый файл для чтения
Варианты ответов
- assign (f, s)
- close (f)
- readln (f, s)
- reset (f)
Вопрос 8
При помощи какого оператора текстовый файл открывается для перезаписи?
Выберите один из 4 вариантов ответа:
Варианты ответов
- assign (f, s)
- eoln (f)
- rewrite (f)
- close (f)
Вопрос 9
Какие разновидности файлов существуют?
Выберите несколько из 4 вариантов ответа:
Варианты ответов
- Текстовые
- Рекурсивные
- Типизированные
- Нетипизированные
Вопрос 10
Какой тип в языке Pascal имеет файловая переменная, для обращения к текстовому файлу?
Выберите один из 4 вариантов ответа:
Ввод данных из файла и вывод в файл
До этого при вводе-выводе данных мы работали со стандартными потоками — клавиатурой и монитором. Теперь рассмотрим, как в языке C реализовано получение данных из файлов и запись их туда. Перед тем как выполнять эти операции, надо открыть файл и получить доступ к нему.
В языке программирования C указатель на файл имеет тип FILE и его объявление выглядит так:
FILE *myfile;
С другой стороны, функция fopen() открывает файл по указанному в качестве первого аргумента адресу в режиме чтения («r»), записи («w») или добавления («a») и возвращает в программу указатель на него. Поэтому процесс открытия файла и подключения его к программе выглядит примерно так:
myfile = fopen("hello.txt", "r");
Примечание. В случае использования относительной адресации текущим/рабочим каталогом в момент исполнения программы должен быть тот, относительно которого указанный относительный адрес корректен. Место нахождения самого исполняемого файла не важно.
При чтении или записи данных в файл обращение к нему осуществляется посредством файлового указателя (в данном случае, myfile).
Если в силу тех или иных причин (нет файла по указанному адресу, запрещен доступ к нему) функция fopen() не может открыть файл, то она возвращает NULL. В реальных программах почти всегда обрабатывают ошибку открытия файла в ветке if , мы же далее опустим это.
Объявление функции fopen() содержится в заголовочном файле stdio.h, поэтому требуется его подключение. Также в stdio.h объявлен тип-структура FILE.
После того, как работа с файлом закончена, принято его закрывать, чтобы освободить буфер от данных и по другим причинам. Это особенно важно, если после работы с файлом программа продолжает выполняться. Разрыв связи между внешним файлом и указателем на него из программы выполняется с помощью функции fclose() . В качестве параметра ей передается указатель на файл:
fclose(myfile);
В программе может быть открыт не один файл. В таком случае каждый файл должен быть связан со своим файловым указателем. Однако если программа сначала работает с одним файлом, потом закрывает его, то указатель можно использовать для открытия второго файла.
Чтение из текстового файла и запись в него
fscanf()
Функция fscanf() аналогична по смыслу функции scanf() , но в отличии от нее осуществляет форматированный ввод из файла, а не стандартного потока ввода. Функция fscanf() принимает параметры: файловый указатель, строку формата, адреса областей памяти для записи данных:
fscanf(myfile, "%s%d", str, &a);
Возвращает количество удачно считанных данных или EOF. Пробелы, символы перехода на новую строку учитываются как разделители данных.
Допустим, у нас есть файл содержащий такое описание объектов:
apples 10 23.4 bananas 5 25.0 bread 1 10.3
Тогда, чтобы считать эти данные, мы можем написать такую программу:
#include int main () { FILE *file; struct food { char name[20]; unsigned qty; float price; }; struct food shop[10]; char i=0; file = fopen("fscanf.txt", "r"); while (fscanf(file, "%s%u%f", shop[i].name, &(shop[i].qty), &(shop[i].price)) != EOF) { printf("%s %u %.2f\n", shop[i].name, shop[i].qty, shop[i].price); i++; } }
В данном случае объявляется структура и массив структур. Каждая строка из файла соответствует одному элементу массива; элемент массива представляет собой структуру, содержащую строковое и два числовых поля. За одну итерацию цикл считывает одну строку. Когда встречается конец файла fscanf() возвращает значение EOF и цикл завершается.
fgets()
Функция fgets() аналогична функции gets() и осуществляет построчный ввод из файла. Один вызов fgets() позволят прочитать одну строку. При этом можно прочитать не всю строку, а лишь ее часть от начала. Параметры fgets() выглядят таким образом:
fgets(массив_символов, количество_считываемых_символов, указатель_на_файл)
fgets(str, 50, myfile)
Такой вызов функции прочитает из файла, связанного с указателем myfile, одну строку текста полностью, если ее длина меньше 50 символов с учетом символа ‘\n’, который функция также сохранит в массиве. Последним (50-ым) элементом массива str будет символ ‘\0’, добавленный fgets() . Если строка окажется длиннее, то функция прочитает 49 символов и в конце запишет ‘\0’. В таком случае ‘\n’ в считанной строке содержаться не будет.
#include #define N 80 main () { FILE *file; char arr[N]; file = fopen("fscanf.txt", "r"); while (fgets(arr, N, file) != NULL) printf("%s", arr); printf("\n"); fclose(file); }
В этой программе в отличие от предыдущей данные считываются строка за строкой в массив arr. Когда считывается следующая строка, предыдущая теряется. Функция fgets() возвращает NULL в случае, если не может прочитать следующую строку.
getc() или fgetc()
Функция getc() или fgetc() (работает и то и другое) позволяет получить из файла очередной один символ.
#include #define N 80 int main () { FILE *file; char arr[N]; int i; file = fopen("fscanf.txt", "r"); while ((arr[i] = fgetc(file)) != EOF) { if (arr[i] == '\n') { arr[i] = '\0'; printf("%s\n",arr); i = 0; } else i++; } arr[i] = '\0'; printf("%s\n",arr); fclose(file); }
Приведенный в качестве примера код выводит данные из файла на экран.
Запись в текстовый файл
Также как и ввод, вывод в файл может быть различным.
- Форматированный вывод. Функция fprintf ( файловый_указатель, строка_формата, переменные ) .
- Посточный вывод. Функция fputs ( строка, файловый_указатель ) .
- Посимвольный вывод. Функция fputc() или putc( символ, файловый_указатель ) .
Ниже приводятся примеры кода, в которых используются три способа вывода данных в файл.
Запись в каждую строку файла полей одной структуры:
#include int main () { FILE *file; struct food { char name[20]; unsigned qty; float price; }; struct food shop[10]; char i=0; file = fopen("fprintf.txt", "w"); while (scanf("%s%u%f", shop[i].name, &(shop[i].qty), &(shop[i].price)) != EOF) { fprintf(file, "%s %u %.2f\n", shop[i].name, shop[i].qty, shop[i].price); i++; } fclose(file); }
Построчный вывод в файл ( fputs() , в отличие от puts() сама не помещает в конце строки ‘\n’):
while (gets(arr) != NULL) { fputs(arr, file); fputs("\n", file); }
Пример посимвольного вывода:
while ((i = getchar()) != EOF) putc(i, file);
Чтение из двоичного файла и запись в него
С файлом можно работать не как с последовательностью символов, а как с последовательностью байтов. В принципе, с нетекстовыми файлами работать по-другому не возможно. Однако так можно читать и писать и в текстовые файлы. Преимущество такого способа доступа к файлу заключается в скорости чтения-записи: за одно обращение можно считать/записать существенный блок информации.
При открытии файла для двоичного доступа, вторым параметром функции fopen() является строка «rb» или «wb».
Тема о работе с двоичными файлами достаточно сложная, для ее изучения требуется отдельный урок. Здесь будут отмечены только особенности функций чтения-записи в файл, который рассматривается как поток байтов.
Функции fread() и fwrite() принимают в качестве параметров:
- адрес области памяти, куда данные записываются или откуда считываются,
- размер одного данного какого-либо типа,
- количество считываемых данных указанного размера,
- файловый указатель.
Эти функции возвращают количество успешно прочитанных или записанных данных. Т.е. можно «заказать» считывание 50 элементов данных, а получить только 10. Ошибки при этом не возникнет.
Пример использования функций fread() и fwrite() :
#include #include int main () { FILE *file; char shelf1[50], shelf2[100]; int n, m; file = fopen("shelf1.txt", "rb"); n=fread(shelf1, sizeof(char), 50, file); fclose(file); file = fopen("shelf2.txt", "rb"); m=fread(shelf2, sizeof(char), 50, file); fclose(file); shelf1[n] = '\0'; shelf2[m] = '\n'; shelf2[m+1] = '\0'; file = fopen("shop.txt", "wb"); fwrite(strcat(shelf2,shelf1), sizeof(char), n+m, file); fclose(file); }
Здесь осуществляется попытка чтения из первого файла 50-ти символов. В n сохраняется количество реально считанных символов. Значение n может быть равно 50 или меньше. Данные помещаются в строку. То же самое происходит со вторым файлом. Далее первая строка присоединяется ко второй, и данные сбрасываются в третий файл.
- Напишите программу, которая запрашивает у пользователя имя (адрес) текстового файла, далее открывает его и считает в нем количество символов и строк.
- Напишите программу, которая записывает в файл данные, полученные из другого файла и так или иначе измененные перед записью. Каждая строка данных, полученная из файла, должна помещаться в структуру.
Курс с решением части задач:
pdf-версия
При помощи какого оператора текстовый файл открывается для перезаписи
Procedure Reset(Var F [ : File; Recsize : Word ] );
Режим
Windows, Real, Protected
Замечания
Параметр F — переменная любого файлового типа, связанная с внешним файлом, с использованием процедуры Assign. Параметр RecSize — необязательный параметр, который может быть определен только, если F — нетипизированный файл. В этом случае, RecSize определяет размер блока, который нужно использовать при передаче данных. Если RecSize опущен, принят заданный по умолчанию размер блока в 128 байт.
Reset открывает существующий внешний файл с именем, назначенным в переменной F. Происходит ошибка, если внешний файл с данным именем не существует. Если файл F уже открыт, то он сначала закрывается, а затем вновь открывается. Текущая позиция указателя устанавливается на начало файла.
Если переменной F назначено пустое имя, например Assign(F, »), то после обращения к Reset, переменная F будет относиться к стандартному входному файлу (стандартный номер дескриптора = 0).
Если F — текстовый файл, то он открывается только на чтение. После обращения к Reset, Eof(F) = True, если файл пуст, иначе Eof (F) = False.
В режиме < $I- > функция IOResult вернет 0, если операция была успешна, иначе, она возвращает отличный от нуля код ошибки.
FileMode
Если F не является текстовым (типизированный или нетипизированный), файл открывается на чтение и запись, либо только на чтение, в зависимости от значения переменной FileMode 2 или 0, соответственно.
- С одной стороны, переменная FileMode слабо задокументирована. В TURBO.TPH можно найти FileMode через алфавитный указатель , но в документации к Reset эта переменная вообще не упоминается.
- С другой стороны, в большинстве версий Pascal (не только Turbo, но ещё и Delphi и TMT Pascal) она по умолчанию равна 2 (чтение и запись).
- С третьей стороны, программы, открывающие бинарный файл при помощи Reset, обычно только читают из файла.
Всё это в совокупности приводит к тому, что программисты используют Reset, чтобы открыть файл на чтение, у программистов всё работает, потому что есть доступ на запись. Проблема остаётся незамеченной и обнаруживается только тогда, когда файл у пользователя по какой–то причине доступен только для чтения. Например, потому что записан на CD-ROM или сетевой диск без доступа на запись. Если в режиме FileMode = 2 файл не удалось открыть на чтение и запись, файл не открывается совсем, и программа завершается аварийно или работает некорректно. Из–за недостаточной задокументированности FileMode проблема возникла даже у программистов фирмы Borland. InitGraph открывает BGI драйвер при помощи Reset и, если к BGI драйверу нет доступа на запись, графику инициализировать не удаётся. Будучи записаны на CD-ROM, ваши графические программы перестают работать. Проблема старая, но до сих пор актуальная. Например, она встречалась в Ёжиках в Quake II , написанных на Delphi.
По всем этим соображениям в School Pak по умолчанию значение этой переменной изменено на 0, но это может привести к обратным последствиям: в файлы, открытые Reset, не удаётся ничего записать.
Чтобы ни в одной из версий Pascal не возникало ни той, ни другой проблемы, всегда перед Reset и InitGraph устанавливайте значение FileMode на нужное.
См. также
Пример
Язык:
Русский
English
