ababin b365400fc1 Добавить 'README.md' | 6 meses atrás | |
---|---|---|
.idea | 7 meses atrás | |
ConsoleApp17 | 7 meses atrás | |
ConsoleApp17.sln | 7 meses atrás | |
README.md | 6 meses atrás |
Работу с файловой системой начнем с самого верхнего уровня - дисков. Для представления диска в пространстве имен System.IO имеется класс DriveInfo. Получим имена и свойства всех дисков на компьютере:
using System;
using System.IO;
DriveInfo[] drives = DriveInfo.GetDrives();
foreach (DriveInfo drive in drives)
{
Console.WriteLine($"Название: {drive.Name}");
Console.WriteLine($"Тип: {drive.DriveType}");
if (drive.IsReady)
{
Console.WriteLine($"Объем диска: {drive.TotalSize}");
Console.WriteLine($"Свободное пространство: {drive.TotalFreeSpace}");
Console.WriteLine($"Метка: {drive.VolumeLabel}");
}
Console.WriteLine();
}
Вывод:
Название: C:\
Тип: Fixed
Объем диска: 2048268763136
Свободное пространство: 666030469120
Метка: disk
Название: D:\
Тип: Fixed
Объем диска: 1000186310656
Свободное пространство: 88899846144
Метка: диск
Название: E:\
Тип: Fixed
Объем диска: 118615961600
Свободное пространство: 118456012800
Метка: Локальный диск
Название: F:\
Тип: Fixed
Объем диска: 1024191361024
Свободное пространство: 307054309376
Метка: disk
Название: H:\
Тип: CDRom
Для работы с каталогами в пространстве имен System.IO предназначены сразу два класса: Directory и DirectoryInfo.
Класс Directory предоставляет ряд статических методов для управления каталогами. Некоторые из этих методов:
CreateDirectory(path): создает каталог по указанному пути path Delete(path): удаляет каталог по указанному пути path Exists(path): определяет, существует ли каталог по указанному пути path. Если существует, возвращается true, если не существует, то false GetDirectories(path): получает список каталогов в каталоге path GetFiles(path): получает список файлов в каталоге path Move(sourceDirName, destDirName): перемещает каталог GetParent(path): получение родительского каталога
Данный класс предоставляет функциональность для создания, удаления, перемещения и других операций с каталогами. Во многом он похож на Directory. Некоторые из его свойств и методов:
Create(): создает каталог CreateSubdirectory(path): создает подкаталог по указанному пути path Delete(): удаляет каталог Свойство Exists: определяет, существует ли каталог GetDirectories(): получает список каталогов GetFiles(): получает список файлов MoveTo(destDirName): перемещает каталог Свойство Parent: получение родительского каталога Свойство Root: получение корневого каталога Посмотрим на примерах применение этих классов
Получение списка файлов и подкаталогов
string dirName = "C:\\";
if (Directory.Exists(dirName))
{
Console.WriteLine("Подкаталоги:");
string[] dirs = Directory.GetDirectories(dirName);
foreach (string s in dirs)
{
Console.WriteLine(s);
}
Console.WriteLine();
Console.WriteLine("Файлы:");
string[] files = Directory.GetFiles(dirName);
foreach (string s in files)
{
Console.WriteLine(s);
}
}
Создание каталога
string path = @"C:\SomeDir";
string subpath = @"program\avalon";
DirectoryInfo dirInfo = new DirectoryInfo(path);
if (!dirInfo.Exists)
{
dirInfo.Create();
}
dirInfo.CreateSubdirectory(subpath);
Получение информации о каталог
string dirName = "C:\\Program Files";
DirectoryInfo dirInfo = new DirectoryInfo(dirName);
Console.WriteLine($"Название каталога: {dirInfo.Name}");
Console.WriteLine($"Полное название каталога: {dirInfo.FullName}");
Console.WriteLine($"Время создания каталога: {dirInfo.CreationTime}");
Console.WriteLine($"Корневой каталог: {dirInfo.Root}");
Удаление каталога В метод Delete дополнительный параметр булевого типа, который укажет, что папку надо удалять со всем содержимым:
string dirName = @"C:\SomeFolder";
try
{
DirectoryInfo dirInfo = new DirectoryInfo(dirName);
dirInfo.Delete(true);
Console.WriteLine("Каталог удален");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Перемещение каталога
string oldPath = @"C:\SomeFolder";
string newPath = @"C:\SomeDir";
DirectoryInfo dirInfo = new DirectoryInfo(oldPath);
if (dirInfo.Exists && Directory.Exists(newPath) == false)
{
dirInfo.MoveTo(newPath);
}
Получение информации о файле
string path = @"C:\apache\hta.txt";
FileInfo fileInf = new FileInfo(path);
if (fileInf.Exists)
{
Console.WriteLine("Имя файла: {0}", fileInf.Name);
Console.WriteLine("Время создания: {0}", fileInf.CreationTime);
Console.WriteLine("Размер: {0}", fileInf.Length);
}
Удаление файла
string path = @"C:\apache\hta.txt";
FileInfo fileInf = new FileInfo(path);
if (fileInf.Exists)
{
fileInf.Delete();
// альтернатива с помощью класса File
// File.Delete(path);
}
Перемещение файла
string path = @"C:\apache\hta.txt";
string newPath = @"C:\SomeDir\hta.txt";
FileInfo fileInf = new FileInfo(path);
if (fileInf.Exists)
{
fileInf.MoveTo(newPath);
// альтернатива с помощью класса File
// File.Move(path, newPath);
}
Создание FileStream
FileStream(string filename, FileMode mode)
Посмотрим на примере считывания-записи в текстовый файл:
using System;
using System.IO;
namespace HelloApp
{
class Program
{
static void Main(string[] args)
{
// создаем каталог для файла
string path = @"C:\SomeDir2";
DirectoryInfo dirInfo = new DirectoryInfo(path);
if (!dirInfo.Exists)
{
dirInfo.Create();
}
Console.WriteLine("Введите строку для записи в файл:");
string text = Console.ReadLine();
// запись в файл
using (FileStream fstream = new FileStream($"{path}\note.txt", FileMode.OpenOrCreate))
{
// преобразуем строку в байты
byte[] array = System.Text.Encoding.Default.GetBytes(text);
// запись массива байтов в файл
fstream.Write(array, 0, array.Length);
Console.WriteLine("Текст записан в файл");
}
// чтение из файла
using (FileStream fstream = File.OpenRead($"{path}\note.txt"))
{
// преобразуем строку в байты
byte[] array = new byte[fstream.Length];
// считываем данные
fstream.Read(array, 0, array.Length);
// декодируем байты в строку
string textFromFile = System.Text.Encoding.Default.GetString(array);
Console.WriteLine($"Текст из файла: {textFromFile}");
}
Console.ReadLine();
}
}
}
В реальных приложениях рекомендуется использовать асинхронные версии методов FileStream, поскольку операции с файлами могут занимать продолжительное время и являются узким местом в работе программы. Например, изменим выше приведенную программу, применив асинхронные методы:
using System;
using System.IO;
using System.Threading.Tasks;
namespace HelloApp
{
class Program
{
static async Task Main(string[] args)
{
// создаем каталог для файла
string path = @"C:\SomeDir3";
DirectoryInfo dirInfo = new DirectoryInfo(path);
if (!dirInfo.Exists)
{
dirInfo.Create();
}
Console.WriteLine("Введите строку для записи в файл:");
string text = Console.ReadLine();
// запись в файл
using (FileStream fstream = new FileStream($"{path}\note.txt", FileMode.OpenOrCreate))
{
byte[] array = System.Text.Encoding.Default.GetBytes(text);
// асинхронная запись массива байтов в файл
await fstream.WriteAsync(array, 0, array.Length);
Console.WriteLine("Текст записан в файл");
}
// чтение из файла
using (FileStream fstream = File.OpenRead($"{path}\note.txt"))
{
byte[] array = new byte[fstream.Length];
// асинхронное чтение файла
await fstream.ReadAsync(array, 0, array.Length);
string textFromFile = System.Text.Encoding.Default.GetString(array);
Console.WriteLine($"Текст из файла: {textFromFile}");
}
Console.ReadLine();
}
}
}
С помощью метода Seek мы можем управлять положением курсора потока, начиная с которого производится считывание или запись в файл. Этот метод принимает два параметра: offset (смещение) и позиция в файле. Позиция в файле описывается тремя значениями:
SeekOrigin.Begin: начало файла
SeekOrigin.End: конец файла
SeekOrigin.Current: текущая позиция в файле
Курсор потока, с которого начинается чтение или запись, смещается вперед на значение offset относительно позиции, указанной в качестве второго параметра. Смещение может быть отрицательным, тогда курсор сдвигается назад, если положительное - то вперед.
Рассмотрим на примере:
using System.IO;
using System.Text;
class Program
{
static void Main(string[] args)
{
string text = "hello world";
// запись в файл
using (FileStream fstream = new FileStream(@"D:\note.dat", FileMode.OpenOrCreate))
{
// преобразуем строку в байты
byte[] input = Encoding.Default.GetBytes(text);
// запись массива байтов в файл
fstream.Write(input, 0, input.Length);
Console.WriteLine("Текст записан в файл");
// перемещаем указатель в конец файла, до конца файла- пять байт
fstream.Seek(-5, SeekOrigin.End); // минус 5 символов с конца потока
// считываем четыре символов с текущей позиции
byte[] output = new byte[4];
fstream.Read(output, 0, output.Length);
// декодируем байты в строку
string textFromFile = Encoding.Default.GetString(output);
Console.WriteLine($"Текст из файла: {textFromFile}"); // worl
// заменим в файле слово world на слово house
string replaceText = "house";
fstream.Seek(-5, SeekOrigin.End); // минус 5 символов с конца потока
input = Encoding.Default.GetBytes(replaceText);
fstream.Write(input, 0, input.Length);
// считываем весь файл
// возвращаем указатель в начало файла
fstream.Seek(0, SeekOrigin.Begin);
output = new byte[fstream.Length];
fstream.Read(output, 0, output.Length);
// декодируем байты в строку
textFromFile = Encoding.Default.GetString(output);
Console.WriteLine($"Текст из файла: {textFromFile}"); // hello house
}
Console.Read();
}
}
Вывод:
Текст записан в файл
Текст из файла: worl
Текст из файла: hello house
FileStream fstream = null;
try
{
fstream = new FileStream(@"D:\note3.dat", FileMode.OpenOrCreate);
// операции с потоком
}
catch(Exception ex)
{
}
finally
{
if (fstream != null)
fstream.Close();
}
Рассмотрим запись в файл на примере:
using System;
using System.IO;
namespace HelloApp
{
class Program
{
static void Main(string[] args)
{
string writePath = @"C:\SomeDir\hta.txt";
string text = "Привет мир!\nПока мир...";
try
{
using (StreamWriter sw = new StreamWriter(
writePath, false, System.Text.Encoding.Default))
{
sw.WriteLine(text);
}
using (StreamWriter sw = new StreamWriter(
writePath, true, System.Text.Encoding.Default))
{
sw.WriteLine("Дозапись");
sw.Write(4.5);
}
Console.WriteLine("Запись выполнена");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
По завершении программы в папке C:/SomeDir мы сможем найти файл hta.txt, который будет иметь следующие строки:
Привет мир!
Пока мир...
Дозапись
4,5
Поскольку операции с файлами могут занимать продолжительное время, то в общем случае рекомендуется использовать асинхронную запись. Используем асинхронные версии методов:
using System;
using System.IO;
using System.Threading.Tasks;
namespace HelloApp
{
class Program
{
static async Task Main(string[] args)
{
string writePath = @"C:\SomeDir\hta2.txt";
string text = "Привет мир!\nПока мир...";
try
{
using (StreamWriter sw = new StreamWriter(
writePath, false, System.Text.Encoding.Default))
{
await sw.WriteLineAsync(text);
}
using (StreamWriter sw = new StreamWriter(
writePath, true, System.Text.Encoding.Default))
{
await sw.WriteLineAsync("Дозапись");
await sw.WriteAsync("4,5");
}
Console.WriteLine("Запись выполнена");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
Посмотрим на реальной задаче применение этих классов. Попробуем с их помощью записывать и считывать из файла массив структур:
struct State
{
public string name;
public string capital;
public int area;
public double people;
public State(string n, string c, int a, double p)
{
name = n;
capital = c;
people = p;
area = a;
}
}
class Program
{
static void Main(string[] args)
{
State[] states = new State[2];
states[0] = new State("Германия", "Берлин", 357168, 80.8);
states[1] = new State("Франция", "Париж", 640679, 64.7);
string path= @"C:\SomeDir\states.dat";
try
{
// создаем объект BinaryWriter
using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.OpenOrCreate)))
{
// записываем в файл значение каждого поля структуры
foreach (State s in states)
{
writer.Write(s.name);
writer.Write(s.capital);
writer.Write(s.area);
writer.Write(s.people);
}
}
// создаем объект BinaryReader
using (BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open)))
{
// пока не достигнут конец файла
// считываем каждое значение из файла
while (reader.PeekChar() > -1)
{
string name = reader.ReadString();
string capital = reader.ReadString();
int area = reader.ReadInt32();
double population = reader.ReadDouble();
Console.WriteLine("Страна: {0} столица: {1} площадь {2} кв. км численность населения: {3} млн. чел.",
name, capital, area, population);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.ReadLine();
}
}
Атрибут Serializable Чтобы объект определенного класса можно было сериализовать, надо этот класс пометить атрибутом Serializable:
[Serializable]
class Person
{
public string Name { get; set; }
public int Year { get; set; }
public Person(string name, int year)
{
Name = name;
Year = year;
}
}
Для бинарной сериализации применяется класс BinaryFormatter:
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace Serialization
{
[Serializable]
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
class Program
{
static void Main(string[] args)
{
// объект для сериализации
Person person = new Person("Tom", 29);
Console.WriteLine("Объект создан");
// создаем объект BinaryFormatter
BinaryFormatter formatter = new BinaryFormatter();
// получаем поток, куда будем записывать сериализованный объект
using (FileStream fs = new FileStream("people.dat", FileMode.OpenOrCreate))
{
formatter.Serialize(fs, person);
Console.WriteLine("Объект сериализован");
}
// десериализация из файла people.dat
using (FileStream fs = new FileStream("people.dat", FileMode.OpenOrCreate))
{
Person newPerson = (Person)formatter.Deserialize(fs);
Console.WriteLine("Объект десериализован");
Console.WriteLine($"Имя: {newPerson.Name} --- Возраст: {newPerson.Age}");
}
Console.ReadLine();
}
}
}