1629295407-c61bfe4caba98380ea3e7cdae6295416 (846200), страница 74
Текст из файла (страница 74)
Следующая программа записывает в файл алфавит прописнымибуквами, а затем беспорядочно считывает его.// Демонстрация произвольного доступа к файлу.using System;using System.IO;class RandomAccessDemo {public static void Main() {FileStream f;char ch;try {f = new FileStream("random.dat", FileMode.Create);}catch(IOException exc) {Console.WriteLine(exc.Message);return;}// Записываем в файл алфавит.for(int i=0; i < 26; i++) {}try {f.WriteByte( (byte) ('A'+i) );}catch(IOException exc) {Console.WriteLine(exc.Message);return;}try {// Теперь считываем отдельные значения.f.Seek(0, SeekOrigin.Begin); // Поиск первого байта.ch = (char) f.ReadByte();Console.WriteLine("Первое значение равно " + ch);f.Seek(1, SeekOrigin.Begin); // Поиск второго байта.ch = (char) f.ReadByte();Console.WriteLine("Второе значение равно " + ch);f.Seek(4, SeekOrigin.Begin); // Поиск пятого байта.ch = (char) f.ReadByte();Console.WriteLine("Пятое значение равно " + ch);Console.WriteLine();// Теперь считываем значения через одно.Console.WriteLine("Выборка значений через одно: ");for(int i=0; i < 26; i += 2) {f.Seek(i, SeekOrigin.Begin);// Переход// к i-му байту.ch = (char) f.ReadByte();Console.Write(ch + " ");}}Глава 14.
Использование средств ввода-вывода401}}catch(IOException exc) {Console.WriteLine(exc.Message);}Console.WriteLine(); f.Close();При выполнении этой программы получены такие результаты:Первое значение равно АВторое значение равно ВПятое значение равно ЕВыборка значений через одно:A C E G I K M O Q S U W YИспользование класса MemoryStreamНе всегда удобно выполнять операции ввода-вывода непосредственно с помощьюфизического устройства. Иногда полезно считывать входные данные из массива илизаписывать их в массив. В этом случае стоит воспользоваться классом MemoryStream.Класс MemoryStream — это реализация класса Stream, в которой для операций вводавывода используются массивы байтов.
Вот как выглядит конструктор этого класса:MemoryStream(byte[] buf)Здесь элемент buf — это массив байтов, который предполагается использовать воперациях ввода-вывода в качестве источника и/или приемника информации. В поток,создаваемый этим конструктором, можно записывать данные или считывать их в него. Этотпоток поддерживает метод Seek(). Перед использованием этого конструктора необходимопозаботиться о достаточном размере массива buf, чтобы он позволил сохранить всенаправляемые в него данные.Вот пример программы, которая демонстрирует использование классаMemoryStream:// Демонстрация использования класса MemoryStream.using System;using System.IO;class MemStrDemo {public static void Main() {byte[] storage = new byte[255];// Создаем поток с ориентацией на память.MemoryStream memstrm = new MemoryStream(storage);// Помещаем объект memstrm в оболочки StreamWriter//и StreamReader.StreamWriter memwtr = new StreamWriter(memstrm);StreamReader memrdr = new StreamReader(memstrm);// Записываем данные в память с помощью// объекта memwtr.for(int i=0; i < 10; i++)402Часть I.
Язык C#memwtr.WriteLine("'byte[" + i + "]: " + i);// Ставим в конце точку.memwtr.Write('.');memwtr.Flush();Console.WriteLine("Считываем данные прямо из массива storage: ");// Отображаем напрямую содержимое памяти.foreach(char ch in storage) {if(ch == '.') break;Console.Write(ch);}Console.WriteLine("\nСчитываем данные посредством объекта memrdr: ");}}// Считываем данные из объекта memstrm, используя// средство чтения потоков.memstrm.Seek(0, SeekOrigin.Begin); // Установка// указателя позиции в начало потока.string str = memrdr.ReadLine();while(str != null) {str = memrdr.ReadLine();if(str.CompareTo(".") == 0) break;Console.WriteLine(str);}Вот как выглядят результаты выполнения этой программыСчитываем данные прямо из массива storage:byte[0]: 0byte[1]: 1byte[2]: 2byte[3]: 3byte[4]: 4byte[5]: 5byte[6]: 6byte[7]: 7byte[8]: 8byte[9]: 9Считываем данные посредством объекта memrdr:byte[1]: 1byte[2]: 2byte[3]: 3byte[4]: 4byte[5]: 5byte[6]: 6byte[7]: 7byte[8]: 8byte[9]: 9Глава 14.
Использование средств ввода-вывода403В этой программе создается байтовый массив storage. Этот массив затемиспользуется в качестве базовой области памяти для объекта memstrm классаMemoryStream. На основе объекта memstrm создаются объект класса StreamReader сименем memrdr и объект класса StreamWriter с именем memwtr. Через объект memwtrданные записываются в поток, ориентированный на конкретную область памяти. Обратитевнимание на то, что после записи выходных данных для объекта memwtr вызывается методflush().
Тем самым гарантируется, что содержимое буфера, связанного с потокомmemwtr, реально перепишется в базовый массив. Затем содержимое этого байтовогомассива отображается “вручную”, т.е. с помощью цикла foreach. После этогопосредством метода Seek() указатель позиции устанавливается в начало потока, и егосодержимое считывается с использованием объекта memrdr.Потоки, ориентированные на память, весьма полезны в программировании.Например, можно заблаговременно составить выходные данные и хранить их в массиве дотех пор, пока в них не отпадет необходимость. Такой подход особенно полезен впрограммировании для такой GUI-среды, как Windows. Можно также перенаправитьстандартный поток для считывания данных из массива.
Это полезно, например, при вводетестовой информации в программу.Использование классов StringReader иStringWriterВнекоторыхприложенияхпривыполненииоперацийввода-вывода,ориентированных на использование памяти в качестве базовой области хранения данных,проще работать не с байтовыми (byte-) массивами, а со строковыми (string-). В этомслучае используйте классы StringReader и StringWriter. Класс StringReaderнаследует класс TextReader, а класс StringWriter — класс TextWriter.Следовательно, эти потоки имеют доступ к методам, определенным в этих классах.Например, вы можете вызывать метод ReadLine() для объекта класса StringReader иметод WriteLine() для объекта класса StringWriter.Конструктор класса StringReader имеет следующий вид:StringReader(string str)Здесь параметр str представляет собой строку, из которой должны считыватьсяданные.В классе StringWriter определено несколько конструкторов.
Мы будемиспользовать такой:StringWriter()Этот конструктор создает “записывающий” механизм, который помещает выходныеданные в строку. Эта строка автоматически создается объектом класса StringWriter.Содержимое строки можно получить, вызвав метод ToString().Рассмотрим пример использования классов StringReader и StringWriter.// Демонстрация использования классов StringReader// и StringWriter.using System;using System.IO;class StrRdrDemo {public static void Main() {// Создаем объект класса StringWriter.404Часть I. Язык C#StringWriter strwtr = new StringWriter();// Записываем данные в StringWriter-объект.for(int i=0; i < 10; i++)strwtr.WriteLine("Значение i равно: " + i);// Создаем объект класса StringReader.StringReader strrdr = new StringReader(strwtr.ToString() );}}// Теперь считываем данные из StringReader-объекта.string str = strrdr.ReadLine();while(str != null) {str = strrdr.ReadLine();Console.WriteLine(str);}Результаты выполнения этой программы имеют такой вид:Значение i равно: 1Значение i равно: 2Значение i равно: 3Значение i равно: 4Значение i равно: 5Значение i равно: 6Значение i равно: 7Значение i равно: 8Значение i равно: 9Эта программа сначала создает объект класса StringWriter с именем strwtr изаписывает в него данные с помощью метода WriteLine().
Затем создается объект классаStringReader с использованием строки, содержащейся в объекте strwtr, и методаToString(). Наконец, содержимое строки считывается с помощью методаReadLine().Преобразование числовых строк во внутреннеепредставлениеПрежде чем завершить тему ввода-вывода, рассмотрим метод, который будет весьмаполезен программистам при считывании числовых строк. Как вы знаете, C#-методWriteLine() предоставляет удобный способ вывода данных различных типов (включаячисловые значения таких встроенных типов, как int и double) на консольное устройство.Следовательно, метод WriteLine() автоматически преобразует числовые значения вудобную для восприятия человеком форму.
Однако C# не обеспечивает обратную функцию,т.е. метод ввода, который бы считывал и преобразовывал строковые представлениячисловых значений во внутренний двоичный формат. Например, не существует методаввода данных, который бы считывал такую строку, как “100”, и автоматическипреобразовывал ее в соответствующее двоичное значение, которое можно было бы хранитьв int-переменной. Для решения этой задачи понадобится метод, определенный для всехвстроенных числовых типов, — Parse().Глава 14. Использование средств ввода-вывода405Приступая к решению этой задачи, необходимо отметить такой важный факт.
Всевстроенные C#-типы (например, int и double) в действительности являются лишьпсевдонимами (т.е. другими именами) для структур, определенных в среде .NET Framework.Компания Microsoft заявляет, что понятия C#-типа и .NET-типа структуры неразличимы.Первое — просто еще одно имя для другого. Поскольку C#-типы значений поддерживаютсяструктурами, они имеют члены, определенные для этих структур.Ниже представлены .NET-имена структур и их C#-эквиваленты (в виде ключевыхслов) для числовых типов..NET-имя структурыDecimalDoubleSingleInt16Int32Int64UInt16UInt32UInt64ByteSbyteC#-имяdecimaldoublefloatshortintlongushortuintulongbytesbyteЭти структуры определены в пространстве имен System. Таким образом, составноеимя для структуры Int32 “звучит” как System.Int32.
Для этих структур определенширокий диапазон методов, которые способствуют полной интеграции типов значений вC#-иерархию объектов. В качестве дополнительного “вознаграждения” эти числовыеструктуры также определяют статические методы, которые преобразуют числовую строку всоответствующий двоичный эквивалент. Эти методы преобразования представлены вследующей таблице. Каждый метод возвращает двоичное значение, которое соответствуетстроке.СтруктураМетод преобразованияDecimalDoubleSingleInt64Int32Int16UInt64UInt32UInt16ByteSBytestaticstaticstaticstaticstaticstaticstaticstaticstaticstaticstaticdecimal Parse(string str)double Parse(string str)float Parse(string str)long Parse(string str)int Parse(string str)short Parse(string str)ulong Parse(string str)uint Parse(string str)ushort Parse(string str)byte Parse(string str)sbyte Parse(string str)Методы Parse() генерируют исключение типа FormatException, если параметрstr не содержит числа, допустимого для типа вызывающего объекта.