Файлы данных (Пространство имен 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 = "c:\\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 = @"c:\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 для кирилицы имеет идентификатор

//1251

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}",

sp[i].famile,sp[i].rez);

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}",

sp[i].famile,sp[i].rez);

}

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. Закрытие потоков.

Задания для самостоятельного выполнения

Выполнить задания п. 4.1 с вводом исходных данных из файла и формированием файлов с результатами выполнения программы.

8. Разработка приложений
с графическим интерфейсом пользователя Windows.
Экранные формы

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

Далее на наглядных примерах рассматриваются основные возможности, предоставляемые при использовании экранных форм, и их реализация.

• Запустите Visual C#. В меню «Файл» выберите команду «Создать проект».

• Выберите шаблон «Приложение Windows Forms» (в поле Имя можно ввести любое имя проекта вместо стандартного) и нажмите кнопку ОК.

• Откроется конструктор Windows Forms с формой Windows. Это пользовательский интерфейс для создаваемого приложения:

• В меню «Вид» выберите команду «Панель элементов», чтобы открыть список элементов управления.

• Разверните список «Стандартные элементы» управления и перетащите два элемента управления TextBox на форму:

Дважды щелкните на форму Windows (Form1), чтобы открыть редактор кода. Visual C# вставил метод с именем Form1_Load, который выполняется при загрузке формы, – обработчик события Load, связанный с запуском приложения. Откроется редактор кода, при этом положение курсора окажется внутри обработчика событий. Обработчик событий – это метод, определяющий действия, которые требуется выполнить при возникновении события. События позволяют классу или объекту уведомлять другие классы или объекты о возникновении каких-либо ситуаций.

Замечание. При двойном щелчке на форму подпись метода и его содержимое (пустые кавычки { })

private void Form1_Load(object sender, EventArgs e)

{

 

}

генерируются автоматически. Одновременно автоматически генерируется код для вызова метода, который помещается в файл Form1.Designer.cs. Поэтому, если попытаться просто набрать код самостоятельно(без щелчка мышью), это не даст нужного эффекта (код для вызова метода не будет сгенерирован) и приведет к ошибке.