Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

lab_13_14 / ЛАБ_13_C# / Средства ввода-вывода2

.doc
Скачиваний:
11
Добавлен:
02.02.2015
Размер:
378.37 Кб
Скачать

Лекция №13, Лаб.раб. №13

C#-система ввода-вывода

До настоящего времени рассмотрены наследование и бработка исключений. Наступила очередь рассмотреть иерархию классов. Все это составляет основу системы ввода- вывода С#. Реализация ввода- вывода выполняется с использованием понятия потоков. Поток (stream) – это абстракция, которая позволяет синтезировать (объединять составные части в целое) информацию либо потребляет ее. Поведение потока не зависит от особенностей организации физических устройств ввода-вывода, т.е., например, описание ввода-вывода на консольное устройство можно описать также, как и работу с дисковым файлом.

Отметм сразу, что на самом низком уровне С#-система ввода-вывода ( в дальнейшем ВВ) работает с байтами (byte – 8-битный код). Человек обычно использует понятие символа (char -16-бтный код). В коде ASCII переход от кода char к коду byte проводится просто отбрасыванием старшего байта. Для распространенных Unicode- символов байтовые потоки не подходят. В ВВ используются ряд классов для преобразования байтового потока в символьный и наоборот (для автоматического преобразования byte-char и char-byte ).

В пространстве имен System для этого применяются три встроенных потока, доступ к которым выполняется через свойства Console.In, Console.Out и Console.Error.

Свойство Console.Inотносится к стандартному входному потоку (по умолчанию это клавиатура, пример Console.ReadLine()).

Свойство Console.Out – относится к стандартному выходному потоку (по умолчанию это консоль, пример Console.WriteLine()).

Свойство Console.Error – относится к ошибкам в стандартном потоке (по умолчанию это консоль).

Эти потоки могут быть переориентированы на любое совместимое устройство ввода-вывода. Эти потоки работают с символами (записывают и считывают символы).

В С# определены байтовые и символьные потоки. Все классы потоков определены в постранстве имен System.IO. Для работы с ними в начале текста пограммы следует включать инструкцию using System.IO;. Так как класс Console определен в пространстве имен System для него эту инструкцию не включают.

1 Классы потоков

1.1 Класс Stream (System.IO.Stream) – абстрактный байтовый поток, базовый для остальных потоковых классов. Распространенные методы этого класса:

Метод

Описание

1

void Close()

Закрывает поток

2

void Flush()

Записывает содержимое потока в физическое устройство

3

Int ReadByte()

Возвращает целочисленное представление следующего доступного байта потока. При обнаружении конца файлавозвращает значение -1

4

Int Read(byte[ ] buf, int jffset,int numBytes)

Делает попытку прочитатm numBytes байт в массив buf, начиная с элемента buf[offset], возвращает количество успешно прочитанных байтов

5

Long Seek(long jffset, SeekOrigin origin)

Устанавливает ттекущню позициюпотока равнойуказанному значениюсмещения от заданного нгачала отсчета

6

Void WriteByte()byte b

Записывает один байт в выходной поток

7

Void Write(byte[] buf, int offset, int numBytes)

Записывает поддиапазон размеромnumbytesбайт из массива buf, начиная с элемента buf[offset]

Ошибки ввода-вывода сопровождаются исключеием IOEsception, при некорректной операции вырабатывается NotSupportedException.

Ниже в таблице описаны несколько свойств класса Stream

Свойство

Описание

1

Bool CanRead

Свойство равно true, если из потока можно считывать данные. Свойство предназначено для чтения

2

Bool CanSeek

Свойство равно true, если поток поддерживает функцию установки в заданную позицию (предназначено только для чтения)

3

Bool CanWrite

Свойство равно true, если в поток можно записывать даные (только для чтения)

4

Long Length

Свойство содержит длинну потока (только для чтения)

5

Long Position

Свойство представляет текущую позицию потока (можно как читать, так и устанавливать)

1.2 Байтовые классы потоков (выделены из класса Stream)

Класс потока

Описание

1

BufferedStream

Заключает в оболочку байтовый поток добавляет буферизацию (увеличивает поизводительность)

2

MemoryStream

Байтовый поток, разработанный для ввода-вывода

3

Bool CanWrite

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

1.3 Символьные классы потоков

Для создания символьного потока следует поместить байтовый поток в одну из символьных С#-оболочек. В вершине иерархии символьных потоков находятся абстрактные классы TextReader (для ввода данных) и TextWriter (для вывода данных). Ниже приведены методы ввода данных, определенных в классе TextReader.

Метод

Описание

1

void Close()

Закрывает источник ввода данных

2

int Peek()

Получает следующий символ из входного потока, но не удаляет его. Возвращает -1.если ни один символ не доступен

3

Int Read()

Возвращает целочисленное представление следующего доступного символа из вызывающего объекта входного потока. При обнаружении конца файла возвращает значение -1

4

Int Read(char[ ] buf, int offset, int numChars)

Делает попытку прочитатm numChars символов в массив buf, начиная с элемента buf[offset], возвращает количество успешно прочитанных символов

5

Int ReadBlock(char[ ]buf, int offset, int numChars)

Делает попытку прочитатm numChars символов в массив buf, начиная с элемента buf[offset], возвращает количество успешно прочитанных символов

6

String ReadLine()

Считывает следующую строку текста и возвращает ее как string-значение. При попытке прочитать признак конца файла возвращает null-значение

7

String ReadToEnd()

Считывает все символы, оставшиеся в потоке, и возвращаеи их как string-значение

В классе TextWriter определены методы Write() и WriteLine(). Ниже приведены основные из них.

Метод

Описание

1

void Write(int val)

Записывает значение типа int

2

Void Write(double val)

Записывает значение типа double

3

Void Write(bool val)

Записывает значение типа bool

4

VoidWriteLine(string val)

Записывает значение типа string c последующим символом новой строки

5

VoidWriteLine(unit val)

Записывает значение типа unit c последующим символом новой строки

6

VoidWriteLine(char val)

Записывает символ с последуюшим символом новой строки

Потоковые классы, определенные в классах TextReader и TextWriter

Потоковые классы

Описание

1

StreamReader

Предназначен для чтения символов из байтового потока.Этот класс является оболочкой для байтового входного потока

2

StreamWriter

Предназначен для чтения символов в байтовый поток.Этот класс является оболочкой для байтового выходного потока

3

StringReader

Предназначен для чтения символа из строки

4

StringWriter

Предназначен для записи символа в строку

1.4 Двоичные потоки

В С# определены два двоичных потока для прямого считывания и записи двоичных данных – BinaryReader и BinaryWriter для работы с двоичными файлами.

2 Практическая реализация ввода-вывода

2.1 Консольный ввод-вывод

2.1.1 Считывание данных из консольного входного потока

Класс TextReader → поток Console.In →

Класс Console → поток Console.In → методы Read()/ReadLine() – два метода для считывания одного символа/строки символов. Опишем считывание одного символа, описание методов static int Read() / static string ReadLine().

При выполнении Read() →ожидается нажатие клавиши → возввращается тип int → необходимо преобразовать в (char) →[Enter] → во входной поток вводятся два символа – возврат каретки + перевод строки, которые, как правило, перед следующем вводе следует удалить (просто считыванием из потока)

  • при ошибке →возврат -1,

  • при сбое → исключение IOException

Ниже приведены три фрагмента текста программы: считывание символа (Read()), считывание строки методом класса Console(Console.ReadLine()) и считывание строки методом базового класса TextReader.

№ 1

Рис 1 Ввод символа с клавиатуры

№ 2

// Ввод строки с помощью ReadLine()

сlass ReadString {

public static void Main()

{

string str;

Console.WriteLine("Ввести строку.");

str = Console.ReadLine();

Console.WriteLine(" Вы ввели: " + str);

}

}

Рис 2 Ввод строки с клавиатуры

№ 3

// Ввод строки с клавиатуры с потоком Console.In (с методом класса TextReader)

class ReadChars2

public static void Main()

{ string str;

Console.WriteLine("Ввести строку символов. ");

str = Console.In.ReadLine();

Console.WriteLine(" Введена строка : " + str);

}

}

Рис 3 Ввод строки с консоли с обращением к методу класса TextReader

4 Запись данных в консольный входной поток

Можно применить методы Write() или WriteLine() класса Console или потоки Console.Out и Console.Error

№ 4

// Запись данных во входной поток Console.Out.WriteLine(), Console.Error.WriteLine()

// с созданием ИС

using System;

class ErrOut

{ public static void Main()

{ int x = 20, y = 0;

int result;

Console.Out.WriteLine("\n Генерируется ИС - деление на 0. ");// Потоки Console.In/Out

Console.WriteLine("\n Искл.Сит.\n "); // Класс Console

try {

result = x / y; // Создается ИС

}

catch (DivideByZeroException exc) {

Console.Error.WriteLine(" " + exc.Message);

Console.Out.WriteLine("\n\n\n ");

}

}

}

Рис 4 В консольный входной поток включается обработка ИС – дел. на 0

Класс FileStream. Файловый ввод-вывод на побайтовой основе

Включение класса FileStream определяет потоковые классы в постранстве имен System.IO. Для их использования в начале текста программы следует включать using System.IO;.

Классы С# позволяют выполнять операции с дисковыми файлами. Операционные системы обрабатывают все файлы на побайтовой основе. На побайтовой основе С# позволяет поместить побайтовую обработку в символьный объект (для обработки текстовых файлов).

Открытие и закрытие файла

Для

№ 5

// Запись данных в файл d:\test1.txt

using System;

using System.IO;

class WriteToFile

{

public static void Main(string[] args)

{

FileStream fout;

// Открываем выходной файл 11

try

{ // Console.WriteLine("\n\n\n URA1 ");

fout = new FileStream("d:/ddd.doc", FileMode.Create); // 14

// Console.WriteLine("\n\n\n URA2");

}

catch (IOException exc)

{ // Console.WriteLine("\n\n\n URA3");

Console.WriteLine(exc.Message + "\n Ошибка при открытии выходного файла.");

return;

}

// Записываем в файл алфавит. 21

try

{ // Console.WriteLine("\n\n\n URA4");

for (char с = 'А'; с <= 'Я'; с++)

fout.WriteByte((byte)с);

}

catch (IOException exc)

{ // Console.WriteLine("\n\n\n URA5");

Console.WriteLine(exc.Message + " Ошибка при записи в файл.");

}

//Console.WriteLine("\n\n\n URA6");

fout.Close();

// Console.WriteLine("\n\n\n URA7");

}

}

ABCDEFGHIJKLMNOPQRSTUVWXYZ

Рис 5 Результаты записи данных в файл

№ 6 Считывание байтов из файла (из объектов класса FileStream)

// Отображение содержимого текстового файла CodeFile1.cs

//

using System;

using System.IO;

class ShowFile

{ public static void Main(string[] args)

{ int i;

FileStream fin;

try

{

Console.WriteLine("\n URA_1");

fin = new FileStream(args[0], FileMode.Open);

}

catch (FileNotFoundException exc)

{

Console.WriteLine("\n URA_2");

Console.WriteLine("\n " + exc.Message);

return;

}

catch (IndexOutOfRangeException exc)

{

Console.WriteLine("\n URA_3");

Console.WriteLine("\n " + exc.Message +

"\n Применение: ShowFile d:/dci/f115s/f115/CodeFile1.cs \n\n\n ");

return;

}

// Считываем байты до тех пор, пока не встретится EOF.

do

{

try

{

i = fin.ReadByte();

}

catch (Exception exc)

{

Console.WriteLine(exc.Message);

return;

}

if (i != -1) Console.Write((char)i + "U_4");

} while (i != -1);

fin.Close();

}

}

Рис 6 Результаты считывания байт с файла

??? № 7 Выполнение копирования файла (применение класса FileStream – f116)

/* Копирование файла. При этом следует указать имена исходного,

который копируется, и приемного файлов (куда копируется)

Имена файлов указываются в командной строке в виде

CopyFile d:/dom1.doc d:/dom2.doc (dom2 + dom1)

*/

using System;

using System.IO;

class CopyFile

{ public static void Main(string[] args)

{ int i;

FileStream fin;

FileStream fout;

try {

// Открываем входной файл

fin = new FileStream(args[0], FileMode.Open); // 17

}

catch (FileNotFoundException exc) {

Console.WriteLine("\n " + exc.Message + "\n Входной файл не найден.");

return;

}

// Открываем выходной файл

try {

fout = new FileStream(args[1], FileMode.Create);

} catch (IOException exc) {

Console.WriteLine("\n " + exc.Message +

"\n Ошибка при открытии выходного файла.");

return;

}

catch (IndexOutOfRangeException exc) {

Console.WriteLine(" " + exc.Message +

"\n Применение: CopyFile d:/dom1.doc d:/dom2.doc");

return;

}

// Копируем файл

try {

do { i = fin.ReadByte();

if (i != -1) fout.WriteByte((byte)i);

} while (i != -1);

}

catch (IOException exc) {

Console.WriteLine("\n " + exc.Message +

"\n Ошибка при чтении файла. ");

}

fin.Close();

fout.Close();

}

}

Файловый ввод-вывод с ориентацией на символы

№ 8 ??????

// "Клавиатура-диск" с применением класса StreamWriter

using System;

using System.IO;

class Kl_disk

{ public static void Main()

{ string str;

FileStream fout;

try {

Console.WriteLine("\n_U1");

fout = new FileStream("d:/domdfa.doc", FileMode.Create); // 14

Console.WriteLine("\n_U2");

} catch (IOException exc) {

Console.WriteLine("\n_U3");

Console.WriteLine(exc.Message + " Не удается открыть файл.");

return; }

StreamWriter fstr_out = new StreamWriter(fout);

Console.WriteLine(" Введите текст(`стоп` для завершения).");

do { Console.Write(": ");

str = Console.ReadLine();

if (str != "стоп")

{ str = str + "\r\n"; // Добавляем символ новой строки

try { Console.WriteLine("\n_U4");

fstr_out.Write(str);

} catch (IOException exc) {

Console.WriteLine(exc.Message + " Ошибка при работе с файлом.");

return;

} } } while (str != "стоп"); Console.WriteLine("\n\n\n "); fstr_out.Close(); }}

Рис 8 Фрагменты ответов при настройке текста пограммы № 8

№ 8.1

//Открытие файла с использованием класса StreamWriter

// "Клавиатура-диск" с применением класса StreamWriter

using System;

using System.IO;

class Kl_disk{

public static void Main()

{ string str;

StreamWriter fstr_out;

// Открываем файл напрямую, используя класс StreamWriter.

try {

Console.WriteLine("\n_U1");

fstr_out = new StreamWriter("d:/text11.tst");

Console.WriteLine("\n_U2");

} catch (IOException exc) {

Console.WriteLine("\n_U3");

Console.WriteLine(exc.Message + " Не удается открыть файл.");

return;

}

// StreamWriter fstr_out = new StreamWriter(fout);

Console.WriteLine(" Введите текст(`стоп` для завершения).");

do

{ Console.Write(": ");

str = Console.ReadLine();

if (str != "стоп")

{ str = str + "\r\n"; // Добавляем символ новой строки

try {

Console.WriteLine("\n_U4");

fstr_out.Write(str);

}

catch (IOException exc)

{ Console.WriteLine(exc.Message + " Ошибка при работе с файлом.");

return;

}

}

} while (str != "стоп");

Console.WriteLine("\n\n\n ");

fstr_out.Close();

} }

Ввод текста

Введенный Данная программа выполняет наиболее просто ввод

текст в файле с клавиатуры текста прямо в файл d:/text11.txt

d:/text11.txt

Рис 8.1 Ввод с клавиатуры символов в файл используя класс SteamWriter

№ 9 ????

// Открытие файла и вывод его содержания на экран в виде символов с

// помощью класса StreamReader // FileStream

// Вывод с файла на экран символов с помощью класса StreamReader

//

using System;

using System.IO;

class disktoStream {

public static void Main() {

FileStream fin; //StreamReader fin;

string s;

try { Console.WriteLine("\n U1");

fin = new FileStream /*SteamReader*/("d:/text11.tst", FileMode.Open); // ?????

Console.WriteLine("\n U2");

} catch(FileNotFoundException exc) {

Console.WriteLine("\n U3");

Console.WriteLine(exc.Message + "Не удается открыть файл.");

return;

}

StreamReader fstr_in = new StreamReader(fin);

// Считываем файл построчно

while((s = fstr_in.ReadLine()) != null) { // ?????

Console.WriteLine(s);

}

fstr_in.Close();

}

}

Перенаправление стандартных потоков

№ 10

Два способа перенаправления: 1. Оператоы ”< “ и/или “>” Пример:

Using System;

Class Test {

Public static void Main() {

Console.WriteLine(“Это тест.”);

}

}

В командной строке > Test > log // Текст «Этот тест» запишется в файл log

2. способ – переправляет стандартные потоки программно. Используются методы: Setin(), SetOut(), SetError() – члены класса Console:

static void SetIn(TextReader input)

static void SetOut(YextWriter output)

static void SetError(TextWriter output)

// Перенаправление потока Console.Out

using System;

using System.IO;

class Redirect

{

public static void Main()

{

StreamWriter log_out;

try

{

Console.WriteLine("\n U1 ");

log_out = new StreamWriter("logfile.text");

Console.WriteLine("\n U2 ");

}

catch (IOException exc)

{ Console.WriteLine("\n U3 ");

Console.WriteLine(exc.Message + " Не удается открыть файлю");

return;

}

// Направляем стандартный поток в системный журнал

Console.WriteLine("\n U4 ");

// Console.SetOut(log_out);

Console.WriteLine("\n Это начало системного журнала.");

for (int i = 0; i < 10; i++) Console.WriteLine(" " + i);

Console.WriteLine(" Это конец системного журнала.");

// Console.WriteLine("\n\n\n ");

log_out.Close();

Console.WriteLine("\n\n\n U5");

}

}

Рис 10 Результаты перенаправления стандартных потоков

Считывание и запись двоичных данных

Здесь рассматривается считывание и запись двоичных данных различных типов С# (дополнительно к рассмотренным ранее байтовых и символьных данных рассматриваются представление данных типов int, double, short, long). Для этого используются классы BinaryReader и BinaryWriter.

№ 11

// Записьи считывание двоичных данных

using System;

using System.IO;

class ReadWriteData

{

public static void Main() {

BinaryWriter dataOut;

BinaryReader dataIn;

int i = 2147483647; //max = 2147483647

double d = 4.98765432100123456789E-324; // min = 5E-324

bool b = true;

try {

dataOut = new

BinaryWriter (new FileStream("testdata",FileMode.Create));

}

catch(IOException exc) {

Console.WriteLine(exc.Message + "\n Не удается открыть файл.");

return;

}

try

{ Console.WriteLine("\n ");

Console.WriteLine(" Запись" + i);

dataOut.Write(i);

Console.WriteLine(" Запись" + d);

dataOut.Write(d);

Console.WriteLine(" Запись" + b);

dataOut.Write(b);

Console.WriteLine(" Запись" + 12.123456789 * 7.123456789);

dataOut.Write(12.123456789 * 7.123456789);

}

catch(IOException exc) {

Console.WriteLine(" " + exc.Message + "\n Ошибка при записи.");

}

dataOut.Close();

Console.WriteLine();

// Теперь попробуем прочитать эти данные.

try {

dataIn = new BinaryReader(

new FileStream("testdata", FileMode.Open));

}

catch(FileNotFoundException exc) {

Console.WriteLine(" " + exc.Message + "\n Не удается открыть файл.");

return;

}

try {

i = dataIn.ReadInt32();

Console.WriteLine(" Считывание " + i);

d = dataIn.ReadDouble();

Console.WriteLine(" Считывание " + d);

b = dataIn.ReadBoolean();

Console.WriteLine(" Считывание " + b);

d = dataIn.ReadDouble();

Console.WriteLine(" Считывание " + d);

}

catch(IOException exc) {

Console.WriteLine(" " + exc.Message + " Ошибка при считывании.");

}

Console.WriteLine("\n\n\n ");

dataIn.Close();

}

}

Рис 11 Результаты записи в файл двоичных данных разных типов

и дальнейшего считывания их на экран

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

Расматриваются файлы со случайным доступом (до этого рассматривались файлы с последовательным доступом - байт за байтом, символ за символом)ю\. Для этого используется метод Seek() из класса FileStream, со следующим заголовком: Long Seek(long newPos, SeekOrigin origin)

где newPos – позиция, выраженная в байтах;

origin – файловый указатель относительно позиции (SeekOrigin).

Элемент origin принимает одно из значений, определенных перечислением SeekOrigin (см. таблицу).

Значение

Описание

1

SeekOrigin.Begin

Поиск от начала файла

2

SeekOrigin.Current

Поиск от текущей позиции

3

SeelOrigin.End

Поиск от конца файла

После обращения к Seek() следующая операция чтения или записи будет выполняться на новой позиции в файле. Генерируются следующие ИС:

IOExceptionпри возникновении любой ошибки при поиске;

NotSupportedException базовый поток не поддерживает функцию запроса.

№ 12

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

using System;

using System.IO;

Соседние файлы в папке ЛАБ_13_C#