Как записать в конец файла c
Перейти к содержимому

Как записать в конец файла c

Запись строки в конец файла (C++)

Я понимаю, что к этому можно многое добавить, и я прошу прощения, если кажется, что я прошу людей кодировать для меня, но я полностью потерян, потому что я никогда не делал этот тип программирования раньше.

Я пробовал разные методы, которые я столкнулся с интернетом, но это самое близкое, что работает и несколько знакомо.

4 ответов

откройте файл с помощью std::ios::app

добавить содержимое в конец файлов, просто откройте файл с ofstream (что означает файл из потока) в app mode (что означает добавить).

откройте поток в качестве добавления, новый текст, записанный в него, будет записан в конце файла.

Я надеюсь, что это не весь ваш код, потому что если это так, с ним много чего не так.

Открываем файл

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

Имя файла

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

Абсолютный (полный) путь: “D:/some-folder/some-file.txt” – указание диска и всех папок

Относительный путь: “../some-folder/some-file.txt” – используя символ “..” можно подняться на уровень выше (выйти из текущей папки). Обычно используется если необходимый файл находится на том же диске в соседней/родительской папке. Символов “..” можно указывать столько, сколько необходимо: “../../../../some-file.txt”

Знание про абсолютный и относительный пути пригодится тебе в любом языке и любой операционной системе – запомни это.

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

Всего есть 3 основных режима:

  • “r” – чтение. Открываем существующий файл и вычитываем оттуда данные.
  • “w” – запись. Создаём новый файл (если такой уже есть, то перезаписываем его) и записываем туда данные.
  • “a” – запись в конец. Открываем существующий файл (если файла ещё нет, то создаём его) и записываем данные в конец файла.

К этим режимам можно дописать “+”, чтобы разблокировать возможность чтения для “w” и “a”, и возможность записи для “r”.

Вот табличка, в которой я собрал все комбинации

Режим Чтение Запись Создать новый файл (если нет) Очистить содержимое
“r” +
“w” + + +
“a” + +
“r+” + +
“w+” + + + +
“a+” + + +

Их не нужно запоминать – обычно все пользуются:

  • “r” при чтении
  • “w” при записи
  • “r+” при чтении/записи

Но если в какой-то ситуации тебе понадобится что-то другое – не стесняйся экспериментировать.

Закрываем файл

fclose – функция принимает дескриптор открытого файла, и закрывает его, записывая все данные из буффера.

Стоп, что за буффер?

FILE – это не дескриптор

Я был не до конца честен, когда говорил, что FILE – это дескриптор файла. На самом деле, FILE это обёртка над настоящим дескриптором.

Чтобы получить настоящий дескриптор, в зависимости от операционной системы, надо использовать функции:

  • Linux: open из “fcntl.h”
  • Windows: _open из “io.h”

Обёртка над дескриптором FILE поддерживает:

  • Буфферизацию – то есть не сразу записывает все данные в файл, а ждёт пока накопится достаточное количество данных во временном буффере (который хранится в оперативной памяти)
  • Отслеживание позиции – благодаря этому мы можем удобно узнать дошли ли мы до конца файла при чтении
  • Обработку ошибок – можно узнать произошла ли ошибка при выполнении чтения/записи с помощью функции ferror

Подробнее про разницу между FILE и дескриптором можно прочитать тут.

Закрываем FILE

Окей, с закрытием FILE разобрались – при закрытии в файл записывается буффер.

Когда это делать? Когда закончили работать с файлом.

Что будет если это не сделать?

Если программа завершается как обычно, то ничего плохого не произойдёт – перед закрытием наша программа запишет буффер в файл и закроет дескриптор файла.

В случае, если программа упадёт до закрытия FILE – в файл ничего не запишется, так как буффер не успел записаться в файл. Однако дескриптор закроется, но не программой, а операционной системой (потому что получившая его программа умерла). Вот пример такой ситуации:

Если бы мы закрыли файл до падения, то всё было бы хорошо в этом случае. В общем – всегда следи за закрытием.

Можно записать буффер в файл до закрытия с помощью функции fflush. Если я вызвал бы её до падения в программе выше, то данные бы записались в файл.

Чтение/запись в файл

Для записи в файл в библиотеке “stdio.h” есть ряд функций:

  • fprintf – записываем текст в файл, указывая строку форматирования (как в обычном printf)
  • fputc – записать один char в файл
  • fputs – записать строку (всё до ‘\0’) в файл
  • fwrite – записать массив значений (с указанным размером элемента и количеством элементов) в файл

Для записи там есть альтер-эго таких же функции:

  • fscanf – считываем текст из файла, указывая строку форматирования (как в обычном scanf)
  • fgetc – считать один char из файла
  • fgets – считать строку из файла. Считывается всё до конца файла или символа переноса строки ‘\n’. Символ переноса строки включается в результирующую строку
  • fread – считать массив значений (с указанным размером элемента и количеством элементов) из файла

Давайте я напишу программу, которая “шифрует” все символы в файле, а потом “дешифрует” их.

“Шифрованием” у меня будет смещение кода символа на 1, а “дешифрацией” – смещение кода символа на -1.

При этом, будет необходимое условие – в начале файла должен стоять символ ‘0’.

Программа изменяет так:

При повторном запуске программы, файл возвращает исходный вид.

Если что, это “шифрование” сможет защитить только от человека, который не является IT-специалистом. В настоящем шифровании каждый символ шифруется с использованием сложных криптографических алгоритмов и длинного уникального секретного ключа (один из них – алгоритм RSA).

Так, в этой программе я использовал какие-то функции feof и fseek – что это?

Навигация по файлу

Благодаря обёртке FILE, у нас есть возможность перемещаться по файлу, смещая указатель позиции файла.

Изначальная позиция

У каждого FILE есть свой указатель позиции файла, изначальная позиция которого зависит от режима работы с файлом, который мы использовали:

  • “r” и “w” – начало файла
  • “a” – конец файла

После этого, при чтении/записи указатель позиции будет смещаться вперёд на:

  • 1 символ для fgetc и fputc
  • Количество символов строки для fgets и fputs
  • Количество символов форматированного ввода/вывода для fscanf и fprintf
  • (Размер_элемента * количество_элементов) символов для fread и fwrite

Сдвигаем позицию

Также, есть функция fseek, которая смещает текущий указатель позиции на указанное количество символов, относительно некоторой позиции.

“Некоторая позиция” также указывается параметром:

  • SEEK_CUR – текущая позиция
  • SEEK_SET – начало файла
  • SEEK_END – конец файла

ВАЖНО: кроме перемещения по файлу, необходимо вызывать fseek, если ты хочешь переключиться с режима чтения на режим записи, в комбинированных режимах, вроде “r+”, “w+” и “a+”. В программе выше я для этого вызываю fseek без смещения.

Значение текущего указателя позиции можно получить через функцию ftell

Проверяем, что дошли до конца файла

Для проверки того, что мы дошли до конца файла, необходимо вызвать функцию feof.

Эта функция возвращает 1, если указатель позиции дошёл до конца файла.

feof вернёт 1 только в случае, если мы перед этим вызвали функцию чтения, которая дошла до конца файла (fgetc, fgets, fscanf, fread).

Это происходит из-за того, что функция чтения, при упирании в конец файла, выставляет флажок “достигли конца файла”, который и проверяет функция feof.

Также, при вызове функций чтения, по возвращаемому значению можно понять что мы дошли до конца файла:

  • fgetc – вернёт -1, если дошли до конца файла; вместо -1 в этом случае используется константа EOF (End Of File)

Обычно fget возвращает код символа от 0 до 255

  • fgets – вернёт NULL
  • fscanf – вернёт количество считанных элементов, отличающееся от требуемого (упёрлись в конец файла)
  • fread – вернёт количество считанных элементов, отличающееся от требуемого (упёрлись в конец файла)

Бинарные файлы

Это последняя тема, которую я хочу объяснить.

У функции fopen есть ещё один режим работы – бинарный файл.

Для того, чтобы открыть файл в бинарном виде, надо указать “b” в конце строки, определяющей режим работы с файлом:

Режим работы при этом может быть любым.

Теперь мы работаем с файлом не как с текстом, а как с набором байт.

То есть, я могу создать массив int, записать его в файл, а потом считать оттуда:

Возможно ты думаешь, что в файле сейчас записано что-то вроде “1 2 4 8 16”, но нет – там такое:

Текст бинарного файла

Оно выглядит так странно из-за того, что текстовый редактор не может нормально отобразить бинарные данные – он пытается прочитать коды символов.

Чтобы реально узнать что там лежит, необходимо воспользоваться редактором, который может отображать бинарные данные. Вот как содержимое выглядит через такой редактор:

Данные в бинарном файле

Обычно они называются hex-editor, потому что отображают данные в шеснадцатеричной системе счисления. Посмотрев на данные в представлении этого редактора, можно заметить что наши 5 int’ов лежат там как ни в чём не бывало.

Зачем вообще это надо? Почему нельзя хранить всё как текст?

Представь, что я захочу сохранить unsigned int число 4294967295:

  • В бинарном файле это число всё так же займёт 4 байта (FF FF FF FF)
  • В текстовом файле это число займёт 10 байт (в этом числе 10 символов) + дополнительная нагрузка при чтении данных, так как надо перевести строку в unsigned int

Про хранение вещественных чисел я вообще молчу

Если численные данные в базах данных хранились бы текстом, то понадобилось бы в 2+ раз больше дата-центров.

В общем, если пользователю не надо напрямую взаимодействовать с текстом в файле, то бинарные файлы – это отличный вариант.

Как работать с русскимим символами?

Надо добавить поддержку русской локализации:

И убедись, что ты сохраняешь файл в кодировке “windows 1251” – обычно файлы сохраняются в кодировке UTF-8. Так как кодировка UTF-8 двухбайтная (каждый символ кодируется двумя байтами), ты не сможешь работать с нимми как обычно.

Как перевести строку в число?

Здесь можешь посмотреть документацию к различным функциям перевода строки в число:

  • atoi() – строка в int
  • atof() – строка в double
  • atol() – строка в long int

Функции strtof, strtod, strtol и подобные, тоже переводят строку в число, но обладают расширенной функциональностью – смотри в документацию.

Обратное преобразование возможно через sprintf и fprintf.

Можно ли удалить из файла какие-то символы/слова?

Нет, нельзя – это можно сделать одним из двух способов:

  • Считать файл во временный буффер, удалить из буффера слова/символы и перезаписать файл с флагом “w” новым содержимым
  • Создать временный файл, считывать символы/слова из исходного файла, записывать (если символ/слово подходит) во временный файл, в конце удалить исходный файл и переименовать временный так, чтобы он назывался как исходный.

Вот пример использования первого способа, для решения задачи “удалить слово mother из файла”:

Как изменить символы в файле?

Открыть файл в режиме “r+”, считывать, смещаться fseek’ом на символ назад, записывать новое значение.

В главе “Чтение/запись в файл” есть пример.

Заключение

Итого, ты узнал что такое:

  • Файл
  • Дескриптор
  • Открытие файла
  • Закрытие файла
  • FILE – это обёртка надо дескриптором
  • Функции чтения и записи
  • Перемещение указателя позиции по файлу
  • Определение конца файла
  • Бинарные файлы

Поздравляю, это супер-круто! Это сложная тема, и скорее всего всё сразу не уляжется в голове – попробуй написать пару программ, перечитать непонятные места и отдохнуть.

Работа с файлами

Для удобства обращения информация в запоминающих устройствах хранится в виде файлов.

Файл – именованная область внешней памяти, выделенная для хранения массива данных. Данные, содержащиеся в файлах, имеют самый разнообразный характер: программы на алгоритмическом или машинном языке; исходные данные для работы программ или результаты выполнения программ; произвольные тексты; графические изображения и т. п.

Каталог ( папка , директория ) – именованная совокупность байтов на носителе информации, содержащая название подкаталогов и файлов, используется в файловой системе для упрощения организации файлов.

Файловой системой называется функциональная часть операционной системы, обеспечивающая выполнение операций над файлами. Примерами файловых систем являются FAT (FAT – File Allocation Table, таблица размещения файлов), NTFS, UDF (используется на компакт-дисках).

Существуют три основные версии FAT: FAT12, FAT16 и FAT32. Они отличаются разрядностью записей в дисковой структуре, т.е. количеством бит, отведённых для хранения номера кластера. FAT12 применяется в основном для дискет (до 4 кбайт), FAT16 – для дисков малого объёма, FAT32 – для FLASH-накопителей большой емкости (до 32 Гбайт).

Рассмотрим структуру файловой системы на примере FAT32.

Файловая структура FAT32

Устройства внешней памяти в системе FAT32 имеют не байтовую, а блочную адресацию. Запись информации в устройство внешней памяти осуществляется блоками или секторами.

Сектор – минимальная адресуемая единица хранения информации на внешних запоминающих устройствах. Как правило, размер сектора фиксирован и составляет 512 байт. Для увеличения адресного пространства устройств внешней памяти сектора объединяют в группы, называемые кластерами.

Кластер – объединение нескольких секторов, которое может рассматриваться как самостоятельная единица, обладающая определёнными свойствами. Основным свойством кластера является его размер, измеряемый в количестве секторов или количестве байт.

Файловая система FAT32 имеет следующую структуру.
Файловая система FAT32
Нумерация кластеров, используемых для записи файлов, ведется с 2. Как правило, кластер №2 используется корневым каталогом, а начиная с кластера №3 хранится массив данных. Сектора, используемые для хранения информации, представленной выше корневого каталога, в кластеры не объединяются.
Минимальный размер файла, занимаемый на диске, соответствует 1 кластеру.

Загрузочный сектор начинается следующей информацией:

  • EB 58 90 – безусловный переход и сигнатура;
  • 4D 53 44 4F 53 35 2E 30 MSDOS5.0;
  • 00 02 – количество байт в секторе (обычно 512);
  • 1 байт – количество секторов в кластере;
  • 2 байта – количество резервных секторов.

Кроме того, загрузочный сектор содержит следующую важную информацию:

  • 0x10 (1 байт) – количество таблиц FAT (обычно 2);
  • 0x20 (4 байта) – количество секторов на диске;
  • 0x2С (4 байта) – номер кластера корневого каталога;
  • 0x47 (11 байт) – метка тома;
  • 0x1FE (2 байта) – сигнатура загрузочного сектора ( 55 AA ).

Сектор информации файловой системы содержит:

  • 0x00 (4 байта) – сигнатура ( 52 52 61 41 );
  • 0x1E4 (4 байта) – сигнатура ( 72 72 41 61 );
  • 0x1E8 (4 байта) – количество свободных кластеров, -1 если не известно;
  • 0x1EС (4 байта) – номер последнего записанного кластера;
  • 0x1FE (2 байта) – сигнатура ( 55 AA ).

Таблица FAT содержит информацию о состоянии каждого кластера на диске. Младшие 2 байт таблицы FAT хранят F8 FF FF 0F FF FF FF FF (что соответствует состоянию кластеров 0 и 1, физически отсутствующих). Далее состояние каждого кластера содержит номер кластера, в котором продолжается текущий файл или следующую информацию:

  • 00 00 00 00 – кластер свободен;
  • FF FF FF 0F – конец текущего файла.

Корневой каталог содержит набор 32-битных записей информации о каждом файле, содержащих следующую информацию:

  • 8 байт – имя файла;
  • 3 байта – расширение файла;

Корневой каталог содержит набор 32-битных записей информации о каждом файле, содержащих следующую информацию:

  • 8 байт – имя файла;
  • 3 байта – расширение файла;
  • 1 байт – атрибут файла:
    Артибуты файла
  • 1 байт – зарезервирован;
  • 1 байт – время создания (миллисекунды) (число от 0 до 199);
  • 2 байта – время создания (с точностью до 2с):
    Время файла
  • 2 байта – дата создания:
    Дата файла
  • 2 байта – дата последнего доступа;
  • 2 байта – старшие 2 байта начального кластера;
  • 2 байта – время последней модификации;
  • 2 байта – дата последней модификации;
  • 2 байта – младшие 2 байта начального кластера;
  • 4 байта – размер файла (в байтах).

В случае работы с длинными именами файлов (включая русские имена) кодировка имени файла производится в системе кодировки UTF-16. При этого для кодирования каждого символа отводится 2 байта. При этом имя файла записывается в виде следующей структуры:

  • 1 байт последовательности;
  • 10 байт содержат младшие 5 символов имени файла;
  • 1 байт атрибут;
  • 1 байт резервный;
  • 1 байт – контрольная сумма имени DOS;
  • 12 байт содержат младшие 3 символа имени файла;
  • 2 байта – номер первого кластера;
  • остальные символы длинного имени.

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

Работа с файлами в языке Си

Для программиста открытый файл представляется как последовательность считываемых или записываемых данных. При открытии файла с ним связывается поток ввода-вывода . Выводимая информация записывается в поток, вводимая информация считывается из потока.

Когда поток открывается для ввода-вывода, он связывается со стандартной структурой типа FILE , которая определена в stdio.h . Структура FILE содержит необходимую информацию о файле.

Открытие файла осуществляется с помощью функции fopen() , которая возвращает указатель на структуру типа FILE , который можно использовать для последующих операций с файлом.

  • "r" — открыть файл для чтения (файл должен существовать);
  • "w" — открыть пустой файл для записи; если файл существует, то его содержимое теряется;
  • "a" — открыть файл для записи в конец (для добавления); файл создается, если он не существует;
  • "r+" — открыть файл для чтения и записи (файл должен существовать);
  • "w+" — открыть пустой файл для чтения и записи; если файл существует, то его содержимое теряется;
  • "a+" — открыть файл для чтения и дополнения, если файл не существует, то он создаётся.

Возвращаемое значение — указатель на открытый поток. Если обнаружена ошибка, то возвращается значение NULL .

Функция fclose() закрывает поток или потоки, связанные с открытыми при помощи функции fopen() файлами. Закрываемый поток определяется аргументом функции fclose() .

Возвращаемое значение: значение 0, если поток успешно закрыт; константа EOF , если произошла ошибка.

Чтение символа из файла:


Аргументом функции является указатель на поток типа FILE . Функция возвращает код считанного символа. Если достигнут конец файла или возникла ошибка, возвращается константа EOF .

Запись символа в файл:

Аргументами функции являются символ и указатель на поток типа FILE . Функция возвращает код считанного символа.

Функции fscanf() и fprintf() аналогичны функциям scanf() и printf() , но работают с файлами данных, и имеют первый аргумент — указатель на файл.

Функции fgets() и fputs() предназначены для ввода-вывода строк, они являются аналогами функций gets() и puts() для работы с файлами.


Символы читаются из потока до тех пор, пока не будет прочитан символ новой строки ‘\n’ , который включается в строку, или пока не наступит конец потока EOF или не будет прочитано максимальное количество символов. Результат помещается в указатель на строку и заканчивается нуль- символом ‘\0’ . Функция возвращает адрес строки.

Результат выполнения — 2 файла
Считать число из файла
Работа с файлами в C++ описана здесь.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *