Завершение работы программы обычно также происходит по инициативе пользователя и приводит к закрытию окна

Вид материалаДокументы

Содержание


Сохранение результатов
Управление объектами файловой системы
Информация о логических дисках (класс DriveInfo)
Работа с каталогами (папками)
Свойства только для чтения
Свойства для чтения и записи
Создание каталога.
Перемещение (переименование) каталога
Работа с файлами
Запись в текстовый файл
Чтение из текстового файла
Добавление в текстовый файл
Перебор файлов каталога и определение размера файла
Получение и изменение атрибутов файла
Чтение и запись в бинарный файл
Подобный материал:
1   2   3   4   5   6   7   8   9   10   11

Сохранение результатов


Возможность хранить информацию в постоянной памяти является необходимым свойством большинства программных приложений. Для этого используются несколько различных подходов:
  1. Файловый ввод-вывод.
  2. Механизм сериализации.
  3. Базы данных.

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

Работа с файлами – наиболее традиционный способ использования постоянной памяти. Для этого в С# имеется множество классов, содержащихся в пространстве имен System.IO. Классы этого пространства имен можно разбить на 2 категории:
  1. Классы, управляющие объектами файловой системы.
  2. Классы, использующие потоки.

Управление объектами файловой системы


Как правило, файловая система представляется пользователю как иерархия объектов трех видов – диски, папки и файлы. Говоря о дисках, мы имеем ввиду логические диски, представленные пользователю по именам C: D: и т.д.

Классы, предоставляющие нужные нам возможности, находятся в пространстве имен System.IO. По какой-то причине разработчики «перестарались» и предоставили нам классы с существенно пересекающимися возможностями. Поэтому в других пособиях Вы можете встретиться с альтернативными способами решения тех же задач.

Информация о логических дисках (класс DriveInfo)


С помощью статического метода GetDrives класса DriveInfo можно получить массив объектов DriveInfo, а затем узнать о каждом диске подробную информацию:

DriveInfo[] allDrives = DriveInfo.GetDrives();

foreach (DriveInfo d in allDrives)

{ Console.WriteLine("Диск {0} Тип: {0}", d.Name, d.DriveType);

if (d.IsReady == true)

{ Console.WriteLine(" Метка: {0}", d.VolumeLabel);

Console.WriteLine(" Файловая система: {0}", d.DriveFormat);

Console.WriteLine(" Доступно пользователю:{0, 15} bytes",

d.AvailableFreeSpace);

Console.WriteLine(" Свободно:{0, 15} bytes", d.TotalFreeSpace);

Console.WriteLine(" Всего:{0, 15} bytes ", d.TotalSize);

}

}

Результат работы этого фрагмента может быть следующим:

Диск C:\ Тип: Removable

Диск C:\ Тип: Fixed

Метка:

Файловая система: NTFS

Доступно пользователю: 11452694528 байт

Свободно: 11452694528 байт

Всего: 31453437952 байт

Диск D:\ Тип: Fixed

Метка: Work

Файловая система: NTFS

Доступно пользователю: 29906001920 байт

Свободно: 29906001920 байт

Всего: 62915133440 байт

Диск F:\ Тип: CDRom

В этом списке присутствуют обозначения и съемных и виртуальных дисков.

Работа с каталогами (папками)


Для решения этих задач можно использовать класс DirectoryInfo.

Для начала с помощью свойства RootDirectory класса DriveInfo получим доступ к объекту DirectoryInfo, представляющему корневой каталог некоторого диска (в примере – второго диска):

DirectoryInfo rootDir = allDrives[1].RootDirectory;

Console.WriteLine(rootDir.FullName); //выводит полное имя

Далее выведем список имен подкаталогов корневого каталога. Здесь используется метод GetDirectories:

Console.WriteLine("Подкаталоги");

foreach (DirectoryInfo di in rootDir.GetDirectories())

Console.WriteLine(" {0}",di.Name);

Аналогично с помощью метода GetFiles выведем список имен файлов (объекты FileInfo):

Console.WriteLine("Файлы");

foreach (FileInfo fi in rootDir.GetFiles())

Console.WriteLine(" {0}", fi.Name);

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

static void TraverseDirectory(DirectoryInfo curDir, string level)

{ Console.WriteLine(level + curDir.Name);

foreach (DirectoryInfo di in curDir.GetDirectories())

TraverseDirectory(di, level + " ");

foreach (FileInfo fi in curDir.GetFiles())

Console.WriteLine(level + " " + "{0}", fi.Name);

}

Строковая переменная level помогает выводит имена файлов и каталогов с текстовыми отступами, соответствующими их уровням.

Поскольку файловая система имеет правильную древовидную организацию, каждое рекурсивное «погружение» обязательно приведет на тот уровень вложенности, где уже нет подкаталогов. В этом случае цикл foreach, осуществляющий рекурсивные вызовы будет пустым. Таким образом, все процедура обхода не окажется бесконечной. Однако применять этот прием нужно с осторожностью, поскольку на интенсивно используемом компьютере образуется чрезвычайно многоуровневая система каталогов и выполнение такого рекурсивного алгоритма приведет к исчерпанию вычислительных ресурсов (обычно такая ситуация формулируется как Stack Overflow). Потому без необходимости не применяйте этот прием для всего логического диска:

DriveInfo[] allDrives = DriveInfo.GetDrives();

DirectoryInfo rootDir = allDrives[1].RootDirectory;

Лучше определить конкретный каталог для перебора:

DirectoryInfo rootDir = new DirectoryInfo(@"D:\WORK\Крыша");

TraverseDirectory(rootDir, "");

Для получения информации о характеристиках каталогов в классе DirectoryInfo имеется несколько свойств.

Свойства только для чтения:

Exists наличие каталога.

FullName полный путь к каталогу.

Extension строка, содержащая расширение каталога.

Name имя каталога

Parent родительский каталог заданного подкаталога.

Root корневой элемент пути.

Свойства для чтения и записи:

Attributes атрибуты каталога

CreationTime время создания каталога

LastAccessTime время последнего доступа к текущему каталогу.

LastWriteTime время последней операции записи в текущий каталог.

Как видите, размер каталога Вам не предоставляется. Его придется вичислять самостоятельно рекурсивно.

Рассмотренные возможности предоставляли доступ к информации о каталогах «по чтению». Класс DirectoryInfo предоставляет и возможности «активной» работы с каталогами. Как правило, для того, чтобы выполнить какое-либо действие, связанное с каталогами, нужно сначала создать программный объект-каталог, указав его адрес:

DirectoryInfo di1 = new DirectoryInfo(@"c:\MyDir");

Это возможно как для уже физически существующего каталога, так и для вновь создаваемого.

Создание каталога.

di1.Create();

Создание подкаталога в заданном каталоге

DirectoryInfo di2 = di.CreateSubdirectory("SubDir");

Удаление каталога

di1.Delete();

Если удаляемый каталог не пуст, возникает исключение.

Перемещение (переименование) каталога

di.MoveTo(@"c:\NewTempDir");

Этот метод не позволяет перемещать каталог на другой диск (для этого придется «вручную» заняться всем содержимым каталога).

Работа с файлами


Для выполнения задач, связанных с файлами, можно использовать класс FileInfo.

Для получения списка файлов в папке используется статический метод GetFiles класса DirectoryInfo.

У методов GetDirectories и GetFiles имеется перегруженный вариант со вторым параметром, в котором можно задать шаблон (маску) интересующих папок или файлов. Например, Directory.GetFiles(@"d:\MyWork", "*.doc") вернет массив с именами Word-файлов в папке d:\MyWork.



Запись в текстовый файл

// оператор using автоматически закрывает StreamWriter

using (StreamWriter sw = new StreamWriter("TestFile.txt"))

{ // Добавить в файл некоторый текст

sw.Write("Это ");

sw.WriteLine("заголовок файла.");

// В могут быть записаны объекты

sw.WriteLine(DateTime.Now);

}

Чтение из текстового файла

try

{ // оператор using автоматически закрывает StreamReader

using (StreamReader sr = new StreamReader("TestFile.txt"))

{ String line;

// читать и показывть строки из файла пока не конец

while ((line = sr.ReadLine()) != null)

Console.WriteLine(line);

}

}

catch (Exception e)

{ Console.WriteLine("The file could not be read:");

Console.WriteLine(e.Message);

}

Добавление в текстовый файл

Так же как запись в файл, но объект StreamWriter создается:

FileInfo fi=new FileInfo("log.txt");

StreamWriter sw = FileInfo.AppendText();

либо

StreamWriter sw = new StreamWriter("TestFile.txt",true);

Перебор файлов каталога и определение размера файла

DirectoryInfo di = new DirectoryInfo("c:\\");

// получить ссылку на каждый файл каталога

FileInfo[] fiArr = di.GetFiles();

// Показать имена и размеры файлов

Console.WriteLine("Каталог {0} содержит файлы:", di.Name);

foreach (FileInfo f in fiArr)

Console.WriteLine("Размер {0} - {1} байт.",f.Name,f.Length);

Получение и изменение атрибутов файла

В примере методы GetAttributes и SetAttributes применяют к файлу атрибуты Archive и Hidden (применяется техника битовых масок).

string path = @"c:\temp\MyTest.txt";

// Создать файл, если он не существует

if (!File.Exists(path)) File.Create(path);

if ((File.GetAttributes(path) & FileAttributes.Hidden) ==

FileAttributes.Hidden)

{ // Показать файл

File.SetAttributes(path, FileAttributes.Archive);

Console.WriteLine("Файл {0} теперь виден.", path);

}

else

{ // Скрыть файл

File.SetAttributes(path, File.GetAttributes(path) |

FileAttributes.Hidden);

Console.WriteLine("Файл {0} скрыт.", path);

}

Чтение и запись в бинарный файл

private const string FILE_NAME = "Test.data";

public static void Main(String[] args)

{ // создать новый пустой файл.

if (File.Exists(FILE_NAME))

{ Console.WriteLine("{0} already exists!", FILE_NAME);

return;

}

FileStream fs=new FileStream(FILE_NAME,FileMode.CreateNew);

BinaryWriter w = new BinaryWriter(fs);

for (int i = 0; i < 11; i++) w.Write( (int) i);

w.Close();

fs.Close();

fs=new FileStream(FILE_NAME, FileMode.Open,FileAccess.Read);

BinaryReader r = new BinaryReader(fs);

for (int i=0; i<11; i++) Console.WriteLine(r.ReadInt32());

r.Close();

fs.Close();

}