Файлы данных (Пространство имен System.IO). Файлы и потоки
Файл данных — это совокупность (последовательность) компонент, имеющая имя, расположенная на внешнем носителе. Файлы могут быть объединены в каталоги (директории, папки), также имеющие имя. Использование файлов данных позволяет хранить данные на внешнем носителе, обрабатывая при необходимости порциями (например, при больших объемах данных), позволяет многократно использовать один и тот же набор данных (например, при отладке), позволяет использовать результаты выполнения одной программы (формируя из них файл) как входные данные при выполнении другой программы и т.п. Для существующего файла данных, который храниться на внешнем носителе и имеет имя, при обращении к файлу создается поток с целью сохранения данных в резервном хранилище. Резервное хранилище — это устройство хранения информации, например, диск или память. Поток — это абстракция последовательности байтов, например файл или другое устройство, предоставляющее данные. Класс Stream (поток) и его производные классы предоставляют универсальное представление различных типов ввода и вывода, избавляя программиста от необходимости знания отдельных сведений операционной системы и базовых устройств. Потоки включают три основные операции: 1. Чтение из потока — это перенос информации из потока в структуру данных, такую как массив байтов. 2. Запись в поток — это передача данных из структуры данных в поток. 3. Потоки также могут поддерживать поиск. Программы, составленные на языке C#, работают с каталогами, файлами и потоками при помощи специально предназначенных для этого классов, входящих в состав библиотеки классов Microsoft.NET Framework и содержащихся в пространстве имен System.IO, которое необходимо подключить, чтобы обеспечить доступ к классам, определенным для потоков ввода-вывода (см. Пример 7.1). Для работы с директориями и файлами предназначены следующие основные классы: Directory предоставляет статические методы операций создания, перемещения и перечисления в директориях и поддиректориях. Класс DirectoryInfo предоставляет методы экземпляра. File предоставляет статические методы для создания, копирования, удаления, перемещения и открытия файлов, а также помогает при создании объектов FileStream. Класс FileInfo предоставляет методы экземпляра. Для работы с потоками предназначены следующие основные классы: FileStream предоставляет поток в файле, поддерживая операции чтения и записи. Класс StreamReader считывает символы из потоков с учетом кодировки, к ласс StreamWriter записывает символы в потоки, используя кодировку для преобразования символов в байты (см. Пример 7.1). Стандартные потоки связаны, как правило, с консолью и клавиатурой. Для вывода данных в стандартный поток вывода и для ввода из стандартного потока ввода используются методы класса Console: Console.ReadLine, Console.Write и Console.WriteLine. Эти методы и использовались до сих пор во всех примерах программ. Количество классов, предназначенных для работы с файлами, достаточно велико. Здесь будут рассмотрены только классы, предназначенные для чтения из текстового файла или записи в текстовый файл: StreamReader и StreamWriter. Для ввода из файла (созданного заранее в текстовом редакторе) необходимо вначале открыть поток класса StreamReader, связав его с файлом. В приведенном ниже примере файл, из которого предполагается считывать данные, расположен по адресу С: \st\Koord.txt (это полный путь к файлу). Открытие потока и его привязка к файлу осуществляются с помощью конструктора (возможны и другие способы, которые здесь не рассматриваются). StreamReader sr = new StreamReader(path); Здесь sr – экземпляр класса StreamReader, а аргумент path передает конструктору строку, содержащую полный путь к файлу (в качестве аргумента можно использовать и константу, содержащую полный адрес файла). Далее строки из файла (в программе это поток sr) по очереди считываются в переменную line, из которой далее как обычно извлекаются отдельные значения. После окончания работы с объявленным потоком, его следует закрыть методом Close sr.Close(); Пример 7.1. Координаты произвольного количества точек на плоскости размещены в файле Koord.txt на диске С в папке (директории) st по два числа (значения x и y) в строке. В первой строке файла размещено одно число — радиус окружности r. Требуется определить, сколько точек попадет в круг радиуса r.
using System; using System.IO; class Program { static void Main() { string path = " С: \\st \\Koord.txt"; StreamReader sr = new StreamReader(path); int n = 0; string line; line = sr.ReadLine(); int r = int.Parse(line); Console.WriteLine(" Радиус {0}", r); while ((line = sr.ReadLine())! = null) { string[] koord = line.Split(' '); int x = int.Parse(koord[0]); int y = int.Parse(koord[1]); Console.WriteLine(" Координаты точек x = {0} y = {1}", x, y); if (x * x + y * y < r * r) n = n + 1; } sr.Close(); Console.WriteLine(" {0} точки попадут в круг ", n); } } Замечание. В программе в адресе файла вместо одной наклонной черты используется две. Одна наклонная черта в строке могла бы восприниматься как первый символ управляющей последовательности. Использование двух наклонных позволяет избежать этой двусмысленности. Теперь наклонная черта будет восприниматься как символ строки, а не как управляющая последовательность (см. п. 1.2). В C# предусмотрен также способ объявления строки, в которой все символы между кавычками трактуются как часть строки. Это специальное объявление – буквальные строки – задается указанием символа @ перед всей строкой и обычно используется для задания пути к файлу. С использованием этого объявления задание строки path может выглядеть так string path = @" С: \st \Koord.txt"; При выводе в файл необходимовыполнить аналогичные действия: открыть поток класса StreamWriter, задав имя потока и связав его с файлом, предназначенным для размещения выводимых результатов, вывести в этот поток (т.е. в указанный файл) необходимые результаты и закрыть поток оператором Close(). Если в примере 7.1 предполагается также вывод результата в файл, то необходимо добавить следующие инструкции string path1 = " c: \\st\\Koord1.txt"; StreamWriter sw = new StreamWriter(path1); sw.WriteLine(n); sw.Close();
Далее рассмотрим пример, в котором осуществляется ввод из файла исходных данных и вывод результатов в файл с учетом регионального стандарта (см. Приложение 3). Пример. 7.2. Протокол соревнований по прыжкам в высоту содержит список фамилий и результатов (одна попытка) в порядке стартовых номеров. Получить итоговую таблицу, содержащую фамилии и результаты в порядке занятых мест. Количество спортсменов не более 30. Для размещения исходных данных используется массив структур. Структура содержит информацию – фамилия и результат спортсмена. Ввод данных осуществлять из заранее подготовленного файла, вывод итоговой таблицы осуществлять в файл. (В примере 4.1 эта же задача решена без использования файлов данных.) Исходный файл using System; using System.Text; using System.IO; namespace ConsoleApplication1 { struct Sportsmen { public string famile; public double rez; } class Program { static void Main(string[] args) { Sportsmen[] sp = new Sportsmen[5]; string line; string path = " c: \\st\\Sportsmen.txt"; //кодовая страница операционной системы Windows для кирилицы имеет StreamReader sr = new StreamReader(path, Encoding.GetEncoding(1251)); int i = 0; while ((line = sr.ReadLine())! = null) { string[] sports = line.Split(' '); sp[i].famile = sports[0]; sp[i].rez = double.Parse(sports[1]); Console.WriteLine(" Фамилия {0}\t Результат {1: f2}", i++; } sr.Close(); for (i = 0; i < sp.Length - 1; i++) { double amax = sp[i].rez; int imax = i; for (int j = i + 1; j < sp.Length; j++) { if (sp[j].rez > amax) { amax = sp[j].rez; imax = j; } } Sportsmen temp; temp = sp[imax]; sp[imax] = sp[i]; sp[i] = temp; } Console.WriteLine(); for (i = 0; i < sp.Length; i++) { Console.WriteLine(" Фамилия {0}\t Результат {1: f2}", } string path1 = " c: \\st\\Sportsmen1.txt"; StreamWriter sw = new StreamWriter(path1); for (i = 0; i < sp.Length; i++) { sw.WriteLine(" {0} {1: f2}", sp[i].famile, sp[i].rez); } sw.Close(); } } } Файл с результатами
Замечание. Дополнительно о региональных стандартах см. в Приложении 3.
Вопросы для самопроверки 1. Что такое файл, директория, поддиректория. 2. В чем преимущества использования файлов для ввода и вывода. 3. Что такое поток. Какие операции определены для потока. 4. Открытие потока для чтения и его привязка к файлу. 5. Что такое «полный путь к файлу». 6. Считывание из файла в переменные программы. 7. Открытие потока для вывода и привязка его к файлу, предназначенному для вывода результатов. 8. Закрытие потоков.
|