Возможно ли считать из файла информации больше чем там сохранено
Текстовыми называют файлы, состоящие из любых символов. Они организуются по строкам, каждая из которых заканчивается символом "конец строки". Конец самого файла обозначается символом " конец файла ". При записи информации в текстовый файл , просмотреть который можно с помощью любого текстового редактора, все данные преобразуются к символьному типу и хранятся в символьном виде.
Для работы с файлами используются специальные типы данных, называемые потоками 4 Вообще говоря, потоки являются классами, которым будет посвящена специальная глава. . Поток ifstream служит для работы с файлами в режиме чтения. Поток ofstream служит для работы с файлами в режиме записи. Для работы с файлами в режиме как чтения, так и записи служит поток iofstream .
В программах на C++ при работе с текстовыми файлами необходимо подключать библиотеки iostream и fstream .
Для того, чтобы записать данные в текстовый файл , необходимо:
- Описать переменную типа ofstream.
- Открыть файл с помощью функции open.
- Вывести информацию в файл.
- Закрыть файл.
Для того, чтобы считать данные из текстового файла, необходимо:
- Описать переменную типа ifstream.
- Открыть файл с помощью функции open.
- Считать информацию из файла, при считывании каждой порции данных необходимо проверять достигнут ли конец файла.
- Закрыть файл.
7.2.1 Запись информации в текстовый файл
Для того, чтобы начать работать с текстовым файлом, необходимо описать переменную типа ofstream . Например, с помощью оператора
ofstream F; 5 Далее термин "поток" будет использоваться для указания переменной, описанной как ofstream, ifstream, iofstream , а термин "файл" для указания реального файла на диске.
будет создана переменная F для записи информации в файл. На следующем этапе файл необходимо открыть для записи. В общем случае оператор открытия потока будет иметь вид:
Здесь F — переменная, описанная как ofstream, file — имя файла на диске, mode — режим работы с открываемым файлом.
Файл может быть открыт в одном из следующих режимов:
- ios::in — открыть файл в режиме чтения данных, этот режим является режимом по умолчанию для потоков ifstream;
- ios::out — открыть файл в режиме записи данных (при этом информация в существующем файле уничтожается), этот режим является режимом по умолчанию для потоков ofstream ;
- ios::app — открыть файл в режиме записи данных в конец файла;
- ios::ate — передвинуться в конец уже открытого файла;
- ios::trunc — очистить файл, это же происходит в режиме ios::out;
- ios::nocreate — не выполнять операцию открытия файла, если он не существует 6 При открытии файла в режиме ios::in происходит как раз обратное, если файл не существует, он создаётся ;
- ios::noreplace — не открывать существующий файл.
Параметр mode может отсутствовать, в этом случае файл открывается в режиме по умолчанию для данного потока 7 ios::in — для потоков ifstream, ios::out — для потоков ofstream . .
После удачного открытия файла (в любом режиме) в переменной F будет храниться true , в противном случае false . Это позволит проверять корректность операции открытия файла.
Открыть файл (в качестве примера возьмём файл abc.txt ) в режиме записи можно одним из следующих способов:
После открытия файла в режиме записи будет создан пустой файл, в который можно будет записывать информацию. Если нужно открыть файл, чтобы в него что-либо дописать, то в качестве режима следует использовать значение ios::app .
После открытия файла в режиме записи, в него можно писать точно также, как и на экран, только вместо стандартного устройства вывода cout необходимо указать имя открытого для записи файла.
Например, для записи в поток F переменной a оператор вывода будет иметь вид:
Для последовательного вывода в поток G переменных b, c и d оператор вывода станет таким:
Закрытие потока осуществляется с помощью оператора:
В качестве примера рассмотрим следующую задачу.
Задача 7.1. Создать текстовый файл abc.txt и записать туда n вещественных чисел.
Текст программы с комментариями:
Обратите внимание, что в текстовый файл записываются не только вещественные числа, но и символы табуляции. Таким образом, в конце файла после последнего числа находится символ табуляции. По этой причине может возникнуть проблема при чтении информации (п. 7.2.2), так как символ табуляции будет интерпретирован как вещественное число. Чтобы этого избежать в программе была применена следующая конструкция:
Здесь реализована проверка ввода последнего числа. После него символ табуляции отсутствует.
В результате работы программы будет создан текстовый файл abc.txt , который можно просмотреть средствами обычного текстового редактора (рис. 7.1,рис. 7.2).
7.2.2 Чтение информации из текстового файла
Для того, чтобы прочитать информацию из текстового файла, необходимо описать переменную типа ifstream . После этого файл необходимо открыть для чтения с помощью оператора open . Если переменную назвать F , то первые два оператора будут такими:
8 Указание режима ios::in можно, конечно, опустить, ведь для потока ifstream значение ios::in является значением по умолчанию, тогда оператор open можно будет записать так F.open("abc.txt");
После открытия файла в режиме чтения, из него можно считывать информацию точно так же, как и с клавиатуры, только вместо стандартного устройства ввода cin необходимо указать имя потока, из которого будет происходить чтение данных.
Например, для чтения из потока F в переменную a оператор ввода будет иметь вид:
Для последовательного ввода из потока G в переменные b, с и d оператор ввода станет таким:
Два числа в текстовом файле считаются разделёнными, если между ними есть хотя бы один из символов: пробел, табуляция, символ конца строки.
Хорошо, если программисту заранее известно, сколько и каких значений хранится в текстовом файле. Однако часто просто известен тип значений, хранящихся в файле, при этом количество значений в файле может быть различным. При решении подобной проблемы необходимо считывать значения из файла по одному, а перед каждым считыванием проверять, достигнут ли конец файла. Для проверки, достигнут или нет конец файла, служит функция
Здесь F — имя потока, функция возвращает логическое значение: true — если достигнут конец файла, если не достигнут функция возвращает значение false .
Следовательно, цикл для чтения содержимого всего файла можно записать так.
Рассмотрим следующую задачу.
Задача 7.2. В текстовом файле хранятся вещественные числа (рис. 7.2), вывести их на экран и вычислить их количество.
Текст программы с комментариями приведён ниже.
Результат работы программы к задаче 7.2:
Программа работает корректно, если текстовый файл abc.txt был создан с помощью программы к задаче 7.1. Предположим, что файл создавался в текстовом редакторе, и пользователь ввёл после последней цифры символ пробела, табуляции или перехода на новую строку. Тогда результат будет таким:
Происходит это потому, что после чтения последней цифры из потока конец файла не достигнут, оператор цикла выполняется ещё один раз, значение переменной увеличивается на единицу, а так как значение переменной не изменилось, то выводится повторно. Один из способов решения данной проблемы может быть таким:
Если количество вещественных чисел, записанных в файл, известно заранее, то текст программы можно переписать следующим образом:
Существует возможность открывать файл с данными таким образом, чтобы в него можно было дописывать информацию. Рассмотрим эту возможность на примере решения следующей задачи.
Задача 7.3. В файле (рис. 7.2) хранится массив вещественных чисел, дописать в файл этот же массив, упорядочив его по возрастанию.
Алгоритм решения задачи очень простой. Считываем в массив данные из текстового файла, упорядочиваем массив, дописываем его в этот же файл.
Для чтения данных из файла описываем поток ifstream , открываем его в режиме чтения и последовательно, пока не достигнем конца файла, считываем все элементы в массив. Сортировку проведём методом пузырька. Обратите внимание, что поток нужно открыть так, чтобы была возможность дописать в конец файла упорядоченный массив.
Пишу простенькую программу по криптографии. В результате шифрования получается txt файлик с набором закорючек(он во вложении). Для дешифрования надо файл обратно считать, а он считывает первые 72 символа нормально, а дальше нули одни. Причем до этого обычный текст нормально считывал тем же методом
считывал так
начал тестить для других текстов и выявил странную закономерность: перестает считывать после определенного символа. а именно "". Может кто-нибудь подскажет как решить эту проблему?
Переполнение при считывании из файла
Подскажите пожалуйста, где ошибка, вот код чтения из файла: void read_file(void) < int mass;.
Странная вещь при считывании файла
надо считать матрицу из текстового файла в класс, но с некоторого момента из файла уже ничего не.
При считывании из файла не выводится отчество
Необходимо прочитать из файла фамилию студента, имя и отчество. И вывеси на экран фамилию и.
Переполнение строки при считывании из файла
Считываю я строки из файла, в котором их 500 тысяч. Если строка начинается на R, то я записываю её.
нашел как избавиться от проблемы, правда суть так и не понял. На вашем же форуме была уже такая тема Считывание данных из файла
з.ы. через гугл искал - но тот как символ этот видел, сразу кучу каркозяблей выдавал. А яндекс норм нашел
Есть подозрение, что вы шифруете так, что какой то символ преобразуется в символ, который в виндоус, считается символом конца файла - вот и заканчивается работа.
KuKu, согласен. При написании Лабы по методам и средствам защиты информации, во время считывания зашифрованного файла, вставала именно такая проблема. Один из символов, при шифровании преобразовывался в символ конца файла. И файл не считывался до конца. Все зависело от вводимого пароля
Ну например, если открывать и закрывать файл в текстовом, а не в бинарном режиме, и с помощью eof попытаться считать зашифрованный файл до конца - может ничего не выйти. Т.к. она возвращает true после прочтения маркера конца файла. И в зависимости от пароля и типа преобразований, файл может считаться полностью, может несколько строк, а может вообще несколько символов.
Ну если не как символы читать то получилось сделать, а после тестов понял, что стрелочка действительно интерпретируется как конец файла. Единственная проблема осталась в том, что у меня класс с шифрованием поддерживает как входной массив char *data, а из поля richTextBox я считываю строку типа String^. И при перекодировании иногда символы меняются. Из-за этого после цикла расшифровки-зашифровки начальный и конечный тексты не совпадают на пару символов.
При записи информации в двоичный файл символы и числа записываются в виде последовательности байт.
Для того чтобы записать данные в двоичный файл, необходимо:
- описать файловую переменную типа FAIL * с помощью оператора FILE *filename, здесь filename — имя переменной, где будет храниться указатель на файл.
- открыть файл с помощью функции fopen
- записать информацию в файл с помощью функции fwrite
- закрыть файл с помощью функции fclose
Для того чтобы считать данные из двоичного файла, необходимо:
- описать переменную типа FILE *
- открыть файл с помощью функции fopen
- считать необходимую информацию из файла с помощью функции fread, при этом следить за тем достигнут ли конец файла.
- закрыть файл с помощью функции fclose
Рассмотрим основные функции, необходимые для работы с двоичными файлами.
Для открытия файла предназначена функция fopen.
FILE *fopen(const *filename, const char *mode)
Здесь filename — строка, в которой хранится полное имя открываемого файла, mode — строка, определяющая режим работы с файлом; возможны следующие значения:
- «rb» — открываем двоичный файл в режиме чтения;
- «wb» — создаем двоичный файл для записи; если он существует, то его содержимое очищается;
- «ab» — создаем или открываем двоичный файл для дозаписи в конец файла;
- «rb+» — открываем существующий двоичный файл в режиме чтения и записи;
- «wb+» — открываем двоичный файл в режиме чтения и записи, существующий файл очищается;
- «ab+» — двоичный файл открывается или создается для исправления существующий информации и добавления новой в конец файла.
Функция возвращает в файловой переменной f значение NULL в случае неудачного открытия файла. После открытия файла доступен 0-й его байт, указатель файла равен 0, значение которого по мере чтения или записи смещается на считанное (записанное) количество байт. Текущие значение указателя файла — номер байта, начиная с которого будет происходить операция чтения или записи.
Для закрытия файла предназначена функция fclose:
int fclose(FILE *filename);
Она возвращает 0 при успешном закрытие файла и EOF в противном случае.
Функция remove предназначена для удаления файлов:
int remove(const char *filename);
Эта функция удаляет с диска файл с именем filenema. Удаляемый файл должен быть закрыт. Функция возвращает ненулевое значение, если файл не удалось удалить.
Для переименования файлов предназначена функция rename:
int rename(const char *oldfilename, const char *newfilename);
Первый параметр — старое имя файла, второй — новое. Возвращает 0 при удачном завершении программы.
Чтение из двоичного файла осуществляется с помощью функции fread:
fread(void *ptr, size, n, FILE *filename);
Функция fread считывает из файла filename в массив ptr n элементов размера size. Функция возвращает количество считанных элементов. После чтения из файла его указатель смещается на n*size байт.
Запись в двоичный файл осуществляется с помощью функции fwrite:
fwrite(const void *ptr, size, n, FILE *filename);
Функция fwrite записывает в файл filename из массива ptr n элементов размера size. Функция возвращает количество записанных элементов. После записи информации в файл указатель смещается на n*size байт.
Для контроля достижения конца файла есть функция feof:
int feof(FILE *filename);
Она возвращает ненулевое значение если достигнут конец файла.
Для более точного усвоения материала предлагаю рассмотреть пару стандартных задач.
Запись информации в текстовый файл
Как было сказано ранее, для того чтобы начать работать с текстовым файлом, необходимо описать переменную типа ofstream. Например, так:
ofstream F;
Будет создана переменная F для записи информации в файл. На следующим этапе файл необходимо открыть для записи. В общем случае оператор открытия потока будет иметь вид:
F.open(«file», mode);
Здесь F — переменная, описанная как ofstream, file — полное имя файла на диске, mode — режим работы с открываемым файлом. Обратите внимание на то, что при указании полного имени файла нужно ставить двойной слеш. Для обращения, например к файлу accounts.txt, находящемуся в папке sites на диске D, в программе необходимо указать: D:\\sites\\accounts.txt.
Файл может быть открыт в одном из следующих режимов:
- ios::in — открыть файл в режиме чтения данных; режим является режимом по умолчанию для потоков ifstream;
- ios::out — открыть файл в режиме записи данных (при этом информация о существующем файле уничтожается); режим является режимом по умолчанию для потоков ofstream;
- ios::app — открыть файл в режиме записи данных в конец файла;
- ios::ate — передвинуться в конец уже открытого файла;
- ios::trunc — очистить файл, это же происходит в режиме ios::out;
- ios::nocreate — не выполнять операцию открытия файла, если он не существует;
- ios::noreplace — не открывать существующий файл.
Параметр mode может отсутствовать, в этом случае файл открывается в режиме по умолчанию для данного потока.
После удачного открытия файла (в любом режиме) в переменной F будет храниться true, в противном случае false. Это позволит проверить корректность операции открытия файла.
Открыть файл (в качестве примера возьмем файл D:\\sites\\accounts.txt) в режиме записи можно одним из следующих способов:
//первый способ
ofstream F ;
F. open ( «D: \\ sites\\accounts.txt» , ios :: out ) ;
//второй способ, режим ios::out является режимом по умолчанию
//для потока ofstream
ofstream F ;
F. open ( «D: \\ game \\ noobs.txt» ) ;
//третий способ объединяет описание переменной и типа поток
//и открытие файла в одном операторе
ofstream F ( «D: \\ game \\ noobs.txt» , ios :: out ) ;
После открытия файла в режиме записи будет создан пустой файл, в который можно будет записывать информацию.
Если вы хотите открыть существующий файл в режиме дозаписи, то в качестве режима следует использовать значение ios::app.
После открытия файла в режиме записи, в него можно писать точно так же, как и на экран, только вместо стандартного устройства вывода cout необходимо указать имя открытого файла.
Например, для записи в поток F переменной a, оператор вывода будет иметь вид:
Для последовательного вывода в поток G переменных b, c, d оператор вывода станет таким:
Закрытие потока осуществляется с помощью оператора:
F.close();
В качестве примера рассмотрим следующую задачу.
Задача 2
В текстовом файле D:\\game\\accounts.txt хранятся вещественные числа, вывести их на экран и вычислить их количество.
Задача 1
Создать двоичный файл D:\\game\\noobs.dat и записать в него целое число n и n вещественных чисел.
Задача 1
Создать двоичный файл D:\\game\\noobs.dat и записать в него целое число n и n вещественных чисел.
Задача 3
В созданном раннее двоичном файле D:\\game\\noobs.dat, поменять местами наибольшее и наименьшее из вещественных чисел.
Алгоритм решения задачи состоит из следующих этапов:
- чтение вещественных из файла в массив a.
- поиск в массиве а максимального (max) и минимального (min) значения и их номеров (imax, imin).
- перемещения указателя файла к максимальному значению и запись min.
- перемещения указателя файла к минимальному значению и запись max.
Ниже приведен текст программы решения задачи с комментариями.
Итак, мы рассмотрели основные принципы работы с файлами в C++. В следующих уроках они вам еще встретятся, поэтому усвойте их как можно лучше.
Файлы позволяют пользователю считывать большие объемы данных непосредственно с диска, не вводя их с клавиатуры. Существуют два основных типа файлов: текстовые и двоичные.
Текстовыми называются файлы, состоящие из любых символов. Они организуются по строкам, каждая из которых заканчивается символом «конца строки». Конец самого файла обозначается символом «конца файла». При записи информации в текстовый файл, просмотреть который можно с помощью любого текстового редактора, все данные преобразуются к символьному типу и хранятся в символьном виде.
В двоичных файлах информация считывается и записывается в виде блоков определенного размера, в которых могут храниться данные любого вида и структуры.
Для работы с файлами используются специальные типы данных, называемые потоками. Поток ifstream служит для работы с файлами в режиме чтения, а ofstream в режиме записи. Для работы с файлами в режиме как записи, так и чтения служит поток fstream.
В программах на C++ при работе с текстовыми файлами необходимо подключать библиотеки iostream и fstream.
Для того чтобы записывать данные в текстовый файл, необходимо:
- описать переменную типа ofstream.
- открыть файл с помощью функции open.
- вывести информацию в файл.
- обязательно закрыть файл.
Для считывания данных из текстового файла, необходимо:
- описать переменную типа ifstream.
- открыть файл с помощью функции open.
- считать информацию из файла, при считывании каждой порции данных необходимо проверять, достигнут ли конец файла.
- закрыть файл.
Задача 1
Создать текстовый файл D:\\sites\\accounts.txt и записать в него n вещественных чисел.
Чтение информации из текстового файла
Для того чтобы прочитать информацию из текстового файла, необходимо описать переменную типа ifstream. После этого нужно открыть файл для чтения с помощью оператора open. Если переменную назвать F, то первые два оператора будут такими:
После открытия файла в режиме чтения из него можно считывать информацию точно так же, как и с клавиатуры, только вместо cin нужно указать имя потока, из которого будет происходить чтение данных.
Например, для чтения данных из потока F в переменную a, оператор ввода будет выглядеть так:
F>>a;
Два числа в текстовом редакторе считаются разделенными, если между ними есть хотя бы один из символов: пробел, табуляция, символ конца строки. Хорошо, когда программисту заранее известно, сколько и какие значения хранятся в текстовом файле. Однако часто известен лишь тип значений, хранящихся в файле, при этом их количество может быть различным. Для решения данной проблемы необходимо считывать значения из файла поочередно, а перед каждым считыванием проверять, достигнут ли конец файла. А поможет сделать это функция F.eof(). Здесь F — имя потока функция возвращает логическое значение: true или false, в зависимости от того достигнут ли конец файла.
Следовательно, цикл для чтения содержимого всего файла можно записать так:
//организуем для чтения значений из файла, выполнение
//цикла прервется, когда достигнем конец файла,
//в этом случае F.eof() вернет истину
while ( ! F. eof ( ) )
<
//чтение очередного значения из потока F в переменную a
F >> a ;
//далее идет обработка значения переменной a
>
Для лучшего усвоения материала рассмотрим задачу.
Решение
Решение
На этом относительно объемный урок по текстовым файлам закончен. В следующей статье будут рассмотрены методы манипуляции, при помощи которых в C++ обрабатываются двоичные файлы.
В зависимости от того, какие действия ваша программа собирается производить с открываемым файлом, возможно троякое его открытие:
Закрытие файла
После того как ваша программа закончит работу с файлом, очень желательно закрыть его:
В противном случае информация, содержащаяся в этом файле, может быть потеряна.
Считывание из файла
Чтение данных из файла, открытого для считывания, производится с помощью команд read() и readln() . В скобках сначала указывается имя файловой переменной , а затем - список ввода 2 См. лекцию 1. . Например:
Если вспомнить, что в памяти компьютера любой файл записывается линейной последовательностью символов и никакой разбивки на строки там реально нет, то действия процедуры readln() можно пояснить так: читать все указанные переменные, а затем игнорировать все символы вплоть до ближайшего символа "конец строки" или "конец файла". Указатель при этом перемещается на позицию непосредственно за первым найденным символом "конец строки".
Если же символ конца строки встретится где-нибудь между переменными, указанными в списке ввода, то обе процедуры его просто проигнорируют.
Считывать из текстового файла можно только переменные простых типов: целых, вещественных, символьных, - а также строковых. Численные переменные, считываемые из файла, должны разделяться хотя бы одним пробельным символом . Типы вводимых данных и типы тех переменных, куда эти данные считываются, обязаны быть совместимыми 3 См. лекцию 2. . Здесь действуют все те же правила, что и при считывании с клавиатуры.
Считываемые переменные могут иметь различные типы. Например, если в файле 4 Более правильно было бы сказать: "в файле, подключенном к файловой переменной f ", однако для краткости здесь и далее мы будем использовать упрощенный вариант, полагая, что это не вызовет никаких недоразумений. f записана строка
то командой read(f,a,b,c); можно прочитать одновременно значения для трех переменных, причем все - разных типов:
Замечание: Обратите внимание, что символьную переменную c пришлось считывать дважды, так как после числа " 2.5 " сначала идет символ пробела и только затем буква " c ".
Из файла невозможно считать переменную составного типа (например, если а - массив, то нельзя написать read(f,a) , можно ввести его только поэлементно, в цикле), файлового, а также логического.
Особенно внимательно нужно считывать строки ( string[length] и string ): эти переменные "забирают" из файла столько символов, сколько позволяет им длина (либо вплоть до ближайшего конца строки). Если строковая переменная неопределенной длины (тип данных string ) является последней в текущей строке файла, то никаких проблем с ее считыванием не возникнет. Но в случае, когда необходимо считывать переменную типа string из начала или из середины строки файла, это придется делать с помощью цикла - посимвольно. Аналогичным образом - посимвольно, от пробела до пробела - считываются из текстового файла слова.
Есть еще один, гораздо более трудоемкий способ: считать из файла всю строку целиком, а затем "распотрошить" ее - разобрать на части специальной процедурой выделения подстрок copy() . После чего (где необходимо) применить процедуру превращения символьной записи числа в само число, применяя стандартную процедуру val () . Кроме того, совсем не очевидно, что длина вводимой строки не будет превышать 256 символов, поэтому такой способ приходится признать неудовлетворительным.
Запись в файл
Сохранять переменные в файл, открытый для записи командами rewrite (f) или append (f) , можно при помощи команд write() и writeln() . Так же как в случае считывания, первой указывается файловая переменная , а за ней - список вывода :
Выводить в текстовый файл можно переменные любых базовых типов (вместо значений логического типа выведется их строковый аналог TRUE или FALSE ) или строки.
Задача 2
Вывести на экран содержимого созданного в прошлой задаче двоичного файла D:\\game\\noobs.dat
Двоичный файл — последовательная структура данных, после открытия файла доступен первый байт, хранящийся в нем. Можно последовательно записывать или считывать данные из файла. Допустим, необходимо считать пятнадцатое число, а затем первое. С помощью последовательного доступа это можно сделать следующим способом:
int n, i ;
double a ;
FILE * f ;
f = fopen ( «D: \\ game \\ noobs.dat» , «rb» ) ;
for ( i = 0 ; i < 15 ; i ++ )
fread ( & a, sizeof ( double ) , 1 , f ) ;
fclose ( f ) ;
f = fopen ( «D: \\ game \\ noobs.dat» , «rb» ) ;
fread ( & a, sizeof ( double ) , 1 , f ) ;
fclose ( f ) ;
Как видно, такое чтение чисел из файла, а затем повторное открытие файла — не самый удобный способ. Гораздо удобнее будет использовать функцию fseek перемещения указателя файла к заданному байту.
int fseek(FILE *filename, long int offset, int origin);
Функция устанавливает указатель текущий позиции файла F в соответствии со значением начала отсчета origin и смещения offset. Параметр offset равен количеству байтов, на которые будет смещен указатель файла относительно начала отсчета, заданного параметром origin. В качестве значения для параметра origin должно быть взято одно из следующих значений отсчета смещения offset, определенных в заголовке stdio.h:
- SEEK_SET — с начала файла;
- SEEK_CUR — с текущей позиции;
- SEEK_END — с конца файла.
Функция возвращает нулевое значение при успешном выполнение операции, ненулевое — при возникновении сбоя при выполнении смещения
Функция fseek фактически реализует прямой доступ к любому значению в файле. Необходимо только знать месторасположение (номер байта) значения в файле. Рассмотрим использование прямого доступа в двоичных файлах на примере решения следующей задачи.
Читайте также: