Текстовые файлы
Рассмотрим работу с текстовым файлом в Си на примере. Создайте на диске С текстовый файл с именем TextFile.txt. Наберите в этом файле такие строки:
String_1 123 String_11, 456
String_2
String_3
Сохраните файл.
А это код программы на C, которая открывает наш файл и считывает из него строки:
/*
*Author: @author Subbotin B.P..h>
#include
Чтоб открыть текстовый файл в C используем функцию fopen:
FILE *pTextFile = fopen("C:\\TextFile.txt", "r");
первый аргумент функции fopen указывает на файл, а второй говорит, что файл открыт для чтения из него.
Строки считываем с помощью функции fgets:
fgets(cArray, LEN, pTextFile);
первый аргумент функции fgets указвает на массив символов, в котором будут сохранятся полученные строки, второй аргумент - это максимальное количество символов для считывания, третий - наш файл.
После завершения работы с файлом, его надо закрыть:
fclose(pTextFile);
Получаем:
Русские буквы в строках тоже проходят.
Кстати, эту программу я сделал в Eclipse. Как работать с C/C++ в Eclipse можно посмотреть .
Итак, мы открыли и считали данные из текстового файла.
Теперь научимся программно создавать текстовый файл и записывать в него данные.
/*
Author: @author Subbotin B.P..h>
#include
Создаем текстовый файл для записи в него данных:
FILE *pTextFile = fopen("C:\\TextFileW.txt", "w");
если файл уже имеется, то он будет открыт, и все данные из него будут удалены.
C-строка cString, и число nVal записываются программой в текстовый файл. cNewLine - это просто переход на новую строку.
Записываем данные в текстовый файл с помощью функции fprintf:
fprintf(pTextFile, "%s%c", cString, cNewLine);
первый аргумент здесь - наш файл, второй - форматная строка, третий и более - нужное для этого формата количество аргументов.
Для программиста открытый файл представляется как последовательность считываемых или записываемых данных. При открытии файла с ним связывается поток ввода-вывода . Выводимая информация записывается в поток, вводимая информация считывается из потока.
Когда поток открывается для ввода-вывода, он связывается со стандартной структурой типа FILE, которая определена в stdio.h. Структура FILE содержит необходимую информацию о файле.
Открытие файла осуществляется с помощью функции fopen(), которая возвращается указатель на структуру типа FILE, который можно использовать для последующих операций с файлом.
FILE *fopen (name, type);
name – имя открываемого файла (включая путь),
type - указатель на строку символов, определяющих способ доступа к файлу:
· "r" - открыть файл для чтения (файл должен существовать);
· "w" - открыть пустой файл для записи; если файл существует, то его содержимое теряется;
· "a" - открыть файл для записи в конец (для добавления); файл создается, если он не существует;
· "r+" - открыть файл для чтения и записи (файл должен существовать);
· "w+" - открыть пустой файл для чтения и записи; если файл существует, то его содержимое теряется;
· "a+" - открыть файл для чтения и дополнения, если файл не существует, то он создаётся.
Возвращаемое значение - указатель на открытый поток. Если обнаружена ошибка, то возвращается значение NULL.
Функция fclose() закрывает поток или потоки, связанные с открытыми при помощи функции fopen() файлами. Закрываемый поток определяется аргументом функции fclose().
Возвращаемое значение: значение 0, если поток успешно закрыт; константа EOF, если произошла ошибка.
#include
int main()
char name="my.txt";
if(fp = fopen(name, "r")!=NULL)
// открыть файлу далось?
... // требуемые действия над данными
else printf("Не удалось открыть файл");
Чтение символа из файла :
char fgetc(поток);
Аргументом функции является указатель на поток типа FILE. Функция возвращает код считанного символа. Если достигнут конец файла или возникла ошибка, возвращается константа EOF.
Запись символа в файл
:
fputc(символ,поток);
Аргументами функции являются символ и указатель на поток типа FILE. Функция возвращает код считанного символа.
Функции fscanf() и fprintf() аналогичны функциям scanf() и printf(), но работают с файлами данных, и имеют первый аргумент - указатель на файл.
fscanf(поток, "Формат Ввода", аргументы);
fprintf(поток, "Формат Вывода", аргументы);
Функции fgets() и fputs() предназначены для ввода-вывода строк, они являются аналогами функций gets() и puts() для работы с файлами.
fgets(Указатель На Строку, Количество Символов, поток);
Символы читаются из потока до тех пор, пока не будет прочитан символ новой строки "\n", который включается в строку, или пока не наступит конец потока EOF или не будет прочитано максимальное символов. Результат помещается в указатель на строку и заканчивается нуль- символом "\0". Функция возвращает адрес строки.
fputs(Указатель На Строку, поток);
Копирует строку в поток с текущей позиции. Завершающий нуль- символ не копируется.
Пример
Ввести число и сохранить его в файле s1.txt. Считать число из файла s1.txt, увеличить его на 3 и сохранить в файле s2.txt.
– сравнение для выявления равенства либо неравенства.
Практическое назначение перечисления – определение множества различающихся символических констант целого типа.
Пример использования переменных перечислимого типа:
mo=1, tu, we, th, fr, sa, su } days;
puts(“ Введите день недели (от 1 до 7) : ”); scanf(“%d”, &t_day);
w_day = su; start = mo;
end = w_day -t_day;
printf(“\n Понедельник - %d-й день недели, \ сейчас %d-й день. \n\
До конца недели %d дней (дня). ”, start, t_day, end);
Результат работы программы: Введите день недели (от 1 до 7) : 2
Понедельник - 1-й день недели, сейчас 2-й день. До конца недели 5 дней (дня).
18. Файлы в языке Си
Файл – это набор данных, размещенный на внешнем носителе и рассматриваемый в процессе обработки как единое целое. В файлах размещаются данные, предназначенные для длительного хранения.
Различают два вида файлов: текстовые и бинарные. Текстовые файлы представляют собой последовательность ASCII символов и могут быть просмотрены и отредактированы с помощью любого текстового редактора.
Бинарные (двоичные) файлы представляют собой последовательность данных, структура которых определяется программно.
В языке Си имеется большой набор функций для работы с файлами, большинство которых находятся в библиотеках stdio.h иio.h .
18.1. Открытие файла
Каждому файлу присваивается внутреннее логическое имя, используемое в дальнейшем при обращении к нему. Логическое имя (идентификатор файла) – это
указатель на файл, т.е. на область памяти, где содержится вся необходимая информация о файле. Формат объявления указателя на файл следующий:
FILE * указатель на файл; |
|
FILE – идентификатор структурного типа, описанный в стандартной библиотеке |
|
stdio.h и содержащий следующую информацию: |
|
type struct { | |
– число оставшихся в буфере непрочитанных байт; |
|
обычный размер буфера – 512 байт; как только level=0, |
|
в буфер из файла читается следующий блок данных; |
|
– флаг статуса файла – чтение, запись, дополнение; |
|
– дескриптор файла, т.е. число, определяющее его но- |
|
unsigned char hold; | – непереданный символ, т.е. ungetc-символ; |
– размер внутреннего промежуточного буфера; |
|
unsigned char buffer; | – значение указателя для доступа внутри буфера, т.е. |
задает начало буфера, начало строки или текущее зна- |
|
чение указателя внутри буфера в зависимости от режи- |
|
ма буферизации; |
|
unsigned char *curp; | – текущее значение указателя для доступа внутри бу- |
фера, т.е. задает текущую позицию в буфере для обме- |
|
на с программой; |
|
unsigned istemp; | – флаг временного файла; |
– флаг при работе с файлом; |
|
} FILE; |
Прежде чем начать работать с файлом, т.е. получить возможность чтения или записи информации в файл, его нужно открыть для доступа. Для этого обычно используется функция
FILE* fopen (char* имя_ файла, char* режим);
она берет внешнее представление – физическое имя файла на носителе (дискета, винчестер) и ставит ему в соответствие логическое имя.
Физическое имя, т.е. имя файла и путь к нему задается первым параметром
– строкой, например, “a:Mas_dat.dat” – файл с именем Mas_dat.dat, находящийся на дискете, “d:\\work\\Sved.txt” – файл с именем Sved.txt, находящийся на винчестере в каталоге work.
Внимание! Обратный слеш (\), как специальный символ, в строке записывается дважды.
При успешном открытии функция fopen возвращает указатель на файл (в дальнейшем – указатель файла). При ошибке возвращаетсяNULL . Данная ситуация обычно возникает, когда неверно указывается путь к открываемому файлу. Например, если в дисплейном классе нашего университета указать путь, запрещенный для записи (обычно разрешенным является d:\work\).
Второй параметр – строка, в которой задается режим доступа к файлу:
w – файл открывается для записи; если файла с заданным именем нет, то он будет создан; если такой файл существует, то перед открытием прежняя информация уничтожается;
r – файл открывается только для чтения; если такого файла нет, то возникает ошибка;
a – файл открывается для добавления в конец новой информации;
r+ – файл открывается для редактирования данных – возможны и запись, и чтение информации;
w+ – то же, что и для r+;
a+ – то же, что и для a, только запись можно выполнять в любое место файла; доступно и чтение файла;
t – файл открывается в текстовом режиме;b – файл открывается в двоичном режиме.
Текстовый режим отличается от двоичного тем, что при открытии файла как текстового пара символов «перевод строки», «возврат каретки» заменяется на один символ: «перевод строки» для всех функций записи данных в файл, а для всех функций вывода символ «перевод строки» теперь заменяется на два символа: «перевод строки», «возврат каретки».
По умолчанию файл открывается в текстовом режиме. Пример: FILE *f; – объявляется указатель на файл f;
f = fopen ("d:\\work\\Dat_sp.cpp", "w"); – открывается для записи файл с логическим именем f, имеющим физическое имя Dat_sp.cpp, находящийся на диске d, в каталоге work; или более кратко
FILE *f = fopen ("d:\\work\\Dat_sp.cpp", "w");
18.2. Закрытие файла
После работы с файлом доступ к нему необходимо закрыть. Это выполняет функция int fclose (указатель файла ). Например, из предыдущего примера файл закрывается так: fclose (f);
Для закрытия нескольких файлов введена функция, объявленная следующим образом: void fcloseall (void );
Если требуется изменить режим доступа к файлу, то для этого сначала необходимо закрыть данный файл, а затем вновь его открыть, но с другими правами доступа. Для этого используют стандартную функцию:
FILE* freopen (char*имя_файла , char *режим , FILE *указатель_файла );
Эта функция сначала закрывает файл, объявленный указателем_файла (как это делает функцияfopen ), а затем открывает файл сименем_файла и правами доступа «режим ».
В языке Си имеется возможность работы с временными файлами, которые нужны только в процессе работы программы. В этом случае используется функция
FILE* tmpfile (void);
которая создает на диске временный файл с правами доступа «w+b», после завершения работы программы или после закрытия временного файла он автоматически удаляется.
18.3. Запись – чтение информации
Все действия по чтению-записи данных в файл можно разделить на три группы: операции посимвольного ввода-вывода; операции построчного вводавывода; операции ввода-вывода по блокам.
Рассмотрим основные функции, применяемые в каждой из указанных трех групп операций.
Посимвольный ввод-вывод
В функциях посимвольного ввода-вывода происходит прием одного символа из файла или передача одного символа в файл:
Построчный ввод-вывод
В функциях построчного ввода-вывода происходит перенос из файла или в
Блоковый ввод-вывод
В функциях блокового ввода-вывода работа происходит с целыми блоками
информации: | |
int fread (void*p, intsize, | – считывает n блоков поsize байт каждый из фай- |
int n, FILE *f) | ла f в область памяти с указателемp (необходимо |
int fwrite (void*p, intsize, | заранее отвести память под считываемый блок); |
– записывает n блоков по size байт каждый из об- |
|
int n, FILE *f) | ласти памяти с указателем p в файл f. |
Форматированный ввод-вывод производится функциями.
До этого при вводе-выводе данных мы работали со стандартными потоками - клавиатурой и монитором. Теперь рассмотрим, как в языке 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
В данном случае объявляется структура и массив структур. Каждая строка из файла соответствует одному элементу массива; элемент массива представляет собой структуру, содержащую строковое и два числовых поля. За одну итерацию цикл считывает одну строку. Когда встречается конец файла fscanf() возвращает значение EOF и цикл завершается.
fgets()
Функция fgets() аналогична функции gets() и осуществляет построчный ввод из файла. Один вызов fgets() позволят прочитать одну строку. При этом можно прочитать не всю строку, а лишь ее часть от начала. Параметры fgets() выглядят таким образом:
fgets (массив_символов, количество_считываемых_символов, указатель_на_файл)
Например:
fgets (str, 50, myfile)
Такой вызов функции прочитает из файла, связанного с указателем myfile, одну строку текста полностью, если ее длина меньше 50 символов с учетом символа "\n", который функция также сохранит в массиве. Последним (50-ым) элементом массива str будет символ "\0", добавленный fgets() . Если строка окажется длиннее, то функция прочитает 49 символов и в конце запишет "\0". В таком случае "\n" в считанной строке содержаться не будет.
#include
В этой программе в отличие от предыдущей данные считываются строка за строкой в массив arr. Когда считывается следующая строка, предыдущая теряется. Функция fgets() возвращает NULL в случае, если не может прочитать следующую строку.
getc() или fgetc()
Функция getc() или fgetc() (работает и то и другое) позволяет получить из файла очередной один символ.
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) ;
Приведенный в качестве примера код выводит данные из файла на экран.
Запись в текстовый файл
Также как и ввод, вывод в файл может быть различным.
- Форматированный вывод. Функция fprintf (файловый_указатель, строка_формата, переменные) .
- Посточный вывод. Функция fputs (строка, файловый_указатель) .
- Посимвольный вывод. Функция fputc() или putc(символ, файловый_указатель) .
Ниже приводятся примеры кода, в которых используются три способа вывода данных в файл.
Запись в каждую строку файла полей одной структуры:
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++; }
Построчный вывод в файл (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
Здесь осуществляется попытка чтения из первого файла 50-ти символов. В n сохраняется количество реально считанных символов. Значение n может быть равно 50 или меньше. Данные помещаются в строку. То же самое происходит со вторым файлом. Далее первая строка присоединяется ко второй, и данные сбрасываются в третий файл.
Решение задач
- Напишите программу, которая запрашивает у пользователя имя (адрес) текстового файла, далее открывает его и считает в нем количество символов и строк.
- Напишите программу, которая записывает в файл данные, полученные из другого файла и так или иначе измененные перед записью. Каждая строка данных, полученная из файла, должна помещаться в структуру.
Последнее обновление: 31.10.2015
Класс FileStream представляет возможности по считыванию из файла и записи в файл. Он позволяет работать как с текстовыми файлами, так и с бинарными.
Рассмотрим наиболее важные его свойства и методы:
array - массив байтов, куда будут помещены считываемые из файла данные
offset представляет смещение в байтах в массиве array, в который считанные байты будут помещены
count - максимальное число байтов, предназначенных для чтения. Если в файле находится меньшее количество байтов, то все они будут считаны.
array - массив байтов, откуда данные будут записываться в файла
offset - смещение в байтах в массиве array, откуда начинается запись байтов в поток
count - максимальное число байтов, предназначенных для записи
Свойство Length : возвращает длину потока в байтах
Свойство Position : возвращает текущую позицию в потоке
Метод Read : считывает данные из файла в массив байтов. Принимает три параметра: int Read(byte array, int offset, int count) и возвращает количество успешно считанных байтов. Здесь используются следующие параметры:
Метод long Seek(long offset, SeekOrigin origin) : устанавливает позицию в потоке со смещением на количество байт, указанных в параметре offset.
Метод Write : записывает в файл данные из массива байтов. Принимает три параметра: Write(byte array, int offset, int count)
FileStream представляет доступ к файлам на уровне байтов, поэтому, например, если вам надо считать или записать одну или несколько строк в текстовый файл, то массив байтов надо преобразовать в строки, используя специальные методы. Поэтому для работы с текстовыми файлами применяются другие классы.
В то же время при работе с различными бинарными файлами, имеющими определенную структуру FileStream может быть очень даже полезен для извлечения определенных порций информации и ее обработки.
Посмотрим на примере считывания-записи в текстовый файл:
Console.WriteLine("Введите строку для записи в файл:"); string text = Console.ReadLine(); // запись в файл using (FileStream fstream = new FileStream(@"C:\SomeDir\noname\note.txt", FileMode.OpenOrCreate)) { // преобразуем строку в байты byte array = System.Text.Encoding.Default.GetBytes(text); // запись массива байтов в файл fstream.Write(array, 0, array.Length); Console.WriteLine("Текст записан в файл"); } // чтение из файла using (FileStream fstream = File.OpenRead(@"C:\SomeDir\noname\note.txt")) { // преобразуем строку в байты byte array = new byte; // считываем данные fstream.Read(array, 0, array.Length); // декодируем байты в строку string textFromFile = System.Text.Encoding.Default.GetString(array); Console.WriteLine("Текст из файла: {0}", textFromFile); } Console.ReadLine();
Разберем этот пример. И при чтении, и при записи используется оператор using . Не надо путать данный оператор с директивой using, которая подключает пространства имен в начале файла кода. Оператор using позволяет создавать объект в блоке кода, по завершению которого вызывается метод Dispose у этого объекта, и, таким образом, объект уничтожается. В данном случае в качестве такого объекта служит переменная fstream .
Объект fstream создается двумя разными способами: через конструктор и через один из статических методов класса File.
Здесь в конструктор передается два параметра: путь к файлу и перечисление FileMode . Данное перечисление указывает на режим доступа к файлу и может принимать следующие значения:
Append : если файл существует, то текст добавляется в конец файл. Если файла нет, то он создается. Файл открывается только для записи.
Create : создается новый файл. Если такой файл уже существует, то он перезаписывается
CreateNew : создается новый файл. Если такой файл уже существует, то он приложение выбрасывает ошибку
Open : открывает файл. Если файл не существует, выбрасывается исключение
OpenOrCreate : если файл существует, он открывается, если нет - создается новый
Truncate : если файл существует, то он перезаписывается. Файл открывается только для записи.
Статический метод OpenRead класса File открывает файл для чтения и возвращает объект FileStream.
Конструктор класса FileStream также имеет ряд перегруженных версий, позволяющий более точно настроить создаваемый объект. Все эти версии можно посмотреть на msdn.
И при записи, и при чтении применяется объект кодировки Encoding.Default из пространства имен System.Text . В данном случае мы используем два его метода: GetBytes для получения массива байтов из строки и GetString для получения строки из массива байтов.
В итоге введенная нами строка записывается в файл note.txt . По сути это бинарный файл (не текстовый), хотя если мы в него запишем только строку, то сможем посмотреть в удобочитаемом виде этот файл, открыв его в текстовом редакторе. Однако если мы в него запишем случайные байты, например:
Fstream.WriteByte(13); fstream.WriteByte(103);
То у нас могут возникнуть проблемы с его пониманием. Поэтому для работы непосредственно с текстовыми файлами предназначены отдельные классы - StreamReader и StreamWriter.
Произвольный доступ к файлам
Нередко бинарные файлы представляют определенную стрктуру. И, зная эту структуру, мы можем взять из файла нужную порцию информации или наоброт записать в определенном месте файла определенный набор байтов. Например, в wav-файлах непосредственно звуковые данные начинаются с 44 байта, а до 44 байта идут различные метаданные - количество каналов аудио, частота дискретизации и т.д.
С помощью метода Seek() мы можем управлять положением курсора потока, начиная с которого производится считывание или запись в файл. Этот метод принимает два параметра: offset (смещение) и позиция в файле. Позиция в файле описывается тремя значениями:
SeekOrigin.Begin : начало файла
SeekOrigin.End : конец файла
SeekOrigin.Current : текущая позиция в файле
Курсор потока, с которого начинается чтение или запись, смещается вперед на значение offset относительно позиции, указанной в качестве второго параметра. Смещение может отрицательным, тогда курсор сдвигается назад, если положительное - то вперед.
Рассмотрим на примере:
Using System.IO; using System.Text; class Program { static void Main(string args) { string text = "hello world"; // запись в файл using (FileStream fstream = new FileStream(@"D:\note.dat", FileMode.OpenOrCreate)) { // преобразуем строку в байты byte input = Encoding.Default.GetBytes(text); // запись массива байтов в файл fstream.Write(input, 0, input.Length); Console.WriteLine("Текст записан в файл"); // перемещаем указатель в конец файла, до конца файла- пять байт fstream.Seek(-5, SeekOrigin.End); // минус 5 символов с конца потока // считываем четыре символов с текущей позиции byte output = new byte; fstream.Read(output, 0, output.Length); // декодируем байты в строку string textFromFile = Encoding.Default.GetString(output); Console.WriteLine("Текст из файла: {0}", textFromFile); // worl // заменим в файле слово world на слово house string replaceText = "house"; fstream.Seek(-5, SeekOrigin.End); // минус 5 символов с конца потока input = Encoding.Default.GetBytes(replaceText); fstream.Write(input, 0, input.Length); // считываем весь файл // возвращаем указатель в начало файла fstream.Seek(0, SeekOrigin.Begin); output = new byte; fstream.Read(output, 0, output.Length); // декодируем байты в строку textFromFile = Encoding.Default.GetString(output); Console.WriteLine("Текст из файла: {0}", textFromFile); // hello house } Console.Read(); } }
Консольный вывод:
Текст записан в файл Текст из файл: worl Текст из файла: hello house
Вызов fstream.Seek(-5, SeekOrigin.End) перемещает курсор потока в конец файлов назад на пять символов:
То есть после записи в новый файл строки "hello world" курсор будет стоять на позиции символа "w".
После этого считываем четыре байта начиная с символа "w". В данной кодировке 1 символ будет представлять 1 байт. Поэтому чтение 4 байтов будет эквивалентно чтению четырех сиволов: "worl".
Затем опять же перемещаемся в конец файла, не доходя до конца пять символов (то есть опять же с позиции символа "w"), и осуществляем запись строки "house". Таким образом, строка "house" заменяет строку "world".
Закрытие потока
В примерах выше дл закрытия потока применяется конструкция using . После того как все операторы и выражения в блоке using отработают, объект FileStream уничтожается. Однако мы можем выбрать и другой способ:
FileStream fstream = null; try { fstream = new FileStream(@"D:\note3.dat", FileMode.OpenOrCreate); // операции с потоком } catch(Exception ex) { } finally { if (fstream != null) fstream.Close(); }
Если мы не используем конструкцию using, то нам надо явным образом вызвать метод Close() : fstream.Close()