Как перезаписать текстовый файл си шарп
Обновлено: 03.07.2024
Для удобства обращения информация в запоминающих устройствах хранится в виде файлов.
Файл – именованная область внешней памяти, выделенная для хранения массива данных. Данные, содержащиеся в файлах, имеют самый разнообразный характер: программы на алгоритмическом или машинном языке; исходные данные для работы программ или результаты выполнения программ; произвольные тексты; графические изображения и т. п.
Каталог ( папка , директория ) – именованная совокупность байтов на носителе информации, содержащая название подкаталогов и файлов, используется в файловой системе для упрощения организации файлов.
Файловой системой называется функциональная часть операционной системы, обеспечивающая выполнение операций над файлами. Примерами файловых систем являются FAT (FAT – File Allocation Table, таблица размещения файлов), NTFS, UDF (используется на компакт-дисках).
Существуют три основные версии FAT: FAT12, FAT16 и FAT32. Они отличаются разрядностью записей в дисковой структуре, т.е. количеством бит, отведённых для хранения номера кластера. FAT12 применяется в основном для дискет (до 4 кбайт), FAT16 – для дисков малого объёма, FAT32 – для FLASH-накопителей большой емкости (до 32 Гбайт).
Рассмотрим структуру файловой системы на примере FAT32.
Файловая структура FAT32
Устройства внешней памяти в системе FAT32 имеют не байтовую, а блочную адресацию. Запись информации в устройство внешней памяти осуществляется блоками или секторами.
Сектор – минимальная адресуемая единица хранения информации на внешних запоминающих устройствах. Как правило, размер сектора фиксирован и составляет 512 байт. Для увеличения адресного пространства устройств внешней памяти сектора объединяют в группы, называемые кластерами.
Кластер – объединение нескольких секторов, которое может рассматриваться как самостоятельная единица, обладающая определёнными свойствами. Основным свойством кластера является его размер, измеряемый в количестве секторов или количестве байт.
Файловая система 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+" — открыть файл для чтения и дополнения, если файл не существует, то он создаётся.
Функция fclose() закрывает поток или потоки, связанные с открытыми при помощи функции fopen() файлами. Закрываемый поток определяется аргументом функции fclose() .
Возвращаемое значение: значение 0, если поток успешно закрыт; константа EOF , если произошла ошибка.
Чтение символа из файла:
Аргументом функции является указатель на поток типа FILE . Функция возвращает код считанного символа. Если достигнут конец файла или возникла ошибка, возвращается константа EOF .
Запись символа в файл:
Аргументами функции являются символ и указатель на поток типа FILE . Функция возвращает код считанного символа.
Функции fscanf() и fprintf() аналогичны функциям scanf() и printf() , но работают с файлами данных, и имеют первый аргумент — указатель на файл.
Функции fgets() и fputs() предназначены для ввода-вывода строк, они являются аналогами функций gets() и puts() для работы с файлами.
Копирует строку в поток с текущей позиции. Завершающий нуль- символ не копируется.
Пример Ввести число и сохранить его в файле s1.txt. Считать число из файла s1.txt, увеличить его на 3 и сохранить в файле s2.txt.
Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
Создает или перезаписывает файл в указанном пути.
Перегрузки
Создает или перезаписывает файл в указанном пути.
Создает или перезаписывает файл по заданному пути с указанием размер буфера.
Создает или перезаписывает файл по заданному пути с указанием размера буфера и параметров, которые описывают, как создавать или перезаписывать файл.
Создает или перезаписывает файл по заданному пути с указанием размера буфера и параметров, которые описывают, как создавать или перезаписывать файл. Также указывается значение, определяющее контроль доступа и безопасность аудита для файла.
Create(String)
Создает или перезаписывает файл в указанном пути.
Параметры
Путь и имя создаваемого файла.
Возвращаемое значение
FileStream, обеспечивающий доступ для чтения и записи к файлу, указанному в path .
Исключения
У вызывающего объекта отсутствует необходимое разрешение.
-или- Параметр path указывает файл, доступный только для чтения.
-или- path указывает файл, который скрыт.
path имеет значение null .
Указанный путь, имя файла или оба значения превышают максимальную длину, заданную в системе.
Указан недопустимый путь (например, он ведет на несопоставленный диск).
Ошибка ввода-вывода при создании файла.
Параметр path задан в недопустимом формате.
Примеры
В следующем примере создается файл по указанному пути, записываются некоторые сведения в файл и считываются из файла.
Комментарии
FileStreamОбъект, созданный этим методом, имеет значение по умолчанию FileShare None ; никакие другие процессы или код не могут получить доступ к созданному файлу, пока не будет закрыт исходный маркер файла.
Этот метод эквивалентен Create(String, Int32) перегрузке метода, используя размер буфера по умолчанию 4 096 байт.
path Параметр может указывать сведения относительного или абсолютного пути. Сведения об относительном пути интерпретируется как относительно текущего рабочего каталога. Сведения о получении текущего рабочего каталога см. в разделе GetCurrentDirectory .
Если указанный файл не существует, он создается; Если он существует и не доступен только для чтения, содержимое перезаписывается.
По умолчанию всем пользователям предоставляется полный доступ на чтение и запись к новым файлам. Файл открыт с доступом на чтение и запись и должен быть закрыт, прежде чем его можно будет открыть другим приложением.
Для обработки текстовых файлов продемонстрирована работа классов File , StreamReader , StreamWriter .
Содержание
- 1. Как определить, что данные в текстовом файле закончились?
- 2. Последовательность действий при чтении данных из файла. Использование класса StreamReader
- 3. Функция PrintFile() . Вывести содержимое текстового файла на экран. Способ 1
- 4. Функция PrintFile2() . Вывести содержимое текстового файла на экран. Способ 2
- 5. Функция ReplaceStringInFile() . Замена строки в текстовом файле. Использование возможностей класса File
- 6. Функция RemoveStringFromFile() . Удаление строки из файла по индексу. Пример
- 7. Функция InsertLineInFile() . Вставка строки в файл в заданной позиции
- 8. Функция ConvertLinesFileToList() . Конвертировать строки файла в список List<string>
- 9. Функция AddArrayLinesInFile() . Добавление массива строк в конец файла
- 10. Функция SwapLinesInFile() . Обмен местами двух строк в файле
- 11. Функция ReverseStringsInFile() . Реверсирование строк файла (перестановка строк файла в обратном порядке)
- 12. Функция SortLineInFileBubble() . Сортировка строк в файле методом пузырька
Поиск на других ресурсах:
1. Как определить, что данные в текстовом файле закончились?
2. Последовательность действий при чтении данных из файла. Использование класса StreamReader
Чтобы прочитать данные из текстового файла нужно выполнить приблизительно следующую последовательность действий:
1. Подключить модуль System.IO с помощью строки
2. Создать экземпляр класса StreamReader с помощью одного из перегруженных конструкторов. Одновременно с созданием экземпляра происходит открытие файла для чтения или записи. Класс StreamReader имеет несколько конструкторов.
3. С помощью экземпляра StreamReader осуществить циклическое чтение строк файла как показано ниже
4. Закрыть файл с помощью метода Close()
3. Функция PrintFile() . Вывести содержимое текстового файла на экран. Способ 1
Для наглядной демонстрации чтения информации из текстового файла приводится статическая функция PrintFile() , которая выводит содержимое текстового файла на экран. Для чтения строк из файла функция использует метод ReadLine() класса StreamReader . Если достигнут конец файла, то ReadLine() возвращает null .
4. Функция PrintFile2() . Вывести содержимое текстового файла на экран. Способ 2
Алгоритм работы следующий:
5. Функция ReplaceStringInFile() . Замена строки в текстовом файле. Использование возможностей класса File
При операциях с файлами важно придерживаться правильной последовательности чтения/записи. Если попробовать изменять данные в файле непосредственно, то можно допустить много трудноуловимых ошибок. Поэтому, для замены строки в текстовом файле рекомендуется использовать следующий алгоритм:
- прочесть все строки из файла в массив. В примере для чтения строк из файла используется метод ReadAllLines() статического класса File . Этот метод возвращает массив типа string[] ;
- осуществить замену строки в массиве;
- записать строки из массива снова в файл. Для записи используется метод WriteAllLines() статического класса File . В метод передается имя файла и массив строк типа string[] , который нужно записать.
Текст демонстрационного консольного приложения следующий.
6. Функция RemoveStringFromFile() . Удаление строки из файла по индексу. Пример
7. Функция InsertLineInFile() . Вставка строки в файл в заданной позиции
По образцу пункта 6 можно реализовать вставку строки в файл в заданной позиции. Строки в файле предварительно копируются в список типа List<string> . Использование списков в подобных задачах облегчает работу программиста, поскольку списки содержат все необходимые методы вставки, добавления, удаления элемента.
Предложенная функция InsertLineInFile() имеет одну особенность. Если позиция вставки (нумеруется с 0) равна количеству элементов в файле n , то строка вставки добавляется в конец файла. Таким образом функция реализует вставку и добавление строки в файл.
8. Функция ConvertLinesFileToList() . Конвертировать строки файла в список List<string>
В пунктах 6, 7 повторяется код, который образовывает список типа List<string> из строк файла. Поэтому, целесообразно написать функцию ConvertLinesFileToList() , которая реализует конвертирование строк файла в список. Текст функции следующий.
9. Функция AddArrayLinesInFile() . Добавление массива строк в конец файла
В примере приведена функция, которая добавляет массив строк в конец файла. Данная функция использует функцию ConvertLinesFileToList() , которая возвращает строки файла в виде списка и описывается в пункте 8. Для работы с файлами используются возможности классов StreamReader и StreamWriter .
Алгоритм метода следующий:
- прочитать данные из файла в список типа List<string> ;
- добавить к списку массив строк;
- записать измененный список в файл. Для записи списка используются средства класса StreamWriter .
Программный код функции AddArrayLinesInFile() следующий.
Использование функции в другом программном коде может быть, например, таким.
10. Функция SwapLinesInFile() . Обмен местами двух строк в файле
Обмен местами двух строк в файле не изменяет общее количество строк. Поэтому, прочитанные строки из файла целесообразно представить массивом типа string[] .
Статический файл File также содержит функцию WriteAllLines() , которая записывает строки типа string[] в файл.
Ниже приведен фрагмент кода, который содержит описание функции SwapLinesInFile() .
Использование функции SwapLinesInFile() в другом коде может быть, например, таким
В нашем первом примере мы сконструируем максимально минималистичный текстовый редактор. На самом деле он настолько простой, что мы можем только прочитать один файл и записать в него новое содержимое, только по одной строке текста одновременно. Но это показывает нам то, насколько просто использовать класс File:
Вы заметите, что мы используем класс File в трех местах: мы используем его, чтобы проверить, существует ли наш файл, мы используем метод ReadAllText () для чтения содержимого файла, и мы используем метод WriteAllText () для записи нового содержимого в файл. Вы заметите, что я не использую абсолютные пути, а просто простое имя файла. Это поместит файл в ту же директорию, что и исполняемый файл, что пока нормально. Кроме этого, пример должен быть достаточно простым для понимания: мы проверяем файл, если он существует, мы читаем его содержимое и выводим его на консоль. Затем мы запрашиваем у пользователя новый контент, и как только он у нас появляется, мы записываем его в файл. Очевидно, что это перезапишет предыдущий контент, но пока это просто отлично. Однако мы могли бы вместо этого использовать метод AppendAllText. Попробуйте вместо этого изменить строку WriteAllText:
Если вы запустите программу, то вы увидите, что новый текст добавляется к уже существующему, вместо перезаписи его. Настолько просто, насколько вообще возможно. Но мы все еще можем записать только одну строку текста за одно выполнение программы. Давайте проявим немного смекалки и исправим это. Замените последние строки нашего примера этим:
Как можно заметить, мы инструктируем пользователя ввести слово exit, если он захочет прекратить редактирование файла, но пока он этого не сделает, мы будем дописывать введенные пользователем данные в конец файла, а затем попросим ввести еще одну строку. Для того, чтобы это выглядело как настоящие строки текста, мы дописываем символ новой строки - Environment.NewLine.
Тем не менее, вместо записи в файл каждый раз, намного более элегантное решение скорее всего будет выглядеть примерно так:
Читайте также: