Содержание:
Теория
- Компонентный тип:
- текстовые файлы (состоит из строк в некоторой кодировке)
- бинарные файлы
- Тип доступа к файлу:
- Произвольный доступ: время доступа = Θ(1), компоненты данных имеют одинаковый размер
 (байты в простейшем случае)
- Последовательный доступ: компоненты данных имеют различный размер, для поиска i-го компонента необходимо считать предыдущийi-1компонент (пример: текстовые файлы)
- Типы операций с файлами:
- только для чтения
- только для записи
- чтение и запись
- using System.IO;
- using System.Text;
- File – статический класс, операции с закрытыми файлами
- FileMode – режим открытия файла
- FileStream
- StreamReader/StreamWriter – потоки для чтения-записи в текстовые файлы
- BinaryReader/BinaryWriter — потоки для чтения-записи в двоичные файлы
- Encoding – кодировки файлов
- Классы FileиFileInfoоба предоставляют методы для создания, копирования, удаления, перемещения и открытия файлов. Они имеют очень похожие интерфейсы, разница лишь в том, чтоFileInfoобеспечивает методы экземпляра, тогда какFileобеспечивает методы static.
- Разница в том, что если у вас будет небольшое количество операций, удобнее обращаться к статическим методам класса File. Если у вас будет много операций, более эффективно создать классFileInfoи получить доступ ко всем его методам экземпляра.
- Класс Directoryпредоставляет статические методы, в то время какDirectoryInfoпредоставляет методы экземпляра.
- У нас также есть класс Path, который предоставляет методы для работы со строкой, содержащей информацию о пути к файлу или каталогу.
- FileMode.Create
- FileMode.Open
- FileMode.OpenOrCreate
- FileMode.Append
- Инструкция Usingобеспечивает автоматический вызов методаClose()при работе с классомFileStream.
Классификация файлов
Операции с файлами
| с закрытыми файлами: открыть проверить существует ли удалить скопировать переименовать переместить | С уже открытыми файлами: закрыть записать информацию читать информацию проверить, достигнут ли конец файла поиск n-й позиции | 
Классы и пространства имен .NET
- 
Пространства имен:
В платформе .net есть пространство имен System.IO, именно там расположено множество классов для работы с файлами и каталогами.
Классы:
FileMode тип перечисленияОсновные методы класса File
- 
Operations with closed files:
| using System.IO; // File.Exists("a.dat") Console.WriteLine(File.Exists("a.dat")); // true или false // File.Exists("d:\\a.dat") Console.WriteLine(File.Exists("d:\\a.dat")); // true или false // File.Exists(@"d:\a.dat") Console.WriteLine(File.Exists(@"d:\a.dat"); // true или false File.Delete("a.dat"); File.Copy("d:\\a.dat", "d:\\b.dat"); // будет создан файл b.dat, если он существует - возникнет исключение File.Copy("a.dat", @"d:\a.dat"); File.Move("a.dat", @"..\a.dat"); | 
Конструкция try .. catch
| try { // код с возможным исключением } catch (Exception e) { // для обработки исключения } | 
Пример:
| try { var path = @"d:\a.dat"; var fs = new FileStream(path, FileMode.Open); ... } catch (FileNotFoundException e) { Console.WriteLine($"Файл с именем {e.FileName} не найден"); } catch (FileLoadException e) { Console.WriteLine($"К файлу с именем {e.FileName} невозможно получить доступ"); } | 
ИнструкцияUsing
Пример работы с двоичными файлами:
| using System.IO; // ... string path = @"Lesson14.dat"; // данные в файле: 1 2 3 4 var fs = new FileStream(path, FileMode.Open); var br = new BinaryReader(fs); var a=br.ReadInt32(); Console.WriteLine(a); // 1 var b = br.ReadInt32(); Console.WriteLine(b); // 2 var c = br.ReadInt32(); Console.WriteLine(c); // 3 fs.Close(); | 
Example:
| var path = @"d:\a.dat"; using (var fs = new FileStream(path, FileMode.Create)) { fs.WriteByte(1); fs.WriteByte(2); fs.WriteByte(3); } using (var fs = new FileStream(path, FileMode.Open)) { Console.WriteLine(fs.ReadByte()); Console.WriteLine(fs.ReadByte()); Console.WriteLine(fs.ReadByte()); } | 
Задания и лабораторные работы
Использование режима для создания файла и работы с ним без класса BinaryReader
Выполнить: Create a file with a name myFile.txt on your root folder d or c  (@"D:\myFile.txt"). Open created file and write there some entered string (don’t forget to convert it into a byte array -> Encoding.Default.GetBytes()). Then, read the file’s data and output it to the console window (by convering data again into string -> Encoding.Default.GetString(...)).
Создайте файл с именем myFile.txt в вашей корневой папке d или c (@"D:\myFile.txt"). Откройте созданный файл и запишите туда некоторую введенную строку (не забудьте преобразовать ее в байтовый массив -> Encoding.Default.GetBytes()). Затем считайте данные файла и выводите их в окно консоли (путем повторного преобразования данных в строку -> Encoding.Default.GetString(...)).
    
Примерный вывод:
Введите строку: Hello, world! Строка из файла: Hello, world!
[Название проекта: Lesson_14Task0, Название файла L14Task0.cs]
Обработка ошибок при работе с файлами. Оператор Try. Считывание данных из файла
Выполнить:
- Создайте программу для вывода содержимого файла в окно консоли (числа могут быть выведены через пробелы в строку). Вы должны использовать класс BinaryReader.
- Скачайте файл L01.dat и поместите его в свою рабочую папку (~/Lesson_14 Lab1/bin/Debug). В файле записано 15 целых чисел..
- Вы должны использовать инструкцию usingпри работе с уже открытым файлом. Тогда, независимо от успеха работы с открытым файлом, он всегда будет закрыт.
- Используйте код для обработки исключений:
- Чтобы предотвратить «сбой» программы и не напугать пользователя, добавьте обработку исключений — блок try..catch. Операторusingдолжен находиться внутри блокаtry..catch.
 ... try { ... } catch (IOException e) { Console.WriteLine($"Ошибка чтения из файла: {e.Message}"); } 
- Чтобы предотвратить «сбой» программы и не напугать пользователя, добавьте обработку исключений — блок 
- Измените имя файла в программном коде на несуществующее. Запустите приложение и проверьте обработку исключения. Снова измените имя на правильное имя.
- Здесь нет необходимости создавать методы.
| using (var fs = new FileStream(path, FileMode.Create)) { ... } | 
Примерный вывод:
Данные из файла: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 +++++++++++++ Данные из файла: Ошибка чтения из: Файл 'C:\Users\User\Documents\Visual Studio 2015\Projects\L14_Lab1\bin\Debug\L02.dat' не найден
 
[Название проекта: Lesson_14Lab1, название файла L14Lab1.cs]
✍ Алгоритм:
- Создайте новый проект с именем файла, как указано в задании.
- Загрузите файл L01.dat и поместите его в свою рабочую папку  (~/Lesson_14Lab1/bin/Debug).
- Чтобы избежать необходимости постоянно упоминать класс Console, мы можем включить его объявление прямо в начале окна редактора:
- Ниже этого кода подключите пространство имен System.IO— для работы с файлами:
- В функции Mainобъявите переменную для хранения пути к файлу. Лучше использовать дословную строку (символ@):
- Чтобы прочитать что-то из файла, сначала нужно открыть файл. Чтобы открыть файл, требуется указать путь к файлу в системе и режим.
- Итак, нам нужно инициализировать новый экземпляр класса FileStreamс указанным путем и режимом. Будем использовать режимopen(для чтения из файла), потому что нам не нужно ничего записывать в файл. Переменнаяfsбудет хранить входной поток:
- После этого нам нужно создать переменную (br) — экземпляр классаBinaryReader, чтобы иметь возможность считывать данные из файла в виде двоичных значений:
- Чтобы не возникало ошибки, если файл не существует или если имя файла написано неверно, мы будем использовать блок try...catch. Поместите добавленные инструкцииusingв блокtry:
- Кроме того, внутри блока tryмы собираемся считывать байты или символы из файла и выводить их в консоль. Для этой цели будем использовать методPeekCharклассаBinaryReader:
- В блоке catchмы собираемся распечатать сообщение в случае возникновения какой-либо ошибки, например, в случае неправильного имени файла:
- В конце программного кода поместите метод ReadKey, чтобы не закрывать окно консоли при запуске программы в режиме отладки:
- Нажмите клавишу F5, чтобы запустить программу в режиме отладки и проверить выходные данные.
- Чтобы увидеть результат при возникновении ошибки, измените имя файла, например:
- Нажмите клавишу F5, чтобы запустить программу в режиме отладки и проверить выходные данные.
- Верните прежнее название файла
- Загрузите файл .csна проверку.
... using static System.Console; ...
using System.IO; ...
path = @"L01.dat";
using (var fs = new FileStream(path, FileMode.Open))
FileStream предоставляет поток (последовательность байтов) для ввода/считывания из файла; поддерживает как синхронные, так и асинхронные операции чтения и записи.... using (var br = new BinaryReader(fs))
... try { using (var fs = new FileStream(path, FileMode.Open)) using (var br = new BinaryReader(fs)) }
// в блоке try, после использования инструкций using: while (br.PeekChar() != -1) { var x = br.ReadInt32(); Write($"{x} "); }
BinaryReader класс считывает примитивные типы данных как двоичные значения в определенной кодировке.PeekChar метод возвращает следующий доступный символ или -1, если больше нет доступных символов или поток не поддерживает поиск.// under try block: catch (IOException e) { WriteLine($"Ошибка чтения из файла: {e.Message}"); }
IOException хранит исключение, которое генерируется при возникновении ошибки ввода-вывода.Message — это атрибут класса Exception, который возвращает сообщение об ошибке, объясняющее причину исключения, или пустую строку.
// после закрывающей скобки блока catch
ReadKey();
ReadKey ожидает ввода или нажатия клавиши клавиатуры. Нажатая клавиша отображается в окне консоли.path = @"L02.dat";
Выполнить: Скопируйте файл L01.dat для предыдущей лабораторной работы и вставьте его в папку текущего задания, пусть к файлу: (~/Lesson_14Task1/bin/Debug).
1. Создайте программу для вывода чисел в квадрате из файла в окно консоли (числа могут быть выведены через пробел в пределах одной строки), а также для вычисления количества четных цифр среди чисел. Вы должны использовать класс BinaryReader. Создайте программу, используя блок try..catch.
Указание: Здесь нет необходимости создавать методы.
     
Примерный вывод:
Квадраты чисел: 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 Количество четных: 7 +++++++++++++++ Ошибка чтения из файла: Файл 'c:\users\user\documents\visual studio 2015\Projects\L_14Task1\bin\Debug\L02.dat' не найден.
[Название проекта: Lesson_14Task1, название файла L14Task1.cs]
Выполнить:
- Загрузите файл в папку с проектом L01.dat. В файле записаны целые числа. Выведите эти числа в окно консоли по Nчисел в каждой строке (Nвводится (N > 0) и имеет значение по умолчанию =10). Необходимо использовать классBinaryReader. В случае если файл пустой выведите сообщение «пустой файл».
- Может быть несколько блоков try..catch, и каждый из них может обрабатывать разные ошибки. Напишите свой код так, чтобы один блокtry..catchобрабатывал ошибки, возникающие при открытии файла, а другой блок обрабатывал ошибки, возникающие при работе с уже открытым файлом.
- Тогда структура программы должна быть следующей:
- Создайте метод с двумя параметрами для выполнения задачи. Сигнатура метода:
- Проверьте, правильно ли работают блоки try..catch. Смоделируйте ошибку при работе с уже открытым файлом и ошибку с именем файла. После проверки верните предыдущий (правильный) код и закомментируйте неверный код.
| ... try { using ( ... ) using ( ... ) { try { // работа с открытым файлом... } catch { // обработка ошибки при работе с уже открытым файлом } } catch { // обработка ошибки, связанной с открытием файла } | 
| static void PrintFileInRows(string path, int N=10) | 
Примерный вывод:
Введите N: 3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 +++++++++++++ Введите N: 3 Ошибка чтения из файла: Файл 'c:\users\user\documents\visual studio 2015\Projects\L_14Lab2\bin\Debug\L02.dat' не найден. +++++++++++++ Введите N: 3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Ошибка работы с данными файла: Чтение после конца потока невозможно.
 
[Название проекта: Lesson_14Lab2, название файла L14Lab2.cs]
✍ Алгоритм:
- Создайте новый проект с именем и именем файла, как указано в задаче.
- Загрузите файл L01.dat и разместите его в рабочей папке проекта (~/Lesson_14Lab2/bin/Debug).
- Чтобы не печатать постоянно класс Console, мы можем включить его объявление прямо в начале окна редактора:
- Подключите пространство имен <код>System.IO для работы с файлами:
- В функции Mainобъявите переменную для хранения пути к файлу. Лучше использовать дословную строку (символ@):
- Мы собираемся вывести числа из файла в нескольких строках: <код> N чисел в каждой строке. В функции main нам нужно запросить пользователя число <код>N:
- Затем необходимо объявить метод с именем PrintFileInRowsс двумя параметрами — путь к файлу и количествоN:
- Чтобы прочитать что-то из файла, сначала нужно открыть файл. Но в соответствии с требованием задачи у нас должно быть два блока try..catch, один из них обрабатывает ошибки, возникающие при открытии файла, а другой блок обрабатывает ошибки, возникающие при работе с уже открытым файлом.
- Итак, давайте сначала создадим блоки try..catch, а затем поместим в них остальной код:
- Чтобы открыть файл, необходимо указать путь к файлу в вашей системе и режим открытия — как операционная система должна открывать файл. Поместите следующий код после открытой фигурной скобки первого блока try..catch:
- После этого мы собираемся работать с файлом, это означает, что мы будем считывать некоторые данные из файла и что-то с ними делать. Итак, нам нужно создать переменную (br) как экземпляр классаBinaryReader, чтобы иметь возможность считывать данные из файла в виде двоичных значений. Следующий код должен быть помещен во второй блокtry..catch, который находится внутри инструкцииusing:
- В соответствии с требованиями задачи мы должны вывести сообщение «пустой файл», если в файле нет никаких данных. Лучше использовать метод PeekChar, который возвращает-1, если файл пуст:
- После этого мы будем считывать числа одно за другим из файла и выводить их в консоль. Необходимо выводить <код>N чисел в каждой строке. Используем счетчик i, чтобы подсчитать, сколько чисел мы уже прочитали. Если количество считанных чисел равноN, то мы перейдем к следующей строке:
- В первом блоке catchмы собираемся распечатать сообщение в случае возникновения какой-либо ошибки при работе с файлом:
- Во втором блоке catchмы собираемся распечатать сообщение в случае возникновения какой-либо ошибки при открытии файла:
- В конце кода программы поместите метод ReadKey, чтобы не закрывать окно консоли при запуске программы в режиме отладки:
- Нажмите F5, чтобы запустить программу в режиме отладки и проверить выходные данные.
- Чтобы увидеть результат при возникновении ошибки, измените имя файла, например:
- Нажмите F5, чтобы запустить программу в режиме отладки и проверить выходные данные.
- Верните правильное имя файлу.
- Чтобы увидеть результат при возникновении ошибки во время работы с файлом, добавьте следующую строку после инструкции while:
- Нажмите F5, чтобы запустить программу в режиме отладки и проверить выходные данные.
- Прокомментируйте неправильную строку кода.
- Загрузите файл .csв систему moodle.
... using static System.Console; ...
using System.IO; ...
path = @"L01.dat";
... WriteLine($"Введите N:"); var n = .Parse(ReadLine());
// после закрывающей фигурной скобки основной функции static PrintFileInRows( path, n = 10) { ... }
void.// в фигурных скобках метода try { /* здесь будет код, в котором могут возникать ошибки при открытии файла*/ { try { /* здесь будет код, в котором могут возникать ошибки при работе с уже открытым файлом*/ } catch (IOException e) { // сообщение об ошибке при работе с файлом } } } catch (IOException e) { // сообщение об ошибке при открытии файла } }
using ( f = File.Open(path, FileMode.Open)) { ... }
// после открытой фигурной скобки оператора using try { br = new BinaryReader(f);
if (br.PeekChar() == -1) { WriteLine("пустой файл"); }
// после предыдущего оператора if i = 0; while (br.PeekChar() != -1) { if (i >= n) { WriteLine(); i = 0; } Write(br.ReadInt32() + " "); i++; }
// within the first catch block: catch (IOException e) { WriteLine($"Ошибка работы с файлом: {e.Message}"); }
IOException хранит исключение, которое генерируется при возникновении ошибки ввода-вывода.Message — это атрибут класса Exception, который возвращает сообщение об ошибке, объясняющее причину исключения, или пустую строку («»).// в пределах первого блока catch: catch (IOException e) { Console.WriteLine($"Ошибка считывания из файла: {e.Message}"); }
// после закрывающей скобки блока фиксации:
ReadKey();
ReadKey получает следующий символ или функциональную клавишу, нажатую пользователем. Нажатая клавиша отображается в окне консоли.path = @"L02.dat";
// после закрытия фигурной скобки оператора while: WriteLine(br.ReadInt32());
Выполнить: Загрузите файл Task02.dat и вставьте его в папку с проектом:  (~/Lesson_14Task2/bin/Debug). В файле записаны целые числа. Создайте программу, которая сначала выведет эти числа в окно консоли, а после этого подсчитает количество чисел, которые меньше, чем их сосед слева (меньше, чем предыдущее число в последовательности чисел).
Указание 1: Создайте метод для печати данных из файла:
| static void PrintData(string path) | 
Указание 2: Создайте метод для вывода количества чисел, меньших, чем их сосед слева:
| static int CountLessThanLeft(string path) | 
Указание 3: Возможно, потребуется использовать определенную кодировку символов при чтении из файла:
| using (var fs = new FileStream(path, FileMode.Open)) using (var br = new BinaryReader(fs, Encoding.ASCII)) | 
Указание 4: Может быть несколько блоков try..catch, и каждый из них может обрабатывать разные ошибки. Напишите свой код так, чтобы один блок try..catch обрабатывал ошибки, возникающие при открытии файла, а другой блок обрабатывал ошибки, возникающие при работе с уже открытым файлом.
Тогда структура программы должна быть следующей:
| ... try { using ( ... ) using ( ... ) { try { //работа с открытым файлом... } catch { // обработка ошибки при работе с уже открытым файлом } } catch { // обработка ошибки открытия файла } | 
Указание 5: Проверьте, правильно ли работают блоки try..catch. Смоделируйте ошибку при работе с уже открытым файлом и ошибку с именем файла. После проверки верните предыдущий (правильный) код и закомментируйте неправильный.
Примерный вывод:
Числа в файле: -35 25 28 -37 13 -9 -24 12 -35 37 -24 20 29 -11 -45 -8 43 12 12 44 Количество чисел, меньших, чем их левый сосед: 8 +++++++++++++++ Числа в файле: -35 25 28 -37 13 -9 -24 12 -35 37 -24 20 29 -11 -45 -8 43 12 12 44 Ошибка работы с файлом: Чтение после конца потока невозможно. Количество чисел, меньших, чем их левый сосед: 8 +++++++++++++++
[Название проекта: Lesson_14Task2, Название файла L14Task2.cs]