Главная страница
Навигация по странице:

  • Класс FileStream и файловый ввод-вывод на побайтовой основе

  • Как открыть и закрыть файл

  • Значение

  • Использование класса FileStream для копирования файла

  • Использование класса StreamWriter

  • Использование класса StreamReader

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

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

  • Метод

  • Демонстрация использования двоичного ввода-вывода

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

  • Использование класса MemoryStream

  • Использование классов StringReader и StringWriter

  • Преобразование числовых строк во внутреннее представление

  • .NET-имя структуры C-имя

  • Структура

  • Справочник по C# Герберт Шилдт ббк 32. 973. 26018 75 Ш57 удк 681 07 Издательский дом "Вильямс" Зав редакцией


    Скачать 5.05 Mb.
    НазваниеСправочник по C# Герберт Шилдт ббк 32. 973. 26018 75 Ш57 удк 681 07 Издательский дом "Вильямс" Зав редакцией
    АнкорC #.pdf
    Дата08.12.2017
    Размер5.05 Mb.
    Формат файлаpdf
    Имя файлаC #.pdf
    ТипСправочник
    #10795
    страница25 из 52
    1   ...   21   22   23   24   25   26   27   28   ...   52
    383 об ошибках будут появляться на консольном устройстве, и их легко увидеть. Но подробнее о перенаправлении потоков мы поговорим ниже, когда рассмотрим файловый ввод-вывод.
    Класс FileStream и файловый ввод-вывод на
    побайтовой основе
    В C# предусмотрены классы, которые позволяют считывать содержимое файлов и записывать в них информацию. Конечно же, дисковые файлы — самый распространенный тип файлов. На уровне операционной системы все файлы обрабатываются на побайтовой основе. Нетрудно предположить, что в C# определены методы, предназначенные для считывания байтов из файла и записи байтов в файл. Таким образом, файловые операции чтения и записи с использованием байтовых потоков очень востребованы. C# также позволяет поместить файловый поток с ориентацией на побайтовую обработку в символьный объект. Файловые операции, ориентированные на символы, используются в случае текстовых файлов. Символьные потоки рассматриваются ниже в этой главе. А пока изучим ввод-вывод данных на побайтовой основе.
    Чтобы создать байтовый поток с привязкой к файлу, используйте класс
    FileStream
    . Класс
    FileStream
    — производный от
    Stream и потому обладает функциональными возможностями базового класса. Помните, что потоковые классы, включая
    FileStream
    , определены в пространстве имен
    System.IO
    . Следовательно, при их использовании в начало программы вы должны включить следующую инструкцию: using System.IO;
    Как открыть и закрыть файл
    Чтобы создать байтовый поток, связанный с файлом, создайте объект класса
    FileStream
    . В классе
    FileStream определено несколько конструкторов. Чаще всего из них используется следующий:
    FileStream(string
    filename
    , FileMode
    mode
    )
    Здесь элемент
    filename
    означает имя файла, который необходимо открыть, причем оно может включать полный путь к файлу. Элемент
    mode
    означает, как именно должен быть открыт этот файл, или режим открытия. Элемент
    mode
    может принимать одно из значений, определенных перечислением
    FileMode
    (они описаны в табл. 14.4). Этот конструктор открывает файл для доступа с разрешением чтения и записи.
    Таблица 14.4. Значения перечисления FileMode
    Значение
    Описание
    FileMode.Append
    Добавляет выходные данные в конец файла
    FileMode.Create
    Создает новый выходной файл. Существующий файл с таким же именем будет разрушен
    FileMode.CreateNew
    Создает новый выходной файл. Файл с таким же именем не должен существовать
    FileMode.Open
    Открывает существующий файл
    FileMode.OpenOrCreate
    Открывает файл, если он существует, В противном случае создает новый
    FileMode.Truncate
    Открывает существующий файл, но усекает его длину до нуля

    384
    Часть I. Язык C#
    Если попытка открыть файл оказалось неуспешной, генерируется исключение. Если файл невозможно открыть по причине его отсутствия, генерируется исключение типа
    FileNotFoundException
    . Если файл невозможно открыть из-за ошибки ввода-вывода, генерируется исключение типа
    IOException
    . Возможны также исключения следующих типов:
    ArgumentNullException
    (если имя файла представляет собой null
    -значение),
    ArgumentException
    (если некорректен параметр
    mode
    ),
    SecurityException
    (если пользователь не обладает правами доступа) и
    DirectoryNotFoundException
    (если некорректно задан каталог).
    В следующем фрагменте программы показан один из способов открыть файл test.dat для ввода данных.
    FileStream fin; try { fin = new FileStream("test.dat", FileMode.Open);
    } catch(FileNotFoundException exc) {
    Console.WriteLine(exc.Message); return;
    } catch {
    Console.WriteLine("Не удается открыть файл."); return;
    }
    Здесь первая catch
    -инструкция перехватывает ошибку, связанную с отсутствием файла. Вторая, предназначенная для “всеобщего перехвата”, обрабатывает другие ошибки, которые возможны при работе с файлами. Конечно, можно было бы отслеживать возникновение каждой ошибки в отдельности, сообщая о возникшей проблеме. Но ради простоты во всех примерах этой книги организован перехват исключений только типа
    FileNotFoundException или
    IOException
    , но в реальных приложениях (в зависимости от обстоятельств) вам, скорее всего, придется обрабатывать другие возможные исключения.
    Как уже упоминалось, приведенный выше конструктор
    FileStream открывает файл с доступом для чтения и записи. Если необходимо ограничить доступ только чтением или только записью, используйте следующий конструктор:
    FileStream(string
    filename
    , FileMode
    mode
    ,
    FileAccess
    how
    )
    Как и прежде, элемент
    filename
    означает имя открываемого файла, a
    mode

    способ его открытия. Значение, передаваемое с помощью параметра
    how
    , определяет способ доступа к файлу. Этот параметр может принимать одно из значений, определенных перечислением
    FileAccess
    , а именно:
    FileAccess.Read FileAccess.Write FileAccess.ReadWrite
    Например, при выполнении следующей инструкции файл test.dat будет открыт только для чтения:
    FileStream fin = new FileStream("test.dat", FileMode.Open,
    FileAccess.Read);
    По завершении работы с файлом его необходимо закрыть. Для этого достаточно вызвать метод
    Close()
    . Его общая форма вызова имеет такой вид: void Close()
    При закрытии файла освобождаются системные ресурсы, ранее выделенные для этого файла, что дает возможность использовать их для других файлов. Метод
    Close()
    может генерировать исключение типа
    IOException

    Глава 14. Использование средств ввода-вывода
    385
    Считывание байтов из объекта класса FileStream
    В классе
    FileStream определены два метода, которые считывают байты из файла:
    ReadByte()
    и
    Read()
    . Чтобы прочитать из файла один байт, используйте метод
    ReadByte()
    , общая форма вызова которого имеет следующий вид: int ReadByte()
    При каждом вызове этого метода из файла считывается один байт, и метод возвращает его как целочисленное значение. При обнаружении конца файла метод возвращает
    -1
    . Метод может генерировать исключения типов
    NotSupportedException
    (поток не открыт для ввода) и
    ObjectDisposedException
    (поток закрыт).
    Чтобы считать блок байтов, используйте метод
    Read()
    , общая форма вызова которого такова: int Read(byte[]
    buf
    , int
    offset
    , int
    numBytes
    )
    Метод
    Read()
    пытается считать
    numBytes
    байтов в массив
    buf
    , начиная с элемента
    buf[offset]
    . Он возвращает количество успешно считанных байтов. При возникновении ошибки ввода-вывода генерируется исключение типа
    IOException
    Помимо прочих, возможно также генерирование исключения типа
    NotSupportedException
    , если используемый поток не поддерживает операцию считывания данных.
    В следующей программе метод
    ReadByte() используется для ввода содержимого текстового файла и его отображения. Имя файла задается в качестве аргумента командной строки. Обратите внимание на try/catch
    -блоки, которые обрабатывают две ошибки, возможные при первоначальном выполнении этой программы: “указанный файл не найден” или “пользователь забыл указать имя файла”. Такой подход обычно полезен при использовании аргументов командной строки.
    /* Отображение содержимого текстового файла.
    Чтобы использовать эту программу, укажите имя файла, содержимое которого вы хотите увидеть.
    Например, чтобы увидеть содержимое файла TEST.CS, используйте следующую командную строку:
    ShowFile TEST.CS */ using System; using System.IO; class ShowFile { public static void Main(string[] args) { int i;
    FileStream fin; try
    { fin = new FileStream(args[0], FileMode.Open);
    } catch(FileNotFoundException exc) {
    Console.WriteLine(exc.Message); return;
    } catch(IndexOutOfRangeException exc) {
    Console.WriteLine(exc.Message
    +
    "\nПрименение: ShowFile Файл"); return;
    }

    386
    Часть I. Язык C#
    // Считываем байты до тех пор, пока не встретится EOF. do { try
    { i
    = fin.ReadByte();
    } catch(Exception exc)
    {
    Console.WriteLine(exc.Message); return;
    } if(i != -1) Console.Write((char) i);
    } while(i != -1); fin.Close();
    }
    }
    Запись данных в файл
    Чтобы записать байт в файл, используйте метод
    WriteByte()
    . Простейшая его форма имеет следующий вид: void WriteByte(byte
    val
    )
    Этот метод записывает в файл байт, заданный параметром
    val
    . При возникновении во время записи ошибки генерируется исключение типа
    IOException
    . Если соответствующий поток не открыт для вывода данных, генерируется исключение типа
    NotSupportedException
    С помощью метода
    Write()
    можно записать в файл массив байтов. Это делается следующим образом: void Write(byte[]
    buf
    , int
    offset
    , int
    numBytes
    )
    Метод
    Write()
    записывает в файл
    numBytes
    байтов из массива
    buf
    , начиная с элемента
    buf[offset]
    .При возникновении во время записи ошибки генерируется исключение типа
    IOException
    . Если соответствующий поток не открыт для вывода данных, генерируется исключение типа
    NotSupportedException
    . Возможны и другие исключения.
    Вероятно, вы уже знаете, что при выполнении операции вывода в файл выводимые данные зачастую не записываются немедленно на реальное физическое устройство, а буферизируются операционной системой до тех пор, пока не накопится порция данных достаточного размера, чтобы ее можно было всю сразу переписать на диск. Такой способ выполнения записи данных на диск повышает эффективность системы. Например, дисковые файлы организованы по секторам, которые могут иметь размер от 128 байт.
    Данные, предназначенные для вывода, обычно буферизируются до тех пор, пока не накопится такой их объем, который позволяет заполнить сразу весь сектор. Но если вы хотите записать данные на физическое устройство вне зависимости от того, полон буфер или нет, вызовите следующий метод
    Flush()
    : void Flush()
    В случае неудачного исхода операции записи генерируется исключение типа
    IOException
    Завершив работу с выходным файлом, вы должны его закрыть с помощью метода
    Close()
    . Это гарантирует, что любые данные, оставшиеся в дисковом буфере, будут переписаны на диск. Поэтому перед закрытием файла нет необходимости специально вызывать метод
    Flush()
    Рассмотрим простой пример записи данных в файл.

    Глава 14. Использование средств ввода-вывода
    387
    // Запись данных в файл. using System; using System.IO; class WriteToFile { public static void Main(string[] args) {
    FileStream fout;
    //
    Открываем выходной файл. try
    { fout = new FileStream("test.txt", FileMode.Create);
    } catch(IOException exc) {
    Console.WriteLine( exc.Message
    +
    "\nОшибка при открытии выходного файла."); return;
    }
    //
    Записываем в файл алфавит. try
    { for(char c = 'A'; c <= 'Z'; c++) fout.WriteByte((byte) c);
    } catch(IOException exc) {
    Console.WriteLine(exc.Message
    +
    "Ошибка при записи в файл. ");
    } fout.Close();
    }
    }
    Эта программа сначала открывает для вывода файл с именем test.txt
    . Затем в этот файл записывается алфавит английского языка, после чего файл закрывается. Обратите внимание на то, как обрабатываются возможные ошибки с помощью блоков try/catch
    После выполнения этой программы файл test.txt будет иметь такое содержимое:
    ABCDEFGHIJKLMNOPQRSTUVWXYZ
    Использование класса FileStream для копирования файла
    Одно из достоинств байтового ввода-вывода с использованием класса
    FileStream заключается в том, что этот класс можно использовать для всех типов файлов, а не только текстовых. Например, следующая программа копирует файл любого типа, включая выполняемые файлы. Имена исходного и приемного файлов указываются в командной строке.
    /* Копирование файла.
    Для использования этой программы укажите имя исходного и приемного файлов.
    Например, чтобы скопировать файл FIRST.DAT в файл SECOND.DAT, используйте следующую командную строку:
    CopyFile FIRST.DAT SECOND.DAT */

    388
    Часть I. Язык C# using System; using System.IO; class CopyFile { public static void Main(string[] args) { int i;
    FileStream fin;
    FileStream fout; try
    {
    //
    Открываем входной файл. try
    { fin = new FileStream(args[0], FileMode.Open);
    } catch(FileNotFoundException exc) {
    Console.WriteLine(exc.Message
    +
    "\nВходной файл не найден."); return;
    }
    //
    Открываем выходной файл. try
    { fout = new FileStream(args[1], FileMode.Create);
    } catch(IOException exc) {
    Console.WriteLine( exc.Message
    +
    "\nОшибка при открытии выходного файла."); return;
    }
    } catch(IndexOutOfRangeException exc) {
    Console.WriteLine(exc.Message
    +
    "\nПрименение: CopyFile ИЗ КУДА"); return;
    }
    //
    Копируем файл. try { do
    { i
    = fin.ReadByte(); if(i != -1) fout.WriteByte((byte)i);
    } while(i != -1);
    } catch(IOException exc) {
    Console.WriteLine(exc.Message
    +
    "Ошибка при чтении файла. ");
    } fin.Close(); fout.Close();
    }
    }

    Глава 14. Использование средств ввода-вывода
    389
    Файловый ввод-вывод с ориентацией на
    символы
    Несмотря на то что байтовая обработка файлов получила широкое распространение,
    C# также поддерживает символьные потоки. Символьные потоки работают непосредственно с Unicode-символами (это их достоинство). Поэтому, если вы хотите сохранить Unicode-текст, лучше всего выбрать именно символьные потоки. В общем случае, чтобы выполнять файловые операции на символьной основе, поместите объект класса
    FileStream внутрь объекта класса
    StreamReader или класса
    StreamWriter
    Эти классы автоматически преобразуют байтовый поток в символьный и наоборот.
    Помните, что на уровне операционной системы файл представляет собой набор байтов. Использование классов
    StreamReader или
    StreamWriter не влияет на этот факт.
    Класс
    StreamWriter
    — производный от класса
    TextWriter
    , a
    StreamReader
    — производный от
    TextReader
    . Следовательно, классы
    StreamWriter и
    StreamReader имеют доступ к методам и свойствам, определенным их базовыми классами.
    Использование класса StreamWriter
    Чтобы создать выходной поток для работы с символами, поместите объект класса
    Stream (например,
    FileStream
    ) в объект класса
    StreamWriter
    . В классе
    StreamWriter определено несколько конструкторов. Самый популярный из них выглядит следующим образом:
    StreamWriter(Stream
    stream
    )
    Здесь элемент
    stream
    означает имя открытого потока. Этот конструктор генерирует исключение типа
    ArgumentException
    , если поток
    stream
    не открыт для вывода, и исключение типа
    ArgumentNullException
    , если он (поток) имеет null
    -значение.
    Созданный объект класса
    StreamWriter автоматически выполняет преобразование символов в байты.
    Рассмотрим простую утилиту “клавиатура-диск”, которая считывает строки текста, вводимые с клавиатуры, и записывает их в файл test.txt
    . Текст считывается до тех пор, пока пользователь не введет слово “стоп”. Здесь используется объект класса
    FileStream
    , помещенный в оболочку класса
    StreamWriter для вывода данных в файл.
    /* Простая утилита "клавиатура-диск", которая демонстрирует использование класса StreamWriter. */ using System; using System.IO; class KtoD { public static void Main() { string str;
    FileStream fout; try
    { fout = new FileStream("test.txt", FileMode.Create);
    } catch(IOException exc) {

    390
    Часть I. Язык C#
    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
    { fstr_out.Write(str);
    } catch(IOException exc)
    {
    Console.WriteLine(exc.Message
    +
    "Ошибка при работе с файлом."); return;
    }
    }
    } while(str != "стоп"); fstr_out.Close();
    }
    }
    Иногда удобнее открывать файл с помощью класса
    StreamWriter
    . Для этого используйте один из следующих конструкторов:
    StreamWriter(string
    filename
    )
    StreamWriter(string
    filename
    , bool
    appendFlag
    )
    Здесь элемент
    filename
    означает имя открываемого файла, причем имя может включать полный путь к файлу. Во второй форме используется параметр
    appendFlag
    типа bool
    : если
    appendFlag
    равен значению true
    , выводимые данные добавляются в конец существующего файла. В противном случае заданный файл перезаписывается. В обоих случаях, если файл не существует, он создается, а при возникновении ошибки ввода- вывода генерируется исключение типа
    IOException
    (также возможны и другие исключения).
    Перед вами новая версия предыдущей утилиты “клавиатура-диск”, в которой для открытия выходного файла используется класс
    StreamWriter
    // Открытие файла с использованием класса StreamWriter. using System; using System.IO; class KtoD { public static void Main() { string str;
    StreamWriter fstr_out;
    //
    Открываем файл напрямую, используя
    // класс StreamWriter. try
    { fstr_out = new StreamWriter("test.txt");

    Глава 14. Использование средств ввода-вывода
    391
    } catch(IOException exc) {
    Console.WriteLine(exc.Message
    +
    "Не удается открыть файл."); return;
    }
    Console.WriteLine(
    "Введите текст ('стоп' для завершения)."); do
    {
    Console.Write(":
    "); str
    =
    Console.ReadLine(); if(str
    !=
    "стоп") { str = str + "\r\n"; // Добавляем символ
    // новой строки. try
    { fstr_out.Write(str);
    } catch(IOException exc)
    {
    Console.WriteLine(exc.Message
    +
    "Ошибка при работе с файлом. "); return;
    }
    }
    } while(str != "стоп"); fstr_out.Close();
    }
    }
    Использование класса StreamReader
    Чтобы создать входной поток с ориентацией на обработку символов, поместите байтовый поток в класс-оболочку
    StreamReader
    . В классе
    StreamReader определено несколько конструкторов. Чаще всего используется следующий конструктор:
    StreamReader(Stream
    stream
    )
    Здесь элемент
    stream
    означает имя открытого потока. Этот конструктор генерирует исключение типа
    ArgumentNullException
    , если поток
    stream
    имеет null
    -значение, и исключение типа
    ArgumentException
    , если поток
    stream
    не открыт для ввода. После создания объект класса
    StreamReader автоматически преобразует байты в символы.
    Следующая программа создает простую утилиту “клавиатура-диск”, которая считывает текстовый файл test.txt и отображает его содержимое на экране. Таким образом, эта программа представляет собой дополнение к утилите, представленной в предыдущем разделе.
    /* Простая утилита "клавиатура-диск", которая демонстрирует использование класса FileReader. */ using System; using System.IO; class DtoS { public static void Main() {
    FileStream fin;

    392
    Часть I. Язык C# string s; try
    { fin = new FileStream("test.txt", FileMode.Open);
    } catch(FileNotFoundException exc) {
    Console.WriteLine(exc.Message
    +
    "Не удается открыть файл."); return;
    }
    StreamReader fstr_in = new StreamReader(fin);
    //
    Считываем файл построчно. while((s = fstr_in.ReadLine()) != null) {
    Console.WriteLine(s);
    } fstr_in.Close();
    }
    }
    Обратите внимание на то, как определяется конец файла. Если ссылка, возвращаемая методом
    ReadLine()
    , равна значению null
    , значит, конец файла достигнут.
    Как и в случае класса
    StreamWriter
    , иногда проще открыть файл, напрямую используя класс
    StreamReader
    . Для этого обратитесь к этому конструктору:
    StreamReader(string
    filename
    )
    Здесь элемент
    filename
    означает имя открываемого файла, которое может включать полный путь к файлу. Указанный файл должен существовать. В противном случае генерируется исключение типа
    FileNotFoundException
    . Если параметр
    filename
    равен значению null
    , генерируется исключение типа
    ArgumentNullException
    , а если он представляет собой пустую строку, — исключение типа
    ArgumentException
    Перенаправление стандартных потоков
    Как упоминалось выше, такие стандартные потоки, как
    Console.In
    , можно перенаправлять. Безусловно, чаще всего они перенаправляются в какой-нибудь файл. При перенаправлении стандартного потока входные и/или выходные данные автоматически направляются в новый поток. При этом устройства, действующие по умолчанию, игнорируются. Благодаря перенаправлению стандартных потоков программа может считывать команды из дискового файла, создавать системные журналы или даже считывать входные данные с сетевых устройств.
    Перенаправить стандартный поток можно двумя способами. Во-первых, при выполнении программы из командной строки можно использовать операторы “
    <
    ” и “
    >
    ”, чтобы перенаправить потоки
    Console.In и/или
    Console.Out
    , соответственно.
    Рассмотрим, например, следующую программу: using System; class Test { public static void Main() {
    Console.WriteLine("Это тест.");
    }
    }

    Глава 14. Использование средств ввода-вывода
    393
    При выполнении ее с помощью командной строки
    Test > log текстовая строка “Это тест.” будет записана в файл log
    . Входной поток можно перенаправить аналогичным способом. При перенаправлении входного потока важно позаботиться о том, чтобы задаваемый источник входных данных содержал информацию, удовлетворяющую требованиям программы. В противном случае программа зависнет.
    Операторы перенаправления “
    <
    ” и “
    >
    ” являются частью не языка C#, а операционной системы. Таким образом, если среда поддерживает функцию перенаправления потоков ввода-вывода (как это реализовано в Windows), вы сможете перенаправить стандартные входные и выходные потоки, не внося изменений в программы. Однако существует и второй способ, который позволяет перенаправлять стандартные потоки именно программно. Для этого понадобятся следующие методы
    SetIn()
    ,
    SetOut()
    и
    SetError()
    , которые являются членами класса
    Console
    : static void SetIn(TextReader
    input
    ) static void SetOut(TextWriter
    output
    ) static void SetError(TextWriter
    output
    )
    Таким образом, чтобы перенаправить входной поток, вызовите метод
    SetIn()
    , указав в качестве параметра желаемый поток. Вы можете использовать любой входной поток, если он является производным от класса
    TextReader
    . Чтобы перенаправить выходной поток в файл, задайте
    FileStream
    -объект, помещенный в оболочку
    StreamWriter
    -объекта. Пример перенаправления потоков проиллюстрирован следующей программой:
    // Перенаправление потока Console.Out. using System; using System.IO; class Redirect { public static void Main() {
    StreamWriter log_out; try
    { log_out = new StreamWriter("logfile.txt");
    } catch(IOException exc) {
    Console.WriteLine(exc.Message
    +
    "Не удается открыть файл."); return;
    }
    //
    Направляем стандартный выходной поток в
    // системный журнал.
    Console.SetOut(log_out);
    Console.WriteLine("Это начало системного журнала."); for(int i=0; i<10; i++)
    Console.WriteLine(i);
    Console.WriteLine("Это конец системного журнала."); log_out.Close();
    }
    }

    394
    Часть I. Язык C#
    При выполнении этой программы на экране не появится ни одного символа, но файл logfile.txt будет иметь такое содержимое:
    Это начало системного журнала.
    0 1
    2 3
    4 5
    6 7
    8 9
    Это конец системного журнала.
    При желании вы можете поэкспериментировать, перенаправляя другие встроенные потоки ввода-вывода.
    Считывание и запись двоичных данных
    До сих пор мы считывали и записывали байты или символы, но эти операции ввода- вывода можно выполнять и с другими типами данных. Например, вы могли бы создать файл, содержащий int
    -, double
    - или short
    -значения. Для считывания и записи двоичных значений встроенных C#-типов используйте классы
    BinaryReader и
    BinaryWriter
    . Важно понимать, что эти данные считываются и записываются с использованием внутреннего двоичного формата, а не в текстовой форме, понятной человеку.
    Класс BinaryWriter
    Класс
    BinaryWriter представляет собой оболочку для байтового потока, которая управляет записью двоичных данных. Его наиболее употребительный конструктор имеет следующий вид:
    BinaryWriter(Stream
    outputStream
    )
    Здесь элемент
    outputStream
    означает поток, в который будут записываться данные. Чтобы записать выходные данные в файл, можно использовать для этого параметра объект, созданный классом
    FileStream
    . Если поток
    outputStream
    имеет null
    - значение, генерируется исключение типа
    ArgumentNullException
    , а если поток
    outputStream
    не открыт для записи, — исключение типа
    ArgumentException
    В классе
    BinaryWriter определены методы, способные записывать значения всех встроенных C#-типов (некоторые из них перечислены в табл. 14.5). Обратите внимание: значение типа string записывается с использованием внутреннего формата, который включает спецификатор длины. В классе
    BinaryWriter также определены стандартные методы
    Close()
    и
    Flush()
    , работа которых описана выше.
    Таблица 14.5. Методы вывода информации, определенные в классе BinaryWriter
    Метод
    Описание
    void Write(sbyte
    val
    )
    Записывает byte
    -значение (со знаком) void Write(byte
    val
    )
    Записывает byte
    -значение (без знака)

    Глава 14. Использование средств ввода-вывода
    395
    Окончание табл. 14.5
    Метод
    Описание
    void Write(byte[]
    buf
    )
    Записывает массив byte
    -значений void Write(short
    val
    )
    Записывает целочисленное значение типа short
    (короткое целое) void Write(ushort
    val
    )
    Записывает целочисленное ushort
    -значение (короткое целое без знака) void Write(int
    val
    )
    Записывает целочисленное значение типа int void Write(uint
    val
    )
    Записывает целочисленное uint
    -значение (целое без знака) void Write(long
    val
    )
    Записывает целочисленное значение типа long
    (длинное целое) void Write(ulong
    val
    )
    Записывает целочисленное ulong
    -значение (длинное целое без знака) void Write(float
    val
    )
    Записывает float
    -значение void Write(double
    val
    )
    Записывает double
    -значение void Write(char
    val
    )
    Записывает символ void Write(char[]
    buf
    )
    Записывает массив символов void Write(string
    val
    )
    Записывает string
    -значение с использованием его внутреннего представления, которое включает спецификатор длины
    Класс BinaryReader
    Класс
    BinaryReader представляет собой оболочку для байтового потока, которая управляет чтением двоичных данных. Его наиболее употребительный конструктор имеет такой вид:
    BinaryReader(Stream,
    inputStream
    )
    Здесь элемент
    inputStream
    означает поток, из которого считываются данные.
    Чтобы выполнить чтение из файла, можно использовать для этого параметра объект, созданный классом
    FileStream
    , Если поток
    inputStream
    имеет null
    -значение, генерируется исключение типа
    ArgumentNullException
    , а если поток
    inputStream
    не открыт для чтения,— исключение типа
    ArgumentException
    В классе
    BinaryReader предусмотрены методы для считывания всех простых C#- типов. Наиболее употребимые из них показаны в табл. 14.6. Обратите внимание на то, что метод
    ReadString()
    считывает строку, которая хранится с использованием внутреннего формата, включающего спецификатор длины. При обнаружении конца потока все эти методы генерируют исключение типа
    EndOfStreamException
    , а при возникновении ошибки — исключение типа
    IOException
    . В классе
    BinaryReader также определены следующие версии метода
    Read()
    :
    Метод
    Описание
    int Read()
    Возвращает целочисленное представление следующего доступного символа из вызывающего входного потока. При обнаружении конца файла возвращает значение -1 int Read( byte[]
    buf
    , int
    offset
    , int
    num
    )
    Делает попытку прочитать
    num
    байтов в массив
    buf
    , начиная с элемента
    buf[offset]
    , и возвращает количество успешно считанных байтов int Read( char[]
    buf
    , int
    offset
    , int
    num
    )
    Делает попытку прочитать
    num
    символов в массив
    buf
    ,
    начиная с элемента
    buf[offset]
    , и возвращает количество успешно считанных символов
    В случае неудачного исхода операции чтения эти методы генерируют исключение типа
    IOException

    396
    Часть I. Язык C#
    В классе
    BinaryReader также определен стандартный метод
    Close()
    Таблица 14.6. Методы ввода данных, определенные в классе BinaryReader
    Метод
    Описание
    bool ReadBoolean()
    Считывает bool
    -значение byte ReadByte()
    Считывает byte
    -значение sbyte ReadSByte()
    Считывает sbyte
    -значение byte[] ReadBytes( int
    num
    )
    Считывает
    num
    байтов и возвращает их в виде массива char ReadChar()
    Считывает char
    -значение char[] ReadChars( int
    num
    )
    Считывает
    num
    символов и возвращает их в виде массива double ReadDouble()
    Считывает double
    -значение float ReadSingle()
    Считывает float
    -значение short ReadInt16()
    Считывает short
    -значение int ReadInt32()
    Считывает int
    -значение long ReadInt64()
    Считывает long
    -значение ushort ReadUInt16()
    Считывает ushort
    -значение uint ReadUInt32()
    Считывает uint
    -значение ulong ReadUInt64()
    Считывает ulong
    -значение string ReadString()
    Считывает 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
    = new
    BinaryWriter(new
    FileStream("testdata",
    FileMode.Create));
    } catch(IOException exc) {
    Console.WriteLine(exc.Message
    +
    "\nНе удается открыть файл.");

    Глава 14. Использование средств ввода-вывода
    397 return;
    } try
    {
    Console.WriteLine("Запись " + i); dataOut.Write(i);
    Console.WriteLine("Запись " + d); dataOut.Write(d);
    Console.WriteLine("Запись " + b); dataOut.Write(b);
    Console.WriteLine("Запись " + 12.2 * 7.4); dataOut.Write(12.2
    *
    7.4);
    } 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
    +
    "Ошибка при считывании.");
    } dataIn.Close();
    }
    }

    398
    Часть I. Язык C#
    При выполнении этой программы были получены следующие результаты:
    Запись 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
    = new
    BinaryWriter(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);

    Глава 14. Использование средств ввода-вывода
    399 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
    = new
    BinaryReader(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("Элемент не найден.");

    400
    Часть I. Язык C#
    } 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.Begin
    Поиск от начала файла
    SeekOrigin.Current
    Поиск от текущей позиции
    SeekOrigin.End
    Поиск от конца файла
    После обращению к методу
    Seek()
    следующая операция чтения или записи данных будет выполняться на новой позиции в файле. Если при выполнении поиска возникнет какая-либо ошибка, генерируется исключение типа
    IOException
    . Если базовый поток не поддерживает функцию запроса нужной позиции, генерируется исключение типа
    NotSupportedException

    Глава 14. Использование средств ввода-вывода
    401
    Рассмотрим пример, который демонстрирует выполнение операций ввода-вывода с произвольным доступом. Следующая программа записывает в файл алфавит прописными буквами, а затем беспорядочно считывает его.
    // Демонстрация произвольного доступа к файлу. using System; using System.IO; class RandomAccessDemo { public static void Main() {
    FileStream f; char ch; try
    { f = new FileStream("random.dat", FileMode.Create);
    } catch(IOException exc) {
    Console.WriteLine(exc.Message); return;
    }
    //
    Записываем в файл алфавит. for(int i=0; i < 26; i++) { try
    { f.WriteByte( (byte) ('A'+i) );
    } catch(IOException exc)
    {
    Console.WriteLine(exc.Message); return;
    }
    } try
    {
    //
    Теперь считываем отдельные значения. f.Seek(0,
    SeekOrigin.Begin);
    //
    Поиск первого байта. ch = (char) f.ReadByte();
    Console.WriteLine("Первое значение равно " + ch); f.Seek(1,
    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 + " ");
    }
    }

    402
    Часть I. Язык C# catch(IOException exc) {
    Console.WriteLine(exc.Message);
    }
    Console.WriteLine(); f.Close();
    }
    }
    При выполнении этой программы получены такие результаты:
    Первое значение равно А
    Второе значение равно В
    Пятое значение равно Е
    Выборка значений через одно:
    A C E G I K M O Q S U W Y
    Использование класса MemoryStream
    Не всегда удобно выполнять операции ввода-вывода непосредственно с помощью физического устройства. Иногда полезно считывать входные данные из массива или записывать их в массив. В этом случае стоит воспользоваться классом
    MemoryStream
    Класс
    MemoryStream
    — это реализация класса
    Stream
    , в которой для операций ввода- вывода используются массивы байтов. Вот как выглядит конструктор этого класса:
    MemoryStream(byte[]
    buf
    )
    Здесь элемент
    buf
    — это массив байтов, который предполагается использовать в операциях ввода-вывода в качестве источника и/или приемника информации. В поток, создаваемый этим конструктором, можно записывать данные или считывать их в него. Этот поток поддерживает метод
    Seek()
    . Перед использованием этого конструктора необходимо позаботиться о достаточном размере массива
    buf
    , чтобы он позволил сохранить все направляемые в него данные.
    Вот пример программы, которая демонстрирует использование класса
    MemoryStream
    :
    // Демонстрация использования класса MemoryStream. using System; using System.IO; class MemStrDemo { public static void Main() { byte[] storage = new byte[255];
    //
    Создаем поток с ориентацией на память.
    MemoryStream memstrm = new MemoryStream(storage);
    //
    Помещаем объект memstrm в оболочки StreamWriter
    //и StreamReader.
    StreamWriter memwtr = new StreamWriter(memstrm);
    StreamReader memrdr = new StreamReader(memstrm);
    //
    Записываем данные в память с помощью
    // объекта memwtr. for(int i=0; i < 10; i++)

    Глава 14. Использование средств ввода-вывода
    403 memwtr.WriteLine("'byte[" + i + "]: " + i);
    //
    Ставим в конце точку. memwtr.Write('.'); memwtr.Flush();
    Console.WriteLine(
    "Считываем данные прямо из массива 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.CompareTo(".") == 0) break;
    Console.WriteLine(str);
    }
    }
    }
    Вот как выглядят результаты выполнения этой программы
    Считываем данные прямо из массива storage: byte[0]: 0 byte[1]: 1 byte[2]: 2 byte[3]: 3 byte[4]: 4 byte[5]: 5 byte[6]: 6 byte[7]: 7 byte[8]: 8 byte[9]: 9
    Считываем данные посредством объекта memrdr: byte[1]: 1 byte[2]: 2 byte[3]: 3 byte[4]: 4 byte[5]: 5 byte[6]: 6 byte[7]: 7 byte[8]: 8 byte[9]: 9

    404
    Часть I. Язык C#
    В этой программе создается байтовый массив storage
    . Этот массив затем используется в качестве базовой области памяти для объекта memstrm класса
    MemoryStream
    . На основе объекта memstrm создаются объект класса
    StreamReader с именем memrdr и объект класса
    StreamWriter с именем memwtr
    . Через объект memwtr данные записываются в поток, ориентированный на конкретную область памяти. Обратите внимание на то, что после записи выходных данных для объекта memwtr вызывается метод flush()
    . Тем самым гарантируется, что содержимое буфера, связанного с потоком memwtr
    , реально перепишется в базовый массив. Затем содержимое этого байтового массива отображается “вручную”, т.е. с помощью цикла foreach
    . После этого посредством метода
    Seek()
    указатель позиции устанавливается в начало потока, и его содержимое считывается с использованием объекта memrdr
    Потоки, ориентированные на память, весьма полезны в программировании.
    Например, можно заблаговременно составить выходные данные и хранить их в массиве до тех пор, пока в них не отпадет необходимость. Такой подход особенно полезен в программировании для такой GUI-среды, как Windows. Можно также перенаправить стандартный поток для считывания данных из массива. Это полезно, например, при вводе тестовой информации в программу.
    Использование классов StringReader и
    StringWriter
    В некоторых приложениях при выполнении операций ввода-вывода, ориентированных на использование памяти в качестве базовой области хранения данных, проще работать не с байтовыми (
    byte
    -) массивами, а со строковыми (
    string
    -). В этом случае используйте классы
    StringReader и
    StringWriter
    . Класс
    StringReader наследует класс
    TextReader
    , а класс
    StringWriter
    — класс
    TextWriter
    Следовательно, эти потоки имеют доступ к методам, определенным в этих классах.
    Например, вы можете вызывать метод
    ReadLine()
    для объекта класса
    StringReader и метод
    WriteLine()
    для объекта класса
    StringWriter
    Конструктор класса
    StringReader имеет следующий вид:
    StringReader(string
    str
    )
    Здесь параметр
    str
    представляет собой строку, из которой должны считываться данные.
    В классе
    StringWriter определено несколько конструкторов. Мы будем использовать такой:
    StringWriter()
    Этот конструктор создает “записывающий” механизм, который помещает выходные данные в строку. Эта строка автоматически создается объектом класса
    StringWriter
    Содержимое строки можно получить, вызвав метод
    ToString()
    Рассмотрим пример использования классов
    StringReader и
    StringWriter
    // Демонстрация использования классов StringReader
    // и StringWriter. using System; using System.IO; class StrRdrDemo { public static void Main() {
    //
    Создаем объект класса StringWriter.

    Глава 14. Использование средств ввода-вывода
    405
    StringWriter strwtr = new StringWriter();
    //
    Записываем данные в StringWriter-объект. for(int i=0; i < 10; i++) strwtr.WriteLine("Значение i равно: " + i);
    //
    Создаем объект класса StringReader.
    StringReader strrdr = new StringReader( strwtr.ToString()
    );
    //
    Теперь считываем данные из StringReader-объекта. string str = strrdr.ReadLine(); while(str != null) { str
    = strrdr.ReadLine();
    Console.WriteLine(str);
    }
    }
    }
    Результаты выполнения этой программы имеют такой вид:
    Значение i равно: 1
    Значение i равно: 2
    Значение i равно: 3
    Значение i равно: 4
    Значение i равно: 5
    Значение i равно: 6
    Значение i равно: 7
    Значение i равно: 8
    Значение i равно: 9
    Эта программа сначала создает объект класса
    StringWriter с именем strwtr и записывает в него данные с помощью метода
    WriteLine()
    . Затем создается объект класса
    StringReader с использованием строки, содержащейся в объекте strwtr
    , и метода
    ToString()
    . Наконец, содержимое строки считывается с помощью метода
    ReadLine()
    Преобразование числовых строк во внутреннее
    представление
    Прежде чем завершить тему ввода-вывода, рассмотрим метод, который будет весьма полезен программистам при считывании числовых строк. Как вы знаете, C#-метод
    WriteLine()
    предоставляет удобный способ вывода данных различных типов (включая числовые значения таких встроенных типов, как int и double
    ) на консольное устройство.
    Следовательно, метод
    WriteLine()
    автоматически преобразует числовые значения в удобную для восприятия человеком форму. Однако C# не обеспечивает обратную функцию, т.е. метод ввода, который бы считывал и преобразовывал строковые представления числовых значений во внутренний двоичный формат. Например, не существует метода ввода данных, который бы считывал такую строку, как “100”, и автоматически преобразовывал ее в соответствующее двоичное значение, которое можно было бы хранить в int
    -переменной. Для решения этой задачи понадобится метод, определенный для всех встроенных числовых типов, —
    Parse()

    406
    Часть I. Язык C#
    Приступая к решению этой задачи, необходимо отметить такой важный факт. Все встроенные C#-типы (например, int и double
    ) в действительности являются лишь псевдонимами (т.е. другими именами) для структур, определенных в среде .NET Framework.
    Компания Microsoft заявляет, что понятия C#-типа и .NET-типа структуры неразличимы.
    Первое — просто еще одно имя для другого. Поскольку C#-типы значений поддерживаются структурами, они имеют члены, определенные для этих структур.
    Ниже представлены .NET-имена структур и их C#-эквиваленты (в виде ключевых слов) для числовых типов.
    .NET-имя структуры C#-имя
    Decimal decimal
    Double double
    Single float
    Int16 short
    Int32 int
    Int64 long
    UInt16 ushort
    UInt32 uint
    UInt64 ulong
    Byte byte
    Sbyte sbyte
    Эти структуры определены в пространстве имен
    System
    . Таким образом, составное имя для структуры
    Int32
    “звучит” как
    System.Int32
    . Для этих структур определен широкий диапазон методов, которые способствуют полной интеграции типов значений в
    C#-иерархию объектов. В качестве дополнительного “вознаграждения” эти числовые структуры также определяют статические методы, которые преобразуют числовую строку в соответствующий двоичный эквивалент. Эти методы преобразования представлены в следующей таблице. Каждый метод возвращает двоичное значение, которое соответствует строке.
    Структура
    Метод преобразования
    Decimal static decimal Parse(string
    str
    )
    Double static double Parse(string
    str
    )
    Single static float Parse(string
    str
    )
    Int64 static long Parse(string
    str
    )
    Int32 static int Parse(string
    str
    )
    Int16 static short Parse(string
    str
    )
    UInt64 static ulong Parse(string
    str
    )
    UInt32 static uint Parse(string
    str
    )
    UInt16 static ushort Parse(string
    str
    )
    Byte static byte Parse(string
    str
    )
    SByte static sbyte Parse(string
    str
    )
    Методы
    Parse()
    генерируют исключение типа
    FormatException
    , если параметр str не содержит числа, допустимого для типа вызывающего объекта. Если параметр str имеет null
    -значение, генерируется исключение типа
    ArgumentNullException
    , a

    Глава 14. Использование средств ввода-вывода
    407 если значение параметра str превышает диапазон, допустимый для типа вызывающего объекта, — исключение типа
    OverflowException
    Методы синтаксического анализа позволяют легко преобразовать числовое значение, прочитанное в виде строки с клавиатуры или текстового файла, в соответствующий внутренний формат. Например, следующая программа вычисляет среднее арифметическое от чисел, введенных пользователем в виде списка. Сначала пользователю предлагается ввести количество усредняемых чисел, а затем программа считывает эти числа с помощью метода
    ReadLine()
    и с помощью метода
    Int32.Parse()
    преобразует строки в целочисленное значение. Затем она вводит значения, используя метод
    Double. Parse()
    для преобразования строк в их double
    -эквиваленты.
    // Эта программа усредняет список чисел,
    // введенных пользователем. using System; using System.IO; class AvgNums { public static void Main() { string str; int n; double sum =0.0; double avg, t;
    Console.Write("Сколько чисел вы собираетесь ввести: "); str = Console.ReadLine(); try
    { n
    =
    Int32.Parse(str);
    } catch(FormatException exc) {
    Console.WriteLine(exc.Message); n = 0;
    } catch(OverflowException exc) {
    Console.WriteLine(exc.Message); n = 0;
    }
    Console.WriteLine("Введите " + n + " чисел."); for(int i=0; i < n; i++) {
    Console.Write(":
    "); str = Console.ReadLine(); try
    { t
    =
    Double.Parse(str);
    } catch(FormatException exc)
    {
    Console.WriteLine(exc.Message); t
    =
    0.0;
    } catch(OverflowException exc)
    {
    Console.WriteLine(exc.Message); t
    =
    0;
    } sum
    += t;
    } avg = sum / n;
    Console.WriteLine("Среднее равно " + avg);
    }
    }

    408
    Часть I. Язык C#
    Вот как могут выглядеть результаты выполнения этой программы
    Сколько чисел вы собираетесь ввести: 5
    Введите 5 чисел.
    : 1.1
    : 2.2
    : 3.3
    : 4.4
    : 5.5
    Среднее равно 3.3
    И еще. Вы должны использовать надлежащий метод анализа для типа значения, которое вы пытаетесь преобразовать. Например, попытка использовать метод
    Int32.Parse()
    для строки, содержащей значение с плавающей точкой, желаемого результата не даст.

    Полный справочник по
    1   ...   21   22   23   24   25   26   27   28   ...   52


    написать администратору сайта