Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен
Шрифт:
Интервал:
Закладка:
Пусть имеется новый проект консольного приложения под названием FileStreamApp (и в файле кода C# импортировано пространство имен System.IO и System.Text). Целью будет запись простого текстового сообщения в новый файл по имени myMessage.dat. Однако с учетом того, что FileStream может оперировать только с низкоуровневыми байтами, объект типа System.String придется закодировать в соответствующий байтовый массив. К счастью, в пространстве имен System.Text определен тип Encoding, предоставляющий члены, которые кодируют и декодируют строки в массивы байтов.
После кодирования байтовый массив сохраняется в файле с помощью метода FileStream.Write(). Чтобы прочитать байты обратно в память, понадобится сбросить внутреннюю позицию потока (посредством свойства Position) и вызвать метод ReadByte(). Наконец, на консоль выводится содержимое низкоуровневого байтового массива и декодированная строка. Ниже приведен полный код:
using System;
using System.IO;
using System.Text;
// He забудьте импортировать пространства имен System.Text и System.IO.
Console.WriteLine("***** Fun with FileStreams *****n");
// Получить объект FileStream.
using(FileStream fStream = File.Open("myMessage.dat",
FileMode.Create))
{
// Закодировать строку в виде массива байтов.
string msg = "Hello!";
byte[] msgAsByteArray = Encoding.Default.GetBytes(msg);
// Записать byte[] в файл.
fStream.Write(msgAsByteArray, 0, msgAsByteArray.Length);
// Сбросить внутреннюю позицию потока.
fStream.Position = 0;
// Прочитать byte[] из файла и вывести на консоль.
Console.Write("Your message as an array of bytes: ");
byte[] bytesFromFile = new byte[msgAsByteArray.Length];
for (int i = 0; i < msgAsByteArray.Length; i++)
{
bytesFromFile[i] = (byte)fStream.ReadByte();
Console.Write(bytesFromFile[i]);
}
// Вывести декодированное сообщение.
Console.Write("nDecoded Message: ");
Console.WriteLine(Encoding.Default.GetString(bytesFromFile));
Console.ReadLine();
}
File.Delete("myMessage.dat");
В приведенном примере не только производится наполнение файла данными, но также демонстрируется основной недостаток прямой работы с типом FileStream: необходимость оперирования низкоуровневыми байтами. Другие производные от Stream типы работают в похожей манере. Например, чтобы записать последовательность байтов в область памяти, понадобится создать объект MemoryStream.
Как упоминалось ранее, в пространстве имен System.IO доступно несколько типов для средств чтения и записи, которые инкапсулируют детали работы с типами, производными от Stream.
Работа с типами StreamWriter и StreamReader
Классы StreamWriter и StreamReader удобны всякий раз, когда нужно читать или записывать символьные данные (например, строки). Оба типа по умолчанию работают с символами Unicode; тем не менее, это можно изменить за счет предоставления должным образом сконфигурированной ссылки на объект System.Text.Encoding. Чтобы не усложнять пример, предположим, что стандартная кодировка Unicode вполне устраивает.
Класс StreamReader является производным от абстрактного класса по имени TextReader, как и связанный с ним тип StringReader (обсуждается далее в главе). Базовый класс TextReader предоставляет каждому из своих наследников ограниченный набор функциональных средств, в частности возможность читать и "заглядывать" в символьный поток.
Класс StreamWriter (а также StringWriter, который будет рассматриваться позже) порожден от абстрактного базового класса по имени TextWriter, в котором определены члены, позволяющие производным типам записывать текстовые данные в текущий символьный поток.
Чтобы содействовать пониманию основных возможностей записи в классах StreamWriter и StringWriter, в табл. 20.8 перечислены основные члены абстрактного базового класса TextWriter.
На заметку! Вероятно, последние два члена класса TextWriter покажутся знакомыми. Вспомните, что тип System.Console имеет члены Write() и WriteLine(), которые выталкивают текстовые данные на стандартное устройство вывода. В действительности свойство Console.In является оболочкой для объекта TextWriter, a Console.Out — для TextWriter.
Производный класс StreamWriter предоставляет подходящую реализацию методов Write(), Close() и Flush(), а также определяет дополнительное свойство AutoFlush. Установка этого свойства в true заставляет StreamWriter выталкивать данные при каждой операции записи. Имейте в виду, что за счет установки AutoFlush в false можно достичь более высокой производительности, но по завершении работы с объектом StreamWriter должен быть вызван метод Close().
Запись в текстовый файл
Чтобы увидеть класс StreamWriter в действии, создайте новый проект консольного приложения по имени StreamWriterReaderApp и импортируйте пространства имен System.IO и System.Text. В показанном ниже коде с помощью метода File.CreateText() создается новый файл reminders.txt внутри текущего каталога выполнения. С применением полученного объекта StreamWriter в новый файл будут добавляться текстовые данные.
using System;
using System.IO;
using System.Text;
Console.WriteLine("***** Fun with StreamWriter / StreamReader *****n");
// Получить объект StreamWriter и записать строковые данные.
using(StreamWriter writer = File.CreateText("reminders.txt"))
{
writer.WriteLine("Don't forget Mother's Day this year...");
writer.WriteLine("Don't forget Father's Day this year...");
writer.WriteLine("Don't forget these numbers:");
for(int i = 0; i < 10; i++)
{
writer.Write(i + " ");
}
// Вставить новую строку.
writer.Write(writer.NewLine);
}
Console.WriteLine("Created file and wrote some thoughts...");
Console.ReadLine();
//File.Delete("reminders.txt");
После выполнения программы можете просмотреть содержимое созданного файла, который будет находиться в корневом каталоге проекта (Visual Studio Code) или в подкаталоге binDebugnet5.0 (Visual Studio). Причина в том, что при вызове CreateText() вы не указали абсолютный путь, а стандартным местоположением является текущий каталог выполнения сборки.
Чтение из текстового файла
Далее вы научитесь программно читать данные из файла, используя соответствующий тип StreamReader. Вспомните, что StreamReader является производным от абстрактного класса TextReader, который предлагает функциональность, описанную в табл. 20.9.
Расширьте текущий пример приложения с целью применения класса StreamReader, чтобы в нем можно было читать текстовые данные из файла reminders.txt:
Console.WriteLine("***** Fun with StreamWriter/StreamReader *****n");
...
// Прочитать данные из файла.
Console.WriteLine("Here are your thoughts:n");
using(StreamReader sr = File.OpenText("reminders.txt"))
{
string input = null;
while ((input = sr.ReadLine()) != null)
{
Console.WriteLine (input);
}