Как перезаписать текстовый файл си шарп

Обновлено: 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

Файловая система 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.

Тем не менее, вместо записи в файл каждый раз, намного более элегантное решение скорее всего будет выглядеть примерно так:

Читайте также: