KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программирование » Герберт Шилдт - C# 4.0: полное руководство

Герберт Шилдт - C# 4.0: полное руководство

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Герберт Шилдт, "C# 4.0: полное руководство" бесплатно, без регистрации.
Перейти на страницу:

Обратите также внимание на то, как в этой программе обнаруживается конец файла. Методы двоичного ввода генерируют исключение EndOfStreamException по достижении конца потока, и поэтому файл читается до тех пор, пока не будет найден искомый предмет или сгенерировано данное исключение. Таким образом, для обнаружения конца файла никакого специального механизма не требуется.


Файлы с произвольным доступом

В предыдущих примерах использовались последовательные файлы, т.е. файлы со строго линейным доступом, байт за байтом. Но доступ к содержимому файла может быть и произвольным. Для этого служит, в частности, метод Seek(), определенный в классе FileStream. Этот метод позволяет установить указатель положения в файле, или так называемый указатель файла, на любое место в файле. Ниже приведена общая форма метода Seek():


long Seek(long offset, SeekOrigin origin)


где offset обозначает новое положение указателя файла в байтах относительно заданного начала отсчета (origin). В качестве origin может быть указано одно из приведенных ниже значений, определяемых в перечислении SeekOrigin.


Значение - Описание


SeekOrigin.Begin - Поиск от начала файла

SeekOrigin.Current - Поиск от текущего положения

SeekOrigin.End - Поиск от конца файла


Следующая операция чтения или записи после вызова метода Seek() будет выполняться, начиная с нового положения в файле, возвращаемого этим методом. Если во время поиска в файле возникает ошибка, то генерируется исключение IOException. Если же запрос положения в файле не поддерживается базовым потоком, то генерируется исключение NotSupportedException. Кроме того, могут быть сгенерированы и другие исключения.

В приведенном ниже примере программы демонстрируется ввод-вывод в файл с произвольным доступом. Сначала в файл записываются прописные буквы английского алфавита, а затем его содержимое считывается обратно в произвольном порядке.


// Продемонстрировать произвольный доступ к файлу.

using System;

using System.IO;

class RandomAccessDemo {

  static void Main() {

    FileStream f = null;

    char ch;


    try {

      f = new FileStream("random.dat", FileMode.Create);

      // Записать английский алфавит в файл,

      for (int i=0; i < 26; i++) f.WriteByte((byte)('A'+i));


      //А теперь считать отдельные буквы английского алфавита.

      f.Seek(0, SeekOrigin.Begin); // найти первый байт

      ch = (char) f.ReadByte() ;

      Console.WriteLine("Первая буква: " + ch) ;


      f.Seek(l, 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 + " ") ;

      }

    }

    catch(IOException exc) {

       Console.WriteLine("Ошибка ввода-вывода" + exc.Message);

    } finally {

      if(f != null) f.Close();

    }

    Console.WriteLine() ;

  }

}


При выполнении этой программы получается следующий результат.


Первая буква: А

Вторая буква: В

Пятая буква: Е


Буквы алфавита, через одну:

А С Е G I K M O Q S U W Y


Несмотря на то что метод Seek() имеет немало преимуществ при использовании с файлами, существует и другой способ установки текущего положения в файле с помощью свойства Position. Как следует из табл. 14.2, свойство Position доступно как для чтения, так и для записи. Поэтому с его помощью можно получить или же установить текущее положение в файле. В качестве примера ниже приведен фрагмент кода из предыдущей программы записи и чтения из файла с произвольным доступом random.dat, измененный с целью продемонстрировать применение свойства Position.


Console.WriteLine("Буквы алфавита через одну: ");

for(int i=0; i < 26; i += 2)    {

  f.Position = i; // найти i-й символ посредством свойства Position

  ch = (char) f.ReadByte();

  Console.Write(ch + " ");

}


Применение класса MemoryStream

Иногда оказывается полезно читать вводимые данные из массива или записывать выводимые данные в массив, а не вводить их непосредственно из устройства или выводить прямо на него. Для этой цели служит класс MemoryStream. Он представляет собой реализацию класса Stream, в которой массив байтов используется для ввода и вывода. В классе MemoryStream определено несколько конструкторов. Ниже представлен один из них:


MemoryStream(byte[] buffer)


где buffer обозначает массив байтов, используемый в качестве источника или адресата в запросах ввода-вывода. Используя этот конструктор, следует иметь в виду, что массив buffer должен быть достаточно большим для хранения направляемых в него данных.

В качестве примера ниже приведена программа, демонстрирующая применение класса MemoryStream в операциях ввода-вывода.


// Продемонстрировать применение класса MemoryStream.

using System;

using System.IO;

class MemStrDemo {

  static void Main() {

    byte[] storage = new byte[255];


    // Создать запоминающий поток.

    MemoryStream memstrm = new MemoryStream(storage);


    // чтения и записи данных в потоки.

    StreamWriter memwtr = new StreamWriter(memstrm);

    StreamReader memrdr = new StreamReader(memstrm);

    try {

      // Записать данные в память, используя объект memwtr.

      for(int i=0; i < 10; i++)

      memwtr.WriteLine("byte [" + i + "]: " + i);


      // Поставить в конце точку,

      memwtr.WriteLine(".");

      memwtr.Flush() ;

      Console.WriteLine("Чтение прямо из массива storage: ");

      // Отобразить содержимое массива 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[0] == '.') break;

        Console.WriteLine(str);

      }

    } catch(IOException exc) {

      Console.WriteLine("Ошибка ввода-вывода" + exc.Message);

    } finally {

      // Освободить ресурсы считывающего и записывающего потоков,

      memwtr.Close();

      memrdr.Close() ;

    }

  }

}


Вот к какому результату приводит выполнение этой программы.


Чтение прямо из массива storage:

byte [0]: 0

byte [1]: 1

byte [2]: 2

byte [3]: 3

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*