Книга: C# 4.0: полное руководство
Переадресация стандартных потоков
Разделы на этой странице:
Переадресация стандартных потоков
Как упоминалось ранее, стандартные потоки, например Console.In
, могут быть переадресованы. И чаще всего они переадресовываются в файл. Когда стандартный поток переадресовывается, то вводимые или выводимые данные направляются в новый поток в обход устройств, используемых по умолчанию. Благодаря переадресации стандартных потоков в программе может быть организован ввод команд из дискового файла, создание файлов журнала регистрации и даже чтение входных данных из сетевого соединения.
Переадресация стандартных потоков достигается двумя способами. Прежде всего, это делается при выполнении программы из командной строки с помощью операторов <
и >
, переадресовывающих потоки Console.In
и Console.Out
соответственно. Допустим, что имеется следующая программа.
using System;
class Test {
static void Main() {
Console.WriteLine("Это тест.");
}
}
Если выполнить эту программу из командной строки Test > log
то символьная строка "Это тест." будет выведена в файл log. Аналогичным образом переадресуется ввод. Но для переадресации ввода указываемый источник входных данных должен удовлетворять требованиям программы, иначе она "зависнет".
Операторы <
и >
, выполняющие переадресацию из командной строки, не являются составной частью С#, а предоставляются операционной системой. Поэтому если в рабочей среде поддерживается переадресация ввода-вывода, как, например, в Windows, то стандартные потоки ввода и вывода можно переадресовать, не внося никаких изменений в программу. Тем не менее существует другой способ, позволяющий осуществлять переадресацию стандартных потоков под управлением самой программы. Для этого служат приведенные ниже методы SetIn()
, SetOut()
и SetError()
, являющиеся членами класса Console
.
static void SetIn(TextReader новый_поток_ввода)
static void SetOut(TextWriter новый_поток_вывода)
static void SetError(TextWriter новый_поток_сообщений_об_ошибках)
Таким образом, для переадресации ввода вызывается метод SetIn()
с указанием требуемого потока. С этой целью может быть использован любой поток ввода, при условии, что он является производным от класса TextReader
. А для переадресации вывода вызывается метод SetOut()
с указанием требуемого потока вывода, который должен быть также производным от класса TextReader
. Так, для переадресации вывода в файл достаточно указать объект класса FileStream
, заключенный в оболочку класса StreamWriter
. Соответствующий пример программы приведен ниже.
// Переадресовать поток Console.Out.
using System;
using System.IO;
class Redirect {
static void Main() {
StreamWriter log_out = null;
try {
log_out = new StreamWriter("logfile.txt");
// Переадресовать стандартный вывод в файл logfile.txt.
Console.SetOut(log_out);
Console.WriteLine("Это начало файла журнала регистрации.");
for(int i=0; i<10; i++) Console.WriteLine(i);
Console.WriteLine("Это конец файла журнала регистрации.");
} catch(IOException exc) {
Console.WriteLine("Ошибка ввода-вывода" + exc.Message);
} finally {
if(log_out != null) log_out.Close();
}
}
}
При выполнении этой программы на экран ничего не выводится, но файл logfile. txt будет содержать следующее.
Это начало файла журнала регистрации.
0
1
2
3
4
5
6
7
8
9
Это конец файла журнала регистрации.
Попробуйте сами поупражняться в переадресации других встроенных потоков.
Чтение и запись двоичных данных
В приведенных ранее примерах демонстрировались возможности чтения и записи байтов или символов. Но ведь имеется также возможность (и ею пользуются часто) читать и записывать другие типы данных. Например, можно создать файл, содержащий данные типа int
, double
или short
. Для чтения и записи двоичных значений встроенных в C# типов данных служат классы потоков BinaryReader
и BinaryWriter
. Используя эти потоки, следует иметь в виду, что данные считываются и записываются во внутреннем двоичном формате, а не в удобочитаемой текстовой форме.
Класс BinaryWriter
Класс BinaryWriter
служит оболочкой, в которую заключается байтовый поток, управляющий выводом двоичных данных. Ниже приведен наиболее часто употребляемый конструктор этого класса:
BinaryWriter(Stream output)
где output обозначает поток, в который выводятся записываемые данные. Для записи в выходной файл в качестве параметра output может быть указан объект, создаваемый средствами класса FileStream
. Если же параметр output оказывается пустым, то генерируется исключение ArgumentNullException
. А если поток, определяемый параметром output, не был открыт для записи данных, то генерируется исключение ArgumentException
. По завершении вывода в поток типа BinaryWriter
его нужно закрыть. При этом закрывается и базовый поток.
В классе BinaryWriter
определены методы, предназначенные для записи данных всех встроенных в C# типов. Некоторые из этих методов перечислены в табл. 14.5. Обратите внимание на то, что строковые данные типа string
записываются во внутреннем формате с указанием длины строки. Кроме того, в классе BinaryWriter
определены стандартные методы Close()
и Flush()
, действующие аналогично описанному выше.
Таблица 14.5. Наиболее часто используемые методы, определенные в классе BinaryWriter
Метод - Описание
void Write(sbyte value) - Записывает значение типа sbyte со знаком
void Write(byte value) - Записывает значение типа byte без знака
void Write(byte[] buffer) - Записывает массив значений типа byte
void Write(short value) - Записывает целочисленное значение типа short (короткое целое)
void Write(ushort value) - Записывает целочисленное значение типа ushort (короткое целое без знака)
void Write (int value) - Записывает целочисленное значение типа int
void Write(uint value) - Записывает целочисленное значение типа uint (целое без знака)
void Write(long value) - Записывает целочисленное значение типа long (длинное целое)
void Write(ulong value) - Записывает целочисленное значение типа ulong (длинное целое без знака)
void Write(float value) - Записывает значение типа float (с плавающей точкой одинарной точности)
void Write(double value) - Записывает значение типа double (с плавающей точкой двойной точности)
void Write(decimal value) - Записывает значение типа decimal (с двумя десятичными разрядами после запятой)
void Write(char ch) - Записывает символ
void Write (char[] buffer) - Записывает массив символов
void Write(string value) Записывает строковое значение типа string, представленное во внутреннем формате с указанием длины строки
Класс BinaryReader
Класс BinaryReader
служит оболочкой, в которую заключается байтовый поток, управляющий вводом двоичных данных. Ниже приведен наиболее часто употребляемый конструктор этого класса:
BinaryReader(Stream input)
где input обозначает поток, из которого вводятся считываемые данные. Для чтения из входного файла в качестве параметра input может быть указан объект, создаваемый средствами класса FileStream
. Если же поток, определяемый параметром input, не был открыт для чтения данных или оказался недоступным по иным причинам, то генерируется исключение ArgumentException
. По завершении ввода из потока типа BinaryReader
его нужно закрыть. При этом закрывается и базовый поток.
В классе BinaryReader
определены методы, предназначенные для чтения данных всех встроенных в C# типов. Некоторые из этих методов перечислены в табл. 14.6. Следует, однако, иметь в виду, что в методе Readstring()
считывается символьная строка, хранящаяся во внутреннем формате с указанием ее длины. Все методы данного класса генерируют исключение IOException
, если возникает ошибка ввода. Кроме того, могут быть сгенерированы и другие исключения.
Таблица 14.6. Наиболее часто используемые методы, определенные в классе BinaryReader
Метод - Описание
bool ReadBoolean() - Считывает значение логического типа bool
byte ReadByte() - Считывает значение типа byte
sbyte ReadSByte() - Считывает значение типа sbyte
byte[] ReadBytes(int count) - Считывает количество count байтов и возвращает их в виде массива
char ReadChar() - Считывает значение типа char
char[] ReadChars(int count) - Считывает количество count символов и возвращает их в виде массива
decimal ReadDecimal() - Считывает значение типа decimal
double ReadDouble() - Считывает значение типа double
float ReadSingle() - Считывает значение типа float
short Readlnt16() - Считывает значение типа short
int Readlnt32() - Считывает значение типа int
long Readlnt64() - Считывает значение типа long
ushort ReadUIntl6() - Считывает значение типа ushort
uint ReadUInt32() - Считывает значение типа uint
ulong ReadUInt64() - Считывает значение типа ulong
string ReadString() - Считывает значение типа string, представленное во внутреннем двоичном формате с указанием длины строки. Этот метод следует использовать для считывания строки, которая была записана средствами класса BinaryWriter
В классе BinaryWriter
определены также три приведенных ниже варианта метода Read()
.
При неудачном исходе операции чтения эти методы генерируют исключение IOException
. Кроме того, в классе BinaryReader
определен стандартный метод Close().
Метод - Описание
int Read() - Возвращает целочисленное представление следующего доступного символа из вызывающего потока ввода. При обнаружении конца файла возвращает значение -1
int Read(byte [] buffer,int offset, int count) - Делает попытку прочитать количество count байтов в массив buffer, начиная с элемента buffer[offset], и возвращает количество успешно считанных байтов
int Read(char[]buffer, int offset, int count) - Делает попытку прочитать количество count символов в массив buffer, начиная с элемента buffer[offset], и возвращает количество успешно считанных символов
- Организация системы ввода-вывода в C# на потоках
- Классы потоков
- Консольный ввод-вывод
- Класс FileStream и байтовый ввод-вывод в файл
- Символьный ввод-вывод в файл
- Переадресация стандартных потоков
- Демонстрирование двоичного ввода-вывода
- Файлы с произвольным доступом
- Применение класса MemoryStream
- Применение классов StringReader и StringWriter
- Класс File
- Преобразование числовых строк в их внутреннее представление
- 4.12.2. Переадресация
- Достоинства и недостатки потоков
- 6.2. Создание и автоматическое заполнение бланков стандартных документов
- 4.3 Потоковый редактор sed
- Глава 6 Автоматизация стандартных документов
- Множество потоков, соревнующихся между собой за обладание единственным ресурсом
- Совет 12. Разумно оценивайте потоковую безопасность контейнеров STL
- Необходимость в синхронизации потоков
- 26.5. Собственные данные потоков
- Объекты синхронизации потоков
- 12.5.1. Использование стандартных функций: setjmp() и longjmp()
- Реализация потоков в ядре Linux