1629295407-c61bfe4caba98380ea3e7cdae6295416 (846200), страница 73
Текст из файла (страница 73)
Его наиболее употребительный конструктор имееттакой вид:BinaryReader(Stream, inputStream)Здесь элемент inputStream означает поток, из которого считываются данные.Чтобы выполнить чтение из файла, можно использовать для этого параметра объект,созданный классом FileStream, Если поток inputStream имеет null-значение,генерируется исключение типа ArgumentNullException, а если поток inputStreamне открыт для чтения,— исключение типа ArgumentException.В классе BinaryReader предусмотрены методы для считывания всех простых C#типов. Наиболее употребимые из них показаны в табл. 14.6. Обратите внимание на то, чтометод ReadString() считывает строку, которая хранится с использованием внутреннегоформата, включающего спецификатор длины.
При обнаружении конца потока все этиметоды генерируют исключение типа EndOfStreamException, а при возникновенииошибки — исключение типа IOException. В классе BinaryReader также определеныследующие версии метода Read():МетодОписаниеint Read()Возвращает целочисленное представление следующегодоступного символа из вызывающего входного потока. Приобнаружении конца файла возвращает значение -1Делает попытку прочитать num байтов в массив buf, начиная сэлемента buf[offset], и возвращает количество успешносчитанных байтовint Read(byte[] buf,int offset,int num)int Read(char[] buf,int offset,int num)Делает попытку прочитать num символов в массив buf,начиная с элемента buf[offset], и возвращает количествоуспешно считанных символовВ случае неудачного исхода операции чтения эти методы генерируют исключениетипа IOException.Глава 14.
Использование средств ввода-вывода395В классе BinaryReader также определен стандартный метод Close().Таблица 14.6. Методы ввода данных, определенные в классе BinaryReaderМетодОписаниеbool ReadBoolean()byte ReadByte()sbyte ReadSByte()byte[] ReadBytes(int num)char ReadChar()char[] ReadChars(int num)double ReadDouble()float ReadSingle()short ReadInt16()int ReadInt32()long ReadInt64()ushort ReadUInt16()uint ReadUInt32()ulong ReadUInt64()string ReadString()Считывает bool-значениеСчитывает byte-значениеСчитывает sbyte-значениеСчитывает num байтов и возвращает их в виде массиваСчитывает char-значениеСчитывает num символов и возвращает их в виде массиваСчитывает double-значениеСчитывает float-значениеСчитывает short-значениеСчитывает int-значениеСчитывает long-значениеСчитывает ushort-значениеСчитывает uint-значениеСчитывает ulong-значениеСчитывает string-значение, представленное во внутреннемдвоичном формате, который включает спецификатор длины.Этот метод следует использовать для считывания строки,которая была записана с помощью объекта класса BinaryWriterДемонстрация использования двоичного ввода-выводаРассмотримпрограмму,котораяиллюстрируетиспользованиеклассовBinaryReader и BinaryWriter.
Она записывает в файл данные различных типов, азатем считывает их.// Запись в файл двоичных данных с последующим//их считыванием.using System;using System.IO;class RWData {public static void Main() {BinaryWriter dataOut;BinaryReader dataIn;int i = 10;double d = 1023.56;bool b = true;try {dataOut = newBinaryWriter(new FileStream("testdata",FileMode.Create));}catch(IOException exc) {Console.WriteLine(exc.Message +"\nНе удается открыть файл.");396Часть I.
Язык C#return;}try {Console.WriteLine("Запись "dataOut.Write(i);Console.WriteLine("Запись "dataOut.Write(d);Console.WriteLine("Запись "dataOut.Write(b);Console.WriteLine("Запись "dataOut.Write(12.2 * 7.4);}+ i);+ d);+ b);+ 12.2 * 7.4);catch(IOException exc) {Console.WriteLine(exc.Message +"\nОшибка при записи.");}dataOut.Close();Console.WriteLine();// Теперь попробуем прочитать эти данные.try {dataIn = newBinaryReader(new FileStream("testdata",FileMode.Open));}catch(FileNotFoundException exc) {Console.WriteLine(exc.Message +"\nНе удается открыть файл.");return;}try {i = dataIn.ReadInt32();Console.WriteLine("Считываниеd = dataIn.ReadDouble();Console.WriteLine("Считываниеb = dataIn.ReadBoolean();Console.WriteLine("Считываниеd = dataIn.ReadDouble();Console.WriteLine("Считывание}" + i);" + d);" + b);" + d);catch(IOException exc) {Console.WriteLine(exc.Message +"Ошибка при считывании.");}}}dataIn.Close();Глава 14.
Использование средств ввода-вывода397При выполнении этой программы были получены следующие результаты:Запись 10Запись 1023,56Запись TrueЗапись 90,28Считывание 10Считывание 1023,56Считывание TrueСчитывание 90,28Если вы попробуете просмотреть содержимое файла testdata, созданного этойпрограммой, то увидите, что в нем содержатся двоичные данные, а не понятный длячеловека текст.А вот более практичный пример, который демонстрирует возможности C#-средствдвоичного ввода-вывода.
Следующая программа реализует очень простую программуинвентаризации. Для каждого элемента описи программа хранит соответствующеенаименование, имеющееся в наличии количество и стоимость. Программа предлагаетпользователю ввести наименование элемента описи, а затем выполняет поиск в базеданных. Если элемент найден, на экране отображается соответствующая информация./* Использование классов BinaryReader и BinaryWriterдля реализации простой программы инвентаризации. */using System;using System.IO;class Inventory {public static void Main() {BinaryWriter dataOut;BinaryReader dataIn;string item; // Наименование элемента.int onhand; // Количество, имеющееся в наличии.double cost; // Цена.try {dataOut = newBinaryWriter(new FileStream("inventory.dat",FileMode.Create));}catch(IOException exc) {Console.WriteLine(exc.Message +"\nНе удается открыть файл.");return;}// Записываем некоторые инвентаризационные данные// в файл.try {dataOut.Write("Молотки");dataOut.Write(10);dataOut.Write(3.95);dataOut.Write("Отвертки");dataOut.Write(18);dataOut.Write(1.50);398Часть I.
Язык C#dataOut.Write("Плоскогубцы");dataOut.Write(5);dataOut.Write(4.95);dataOut.Write("Пилы");dataOut.Write(8);dataOut.Write(8.95);}catch(IOException exc) {Console.WriteLine(exc.Message +"\nОшибка при записи.");}dataOut.Close();Console.WriteLine();// Теперь откроем файл инвентаризации// для чтения информации.try {dataIn = newBinaryReader(new FileStream("inventory.dat",FileMode.Open));}catch(FileNotFoundException exc) {Console.WriteLine(exc.Message +"\nНе удается открыть файл.");return;}// Поиск элемента, введенного пользователем.Console.Write("Введите наименование для поиска: ");string what = Console.ReadLine();Console.WriteLine();try {for(;;) {// Считываем запись из базы данных.item = dataIn.ReadString();onhand = dataIn.ReadInt32();cost = dataIn.ReadDouble();/* Если элемент в базе данных совпадает с элементомиз запроса, отображаем найденную информацию.
*/if(item.CompareTo(what) == 0) {Console.WriteLine(item + ": " + onhand +" штук в наличии. " +"Цена: {0:C} за каждую единицу.",cost);Console.WriteLine("Общая стоимость по наименованию <{0}>: {1:С}.",item, cost * onhand);break;}}}catch(EndOfStreamException) {Console.WriteLine("Элемент не найден.");Глава 14. Использование средств ввода-вывода399}}}catch(IOException exc) {Console.WriteLine(exc.Message + "Ошибка при чтении.");}dataIn.Close();Вот результаты выполнения этой программы:Введите наименование для поиска: ОтверткиОтвертки; 18 штук в наличии. Цена: $1.50 за каждую единицу.Общая стоимость по наименованию <Отвертки>: $27.00.В этой программе стоит обратить внимание на то, как хранится информация оналичии товаров на складе, а именно — на двоичный формат хранения данных.Следовательно, количество товаров, имеющихся в наличии, и их стоимость хранятся сиспользованием двоичного формата, а не в текстовом виде, удобном для восприятиячеловеком.
Это позволяет выполнять вычисления над числовыми данными, не делаядополнительных преобразований.Хотелось бы также обратить ваше внимание на то, как обнаруживается здесь конецфайла. Поскольку при достижении конца потока методы ввода двоичной информациигенерируют исключение типа EndOfStreamException, эта программа просто считываетсодержимое файла до тех пор, пока либо не найдет нужный элемент, либо не сгенерируетсяэто исключение. Таким образом, для обнаружения конца файла в данном случаеспециального механизма не требуется.Файлы с произвольным доступомДо сих пор мы использовали последовательные файлы, т.е.
файлы, доступ ксодержимому которых организован строго линейно, байт за байтом. Но в C# такжевозможен доступ к файлу, осуществляющийся случайным образом. В этом случаенеобходимо использовать метод Seek(), определенный в классе FileStream. Этот методпозволяет установить индикатор позиции (или указатель позиции) в любое место файла.Заголовочная информация о методе Seek() имеет следующий вид:long Seek(long newPos, SeekOrigin origin)Здесь элемент newPos означает новую позицию, выраженную в байтах, файловогоуказателя относительно позиции, заданной элементом origin. Элемент origin можетпринимать одно из значений, определенных перечислением SeekOrigin.ЗначениеОписаниеSeekOrigin.BeginSeekOrigin.CurrentSeekOrigin.EndПоиск от начала файлаПоиск от текущей позицииПоиск от конца файлаПосле обращению к методу Seek() следующая операция чтения или записи данныхбудет выполняться на новой позиции в файле.
Если при выполнении поиска возникнеткакая-либо ошибка, генерируется исключение типа IOException. Если базовый поток неподдерживает функцию запроса нужной позиции, генерируется исключение типаNotSupportedException.400Часть I. Язык C#Рассмотрим пример, который демонстрирует выполнение операций ввода-вывода спроизвольным доступом.