Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
файлы лекция (основная).pdf
Скачиваний:
32
Добавлен:
15.04.2015
Размер:
938.85 Кб
Скачать

значение -1, если был достигнут конец потока.

После отображения всех данных, хранящихся в потоке, мы закрываем поток методом Close:

ms.Close();

7.4 Доступ к буферу потока MemoryStream

Как вы уже знаете, поток MemoryStream может быть сформирован на базе предварительно проинициализированного массива байтов или путем последовательной записи в него данных методами Write и WriteByte. При этом данные фактически будуг храниться во внутреннем буфере потока.

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

Метод ТоАггау позволяет преобразовать поток (даже закрытый методом Close) в массив байтов.

Программа, исходный текст которой представлен в листинге 10, демонстрирует использование упомянутых выше методов.

Листинг 10.

using System; using System.IO;

namespace GetBuffer

{

class GetBufferApp

{

static void Main(string[] args)

{

MemoryStream ms = new MemoryStream();

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

{

ms.WriteByte(i);

}

ms.Flush();

byte[] buf = ms.GetBuffer();

foreach (byte bt in buf) Console,Write(bt);

Console.WriteLine(); ms.Close ();

byte[] buf1 = ms.ToArray();

foreach (byte bt in bufl) Console.Write(bt);

Console.ReadLine();

}

}

}

Получив управление, программа создаст поток в памяти и записывает в него 10 целых чисел. После этого происходит сброс буфера:

MemoryStream ms = new MemoryStream();

for (byte i = 0; 1 < 10; i + + )

{

ms.WriteByte(i);

}

ms.Flush ();

Далее наша программа получает доступ к буферу открытого потока, вызывая метод

GetBuffer:

byte[] buf = ms.GetBuffer ();

В результате в массив buf будет записано содержимое текущего буфера потока. Программа отображает его на консоли с помощью простого цикла:

foreach (byte bt in buf) Console.Write(bt);

Заметим, что, хотя мы записали в поток всего 10 байт, на консоль будут выведены не только записанные числа, но и дополнительные нули. Это получается потому, что по умолчанию размер буфера превышает 10 байт. Метод GetBuffer возвращает нам полное содержимое буфера потока, изначально проинициализированного нулевыми значениями.

После вывода содержимого буфера потока на консоль наша программа закрывает поток:

ms.Close ();

Несмотря на то что поток закрыт, хранящиеся в нем данные все еще могут быть доступны. С помощью метода ТоАггау программа может преобразовать закрытый поток в массив байтов, как это показано ниже:

byte[] bufl = ms.ТоАггау();

Далее содержимое полученного таким способом массива отображается на консоли:

foreach (byte bt in bufl) Console.Write(bt);

Обратите внимание, что во второй раз будет выведено только 10 чисел:

012345678900000000000000000000000000000000000000000000000000000000000000000

00000000000000000000000000000000000000000000000000000000000000000000000000000

00000000000000000000000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000

0123456789

Дело в том, что метод ТоАггау преобразует только те данные, которые были записаны в поток, а не весь буфер потока.

7.5 Потоки на базе строк string

Рассказывая о потоках в оперативной памяти, следует упомянуть и потоки, создаваемые на базе текстовых строк класса string.

Чтобы создать входной поток на базе строки string, вам потребуется класс StringReader.

Создав такой поток с помощью конструктора класса StringReader, программа сможет читать из него отдельные символы или блоки символов с помощью перегруженных методов Read.

Использование этих методов демонстрируется в программе, исходный текст которой представлен в листинге 14.11.

Листинг 11.

using System; using System.IO;

namespace StringReaderDemo

{

class StringReaderDemoApp

{

static void Main(string[] args)

{

string str = "Каждый охотник желает знать, где сидит фазан"; StringReader sr = new StringReader(str);

int ch;

while(true)

{

ch = sr.Read();

if(ch == -1) break; Console.Write((char)ch);

}

Console.WriteLine(); sr.Close();

sr = new StringReader(str); char[] b = new char[str.Length];

sr.Read(b, 0, 15); Console.WriteLine(b); sr.Close(); Console.ReadLine();

}

}

)

Вэтой программе мы определили текстовую строку str класса string, а затем создали на

ееоснове поток sr класса StringReader:

string str = "Каждый охотник желает знать, где сидит фазан"; StringReader sr = new StringReader(str);

Далее мы в цикле считываем символы из потока и отображаем их на консоли:

int ch;

while(true)

{

ch = sr.Read();

if (ch == -1) break; Console.Write((char)ch);

}

Заметим, что метод Read возвращает значение int, а не char. Поэтому перед отображением прочитанного символа на консоли мы выполняем необходимое явное преобразование типов.

Завершив работу с потоком, мы закрываем его обычным образом с помощью метода Close:

sr.Close();

Далее в программе демонстрируется чтение блока символов. Для этого мы снова открываем поток:

sr = new StringReader(str);

Используя перегруженный метод Read, мы читаем первые 15 символов из потока в

массив data:

char[] data = new char[str.Length]; sr.Read(data, 0, 15);

Далее программа отображает на консоли содержимое массива и закрывает поток:

Console.WriteLine(data);

sr.Close();

Вот что появится на консоли, после того как программа завершит свою работу:

Каждый охотник желает знать, где сидит фазан Каждый охотник

7.6 Потоки класса StringBuilder

С помощью класса StringBuilder вы можете создавать потоки на базе текстовых строк, которые затем поддаются изменению. Например, создав такой поток, программа может вставлять в произвольное место потока новые текстовые строки или добавлять их в конец потока, а также удалять и замещать фрагменты строк.

Основные приемы работы с потоками класса StringBuilder демонстрируются в программе, исходный текст которой представлен в листинге 12.

Листинг 12.

using System; using System.IO; using System.Text;

namespace StringBuilderDemo

{

class StringBuilderDemoApp

{

static void Main(string[] args)

{

StringBuilder sb = new StringBuilder("охотник желает");

sb.lnsert(0, "Каждый "); sb.Append(" знать, где сидит"};

StringWriter sw = new StringWriter(sb);

char[) data = {'ф' , 'a', 'з', 'a', 'н' , '.'}; sw.Write(data);

Console.WriteLine(sb);

sw.Close(); Console.ReadLine();

}

}

}

Прежде всего наша программа создаст поток StringBuilder с помощью конструктора и записывает в него фрагмент фразы про охотника:

StringBuilder sb = new StringBuilder("охотник желает");

Далее, пользуясь методами Insert и Append, программа вставляет один фрагмент фразы в начало потока, а другой — в конец потока:

sb.lnsert(0, "Каждый "); sb.Append(" знать, где сидит"};

При необходимости вы можете воспользоваться методами Remove и Replace соответственно для удаления из потока фрагмента строки и для замены его другим фрагментом.

Методу Remove в качестве первого параметра нужно передать начальный индекс удаляемого фрагмента, а в качестве второго — длину удаляемого фрагмента в байтах:

public Remove(int index, int size);

Что же касается метода Replace, то определено его несколько перегруженных вариантов.

Следующие два метода заменяют в потоке соответственно все заданные символы и строки другими:

public Replace(char chl, char ch2); public Replace(string strl, string str2);

Эти методы делают замену во всем потоке.

Следующие два метода позволяют ограничить область замены блоком, начало которого задано параметром index, а размер — параметром size:

public Replace(char chl, char ch2, int index, int size); public Replace(string strl, string str2, int index, int size);

Вернемся, однако, к описанию нашей программы.

На следующем шаге программа создает поток StringWriter на базе потока StringBuilder:

StringWriter sw = new StringWriter(sb);

Пользуясь этим потоком с помощью метода Write, паша программа дописывает в конец фразы последнее слово:

char[) data = {'ф' , 'a', 'з', 'a', 'н' , '.'}; sw.Write(data);

Далее содержимое потока выводится на консоль, после чего поток закрывается методом Close:

Console.WriteLine(sb); sw.Close();

В классе StringWriter определено множество перегруженных методов Write, позволяющих записывать в поток данные практически всех встроенных типов. Кроме того, предусмотрены аналогичные методы WriteLine, добавляющие после записи символ перевода строки.