Содержание:
Теория
- Компонентный тип:
- текстовые файлы (состоит из строк в некоторой кодировке)
- бинарные файлы
- Тип доступа к файлу:
- Произвольный доступ: время доступа = Θ(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; ...
L01.dat";path = @"
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
ожидает ввода или нажатия клавиши клавиатуры. Нажатая клавиша отображается в окне консоли.L02.dat";path = @"
Выполнить: Скопируйте файл 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; ...
L01.dat";path = @"
... 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
получает следующий символ или функциональную клавишу, нажатую пользователем. Нажатая клавиша отображается в окне консоли.L02.dat";path = @"
// после закрытия фигурной скобки оператора 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
]