РАБОТА С КАТАЛОГАМИ И ФАЙЛАМИ
В пространстве имен System. IO есть четыре класса, предназначенные для работы с физическими файлами и структурой каталогов на дис-
ке: Directory, File, Directorylnfo и Filelnfo. С их помощью можно выполнять создание, удаление, перемещение файлов и каталогов, а также получение их свойств.
Классы Directory и File реализуют свои функции через статические методы. Directorylnfo и Filelnfo обладают схожими возможностями, но они реализуются путем создания объектов соответствующих классов. Классы
Directorylnfo и Filelnfo происходят от абстрактного класса FileSystemlnfo,
который снабжает их базовыми свойствами, описанными в табл.1.
Таблица 1. Свойства класса FileSystemlnfo
Свойство |
Описание |
Attributes |
Получить или установить атрибуты для данного |
|
объекта файловой системы. Для этого свойства ис- |
|
пользуются значения перечисления FileAttributes |
CreationTime |
Получить или установить время создания объ- |
|
екта файловой системы |
Exists |
Определить, существует ли данный объект |
|
файловой системы |
Extension |
Получить расширение файла |
Full Name |
Возвратить имя файла или каталога с указани- |
|
ем полного пути |
LastAccessTime |
Получить или установить время последнего об- |
|
ращения к объекту файловой системы |
LastWriteTime |
Получить или установить время последнего |
|
внесения изменении и обьект файловой системы |
Name |
Возвратить имя файла. Это свойство доступно |
|
только для чтения. Для каталогов возвращает имя |
|
последнего каталога в иерархии, если это возмож- |
|
но. Если пет, возвращает полностью определенное |
|
имя |
Класс Directory Info содержит элементы, позволяющие выполнять необходимые действия с каталогами файловой системы. Эти элементы перечислены в табл. 2.
Таблица 2. Элементы класса Directorylnfo
Элемент |
Описание |
Create, |
Создать каталог или подкаталог по указанному |
CreateSubDIrectory |
пути в файловой системе |
Delete |
Удалить катапог со всем его содержимым |
GetDirectories |
Возвратить массив строк, представляющих все |
|
подкаталоги |
GetFiIes |
Получить файлы в текущем каталоге в виде |
|
массива объектов |
класса Filelnfo |
|
MoveTo |
Переместить каталог и все его содержимое на |
|
новый адрес в файловой системе |
Parent |
Возвратить родительский каталог |
В листинге 1 приведен пример, в котором создаются два каталога, выводится информация о них и предпринимается попытка удаления каталога.
Листинг 1. Использование класса Directorylnfo
using System; using System.IO;
namespace ConsoleApplication1
{
class Classl
{
static void DirInfo(DirectoryInfo di)
{
// Вывод информации о каталоге
Console.WriteLine("===== Directory Info =====");
Console.WriteLine("FullName: " + di.FullName); Console.WriteLine("Name: " + di.Name); Console.WriteLine("Parent: " + di.Parent); Console.WriteLine("Creation: " + di.CreationTime); Console.WriteLine("Attributes: " + di.Attributes); Console.WriteLine("Root: " + di.Root); Console.WriteLine("=========================");
}
static void Main()
{
DirectoryInfo di1 = new DirectoryInfo(@"c:\MyDir"); DirectoryInfo di2 = new DirectoryInfo(@"c-\MyDir\temp"); try
{
//Создать каталоги di1.Create(); di2.Create();
//Вывести информацию о каталогах
DirInfo(di1);
DirInfo(di2);
//Попытаться удалить каталог
Console.WriteLine("Попытка удалить {0}.", di1.Name); di1.Delete();
}
catch (Exception)
{
Console.WriteLine("Попытка не удалась ");
}
}
}
}
Результат работы программы:
=====Directory Info =====
Full Name: c:\MyDir Name: MyDir Parent:
Creation: 30.04.2006 17:14:44 Attributes: Directory
Root: c:\
=====Directory Info =====
Full Name: c:\MyDir\temp Name: temp
Parent: MyDir
Creation: 30.04.2006 17:14:44 Attributes: Directory
Root: c:\
Попытка удалить MyDir. Попытка не удалась
Каталог не пуст, поэтому попытка его удаления не удалась. Впрочем, если использовать перегруженный вариант метода Delete с одним параметром, задающим режим удаления, можно удалить и непустой каталог:
di1.Delete( true);
Обратите внимание на свойство Attributes. Некоторые его возможные значения, заданные в перечислении FileAttributes приведены в табл. 3.
Таблица 3. Некоторые значения перечисления FileAttributes
Значение |
Описание |
Archi ve |
Используется приложениями при выполнении ре- |
|
зервного копирования, а в некоторых случаях - при |
|
удалении старых файлов |
Compressed |
Файл является сжатым |
Di rectory |
Объект файловой системы является каталогом |
Encrypted |
Файл является зашифрованным |
Hidden |
Файл является скрытым |
Normal |
Файл находится в обычном состоянии, и для него ус- |
|
тановлены любые другие атрибуты. Этот атрибут не мо- |
|
жет использоваться с другими атрибутами |
OffIine |
Файл, расположенный на сервере, кэширован в хра- |
|
нилище на клиентском компьютере. Возможно, что дан- |
|
ные этого файла уже устарели |
ReadOnly |
Файл доступен только для чтения |
System |
Файл является системным |
Листинг 2 демонстрирует использование класса Filelnfo для копирования всех файлов с расширением jpg из каталога d:\foto в каталог d:\temp. Метод Exists позволяет проверить, существует ли исходный каталог.
Листинг 2. Копирование файлов using System;
253
using System.IO;
namespace ConsoleApplicationi
{
class Classl
{
static void Main()
{
try
{
string DestName = @"d:\temp\";
DirectoryInfo dest = new DirectoryInfo(DestName); dest.Create(); // создание целевого каталога
DirectoryInfo dir = new DirectoryInfo(@"d:\foto");
if (!dir.Exists) // проверка существования каталога
{
Console.WriteLine("Каталог " + dir.Name + " не существует"); return;
}
FileInfo[] files = dir.GetFiles("*.jpg"); //список файлов foreach (FileInfo f in files)
f.CopyTo(dest + f.Name); // копирование файлов
Console.WriteLine("Скопировано " + files.Length + " jpg-файлов");
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
}
}
}
Использование классов File и Directory аналогично, за исключением того, что их методы являются статическими и, следовательно, не требуют создания объектов.
Класс FileStream реализует эти элементы для работы с дисковыми файлами. Для определения режимов работы с файлом используются стандартные перечисления FileMode, FileAccess и FileShare. Значения этих перечислений приведены в табл. 11.2—11.4.
В листинге 3 представлен пример работы с файлом. В примере демонстрируются чтение и запись одного байта и массива байтов, а также позиционирование в потоке.
Листинг 3. Пример использования потока байтов
using System; using System.IO; class Class1
{
static void Main()
{
FileStream f = new FileStream("test.txt",
FileMode.Create, FileAccess.ReadWrite);
f.WriteByte(100); |
// в начало файла записывается число 100 |
byte[] x = new byte[10]; |
|
for (byte i = 0; i < 10; ++i) |
|
{ |
|
|
x[i] = (byte)(10 - i); |
|
f.WriteByte(i); |
// записывается 10 чисел от 0 до 9 |
} |
|
|
f.Write(x, 0, 5); |
|
// записывается 5 элементов массива |
byte[] у = new byte[20]; |
|
f.Seek(0, SeekOrigin.Begin); |
// текущий указатель - на начало |
f.Read(у, 0, 20); |
|
// чтение из файла в массив |
foreach (byte elem in у) Console.Write(" " + elem);
Console.WriteLine(); |
|
|
f.Seek(5, SeekOrigin.Begin); |
// текущий указатель - на 5-й элемент |
int a = f.ReadByte(); |
|
// чтение 5-го элемента |
Console.WriteLine(a); |
|
|
a = f.ReadByte(); |
// чтение 6-го элемента |
Console.WriteLine(a); |
|
|
Console.WriteLine("Текущая позиция в потоке" + f.Position); f.Close();
}
}
В листинге 4 создается текстовый файл, в который записываются две строки. Вторая строка формируется из преобразованных численных значений переменных и поясняющего текста. Содержимое файла можно посмотреть в любом текстовом редакторе. Файл создается в том же каталоге, куда среда записывает исполняемый файл. По умолчанию это каталог
...\ConsoleApplication1\bin\Debug.
Листинг 4. Вывод в текстовый файл
using System; using System.IO; class Class2
{
static void Main()
{
try
{
StreamWriter f = new StreamWriter("text.txt"); f.WriteLine("Вывод в текстовый файл:"); double a = 12.234;
int b = 29;
f.WriteLine(" a = {0.6:C} b = {1.2:X}", a, b); f.Close();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message); return;
}
}
}
В листинге 5 файл, созданный в предыдущем листинге, выводится на экран.
Листинг 5. Чтение текстового файла
using System; using System.IO; class Class4
{
static void Main()
{
try
{
StreamReader f = new StreamReader("text.txt"); string s = f.ReadToEnd(); Console.WriteLine(s);
f.Close();
}
catch (FileNotFoundException e)
{
Console.WriteLine(e.Message);
Console.WriteLine(" Проверьте правильность имени файла! "); return;
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message); return;
}
}
}
В этой программе весь файл считывается за один прием с помощью метода ReadToEnd(). Чаще возникает необходимость считывать файл построчно, такой пример приведен в листинге 6. Каждая строка при выводе предваряется номером.
Листинг 6. Построчное чтение текстового файла
using System; using System.IO; class Class5
{
static void Main()
{
try
{
StreamReader f = new StreamReader("text.txt"); string s;
long i = 0;
while ((s = f.ReadLine()) != null) Console.WriteLine("{0}: {1}", ++i, s);
f.Close();
}
catch (FileNotFoundException e)
{
Console.WriteLine(e.Message); Console.WriteLine("Проверьте правильность имени файла!"); return;
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message); return;
}
}
}
Пример преобразования чисел, содержащихся в текстовом файле, в их внутреннюю форму представления приведен в листинге 7. В программе вычисляется сумма чисел в каждой строке.
На содержимое файла накладываются весьма строгие ограничения: числа должны быть разделены ровно одним пробелом, после последнего числа в строке пробела быть не должно, файл не должен заканчиваться символом перевода строки. Методы разбиения строки и преобразования в целочисленное представление рассматривались ранее.
Листинг 7. Преобразования строк в числа
using System; using System.IO; class Class6
{
static void Main()
{
try
{
StreamReader f = new StreamReader("numbers.txt"); string s;
const int n = 20;
257
int[] a = new int[n]; string[] buf;
while ((s = f.ReadLine()) != null)
{
buf = s.Split(' '); long sum = 0;
for (int i = 0; i < buf.Length; ++i)
{
a[i] = Convert.ToInt32(buf[i]); sum += a[i];
}
Console.WriteLine("{0} сумма: {1}", s, sum);
}
f.Close();
}
catch (FileNotFoundException e)
{
Console.WriteLine(e.Message);
Console.WriteLine(" Проверьте правильность имени файла!"); return;
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message); return;
}
}
}
Результат работы программы: 12 4 сумма: 7 3 44 -3 6 сумма: 50 8 1 1 сумма: 10
В листинге 8 приведен пример формирования двоичного файла. В файл записывается последовательность вещественных чисел, а затем для демонстрации произвольного доступа третье число заменяется чис-
лом 8888.
Листинг 8. Формирование двоичного файла
using System; using System.IO; class Class7
{
static void Main()
{
try
{
BinaryWriter fout = new BinaryWriter(
new FileStream(@"D:\C#\binary", FileMode.Create));
double d = 0;
while (d < 4)
{
fout.Write(d); d += 0.33;
}
fout.Seek(16, SeekOrigin.Begin); // второй элемент файла fout.Write(8888d);
fout.Close();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message); return;
}
}
}
При создании двоичного потока в него передается объект базового потока. При установке указателя текущей позиции в файле учитывается длина каждого значения типа doubl e — 8 байт.
Попытка просмотра сформированного программой файла в текстовом редакторе весьма медитативная, но не информативная, поэтому в листинге 9 приводится программа, которая с помощью экземпляра BinaryReader считывает содержимое файла в массив вещественных чисел, а затем выводит этот массив на экран. При чтении принимается во внимание тот факт, что метод ReadDouble при обнаружении конца файла генерирует исключение EndOfStreamException. Поскольку в данном случае это не ошибка, тело обработчика исключений пустое.
Листинг 9. Считывание двоичного файла
using System; using System.IO; class Class8
{
static void Main()
{
try
{
FileStream f = new FileStream(@"D:\C#\binary", FileMode.Open);
BinaryReader fin = new BinaryReader(f);
long n = f.Length / 8; // количество чисел в файле double[] x = new double[n];
long i = 0;
try |
|
{ |
|
while (true) x[i++] = fin.ReadDouble(); |
// чтение |
} |
|
catch (EndOfStreamException e) { } |
|
foreach (double d in x) Console.Write(" " + d); // вывод
fin.Close();
f.Close();
}
catch (FileNotFoundException e)
{
Console.WriteLine(e.Message); Console.WriteLine("Проверьте правильность имени файла!"); return;
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message); return;
}
}
}
Результат работы программы:
0 0,33 8888 0,99 1,32 1,65 1,98 2,31 2,64 2,97 3,3 3,63 3.96
260