Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
68
Добавлен:
09.05.2015
Размер:
265.04 Кб
Скачать

Урок 9: Обработка исключений.

Основная цель урока.

1.Изучить основные принципы перехвата и обработки исключений.

2.Познакомиться с некоторыми операции работы с файловой системой.

.

Краткая справка.

Обработка исключений.

Исключительная ситуация (или исключение) — это ошибка, которая возникает во время выполнения программы. В C# реализован механизм, позволяющий перехватывать такие исключительные ситуации. Рассмотрим пример – программа запрашивает у пользователя ввод некоторого числа из консоли, но не факт, что пользователь введёт именно число и следующий код может привести к ошибке(исключению).

Console.WriteLine("Введите число");

int n = Convert.ToInt32(Console.ReadLine());

Если пользователь введёт нечисловое значение, исключение в вышеприведённом коде сгенерирует метод ToInt32. Например, пользователь вводит консоли строку «56 ф», эта строка не может быть преобразована в число с помощью метода ToInt32 и будет выброшено исключение System.FormatException. (Exception –

с англ. « исключение»).

Чтобы узнать какие исключения может генерировать тот или иной метод,

достаточно просто подвести курсор к соответствующему методу.

Видно, что метод ToInt32 может генерировать 2 разных исключения –

System.FormatException и System.OverflowException.

Исключение System.FormatException выбрасывается, когда была передана строка в неверном формате, например: “сто”, “50ъ”, “+-200” или “абсде”.

Т.е. код Convert.ToInt32(“двести”) выбросит исключение System.FormatException.

Исключение System.OverflowException выбрасывается, когда было передано слишком большое число (Overflow – с англ. « переполнение»).

Т.е. код Convert.ToInt32(“648476438746”) выбросит исключение System.

OverflowException, т.к. строка несмотря на то, что строка “648476438746“ имеет числовой формат – такое больше число не может быть представлено типом int.

Для того чтобы отловить исключение соответствующего типа и предотвратить появление ошибки в программе нужно воспользоваться конструкцией try..catch.(try – c англ. « пробовать», catch – с англ. « ловить»).

Console.WriteLine("Введите число"); try

{

int n = Convert.ToInt32(Console.ReadLine()); }catch(FormatException ex)

{

Console.WriteLine("Неверный формат числа!");

}

Вслучае ввода нечислового значения при выполнении вышеприведённого кода

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

Console.WriteLine("Введите число"); try

{

int n = Convert.ToInt32(Console.ReadLine()); }catch(FormatException ex)

{

Console.WriteLine("Неверный формат числа!"); }catch(OverflowException ex)

{

Console.WriteLine("Введённое число не умещается в диапазоне"); Console.WriteLine("от {0} до {1}",int.MinValue,int.MaxValue);

}

Если необходимо отловить все исключения, можно воспользоваться базовым

классом для всех исключений – классом Exception. В этом случае отлавливаются

исключения всех видов, однако нельзя узнать из-за чего именно возникло

исключение.

Console.WriteLine("Введите число"); try

{

int n = Convert.ToInt32(Console.ReadLine()); }catch(Exception ex)

{

Console.WriteLine("Ошибка!"); Console.WriteLine("Информация об ошибке: {0}",ex.Message);

}

Выбрасывание исключений.

Общий синтаксис для выбрасывания (т.е. генерации) исключения выглядит

следующим образом:

Throw НовыйЭкземпярКлассаException;

Пример:

Console.WriteLine("Введите чётное число"); try

{

int n = Convert.ToInt32(Console.ReadLine());

if (n % 2 != 0) throw new Exception("Вы ввели НЕЧЁТНОЕ число!"); Console.WriteLine("Спасибо!");

}

catch (Exception ex)

{

Console.WriteLine("Ошибка: {0}", ex.Message);

}

Результаты работы программы:

Пользователь ввёл

Результат

 

 

3,,5

Ошибка: Входная строка имела неверный формат

 

 

35

Ошибка: Вы ввели НЕЧЁТНОЕ число!

 

 

36

Спасибо!

 

 

Учебное задание 2.1.

Создать программу упрощающую процесс очистки жесткого диска от « мусора» –

тяжелых и неиспользуемых файлов. Программа должна уметь сканировать определённую директорию (или диск) на наличие больших файлов (более 300Мб)

последнее обращение к которым было более 90 дней назад. Программа должна игнорировать системные файлы.

Технология выполнения учебного задания 2.1.

Шаг 1. Создайте новый проект консольного приложения, назовите его Lab23.

Шаг 2. .Для того чтобы использовать классы Directory, File, Path и другие без явного указания принадлежности к пространству имён System.IO укажем, что он будет использоваться по умолчанию (листинг 1).

using System;

using System.Collections.Generic; using System.Text;

using System.IO; namespace Lab23

{

class Program

Листинг 1

Шаг 3. С помощью метода Directory.GetFiles можно получить список всех файлов в заданной директории. Получим список всех файлов на диске “C”. В

дальнейшем можно усовершенствовать программу так, чтобы пользователь сам мог указывать директорию для сканирования.

Для определения размера файла будем использовать класс FileInfo (см листин

2).

static void Main(string[] args)

{

string[] files;

//получаем список файлов на диске C files = Directory.GetFiles(@"C:\");

//Перебираем все файлы...

for (int i = 0; i < files.Length; i++)

{

//Для определения размера файла и других его характеристик //используем класс FileInfo

FileInfo info = new FileInfo(files[i]); //если размер файла больше 300 МБ...

if (info.Length > 300 * 1024 * 1024)

{

Console.WriteLine("{0} (размер {1} мегабайт)", files[i], info.Length/1024/1024);

}

}

Console.ReadKey();

}

Листинг 2

Шаг 4. Запустите программу, нажав клавишу F5, убедитесь, что программа

работает.

Шаг 5. Программа выводит список всех файлов на диске C, размер которых превышает 300Мб, программа перечисляет все файлы в корне диска (даже скрытые и системные). Системные файлы удалять небезопасно, даже если к ним не было обращения в течении 90 дней – исключим эти файлы из результатов поиска.

Для этого воспользуемся свойством Attributes класса FileInfo. Свойство Attributes

имеет тип перечисления FileAttributes, само перечисление содержит следующие элементы (атрибуты).

public enum FileAttributes

{

ReadOnly = 1,

Hidden = 2,

System = 4, Directory = 16, Archive = 32, Device = 64, Normal = 128, Temporary = 256, SparseFile = 512,

ReparsePoint = 1024, Compressed = 2048, Offline = 4096, NotContentIndexed = 8192, Encrypted = 16384,

}

Обратите внимание, что каждому элементу в перечислении соответствуют не числа по порядку, а степени двойки (21, 22, 23, 24 и.т.д.). Это сделано для того, чтобы файл мог содержать не один, а несколько атрибутов. Если представить все эти числа в двоичной системе, получим:

ReadOnly

00000000000000000000000000000001

1

 

 

 

Hidden

00000000000000000000000000000010

2

 

 

 

System

00000000000000000000000000000100

4

 

 

 

Directory

00000000000000000000000000001000

8

 

 

 

Archive

00000000000000000000000000010000

16

 

 

 

Если файл имеет несколько атрибутов, например: архивный + только для чтения

+ скрытый, мы можем объединить каждый из этих атрибутов с помощью поразрядного ИЛИ.

1 ИЛИ 2 ИЛИ 16 = 19

В двоичной системе это будет выглядеть следующим образом:

00000000000000000000000000010011

Т.е. в двоичном представлении у числа 19 установлены только те биты, которые отвечают за соответствующие атрибуты.

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

FileInfo info = new FileInfo(@"C:\1.txt");

if ((info.Attributes & FileAttributes.System) != 0)

{

Console.WriteLine("У файла установлен атрибут Системный");

}

Чтобы узнать дату последнего обращения к файлу нужно воспользоваться свойством LastAccessTime класса FileInfo.

Добавим функционал игнорирующий системные файлы и учитывающий файлы последнее обращение к которым было более 90 дней назад (листинг 3).

for (int i = 0; i < files.Length; i++)

{

//Для определения размера файла и других его характеристик //используем класс FileInfo

FileInfo info = new FileInfo(files[i]);

//если файл не является системным И //с момента последнего обращения к файлу прошло более 90 дней И //размер файла более 300 мегабайт

if (((info.Attributes & FileAttributes.System) == 0) && ((DateTime.Nowinfo.LastAccessTime).Days>90) && (info.Length > 300 * 1024 * 1024))

{

//Выводи информацию о файле в консоль

string name = Path.GetFileName(files[i]); Console.WriteLine("{0} (размер {1} мегабайт)", name,

info.Length/1024/1024);

}

}

Листинг 3

Шаг 6. На данный момент программа перечисляет все файлы только в корне диска C, без учёта вложенных директорий. Для того, чтобы программа перечисляла все файлы с учётом вложенных поддиректорий удобно будет воспользоваться механизмом рекурсивных вызовов.

Идея в следующем, создаётся некоторая функция (например, EnumDir)

принимающая 1 аргумент – директорию, которую надо просканировать.

Внутри функции прописан следующий функционал:

1.Получаем список файлов в указанной директории (заданной аргументом)

2.Определяем размер файла, дату последнего обращения, принимаем решение выводить файл в консоль или нет.

3.Получаем список всех директорий в указанной директории (заданной аргументом)

4.В цикле для каждой директории из списка вызываем функцию EnumDir

ВС# функция может вызвать сама себя. Этот процесс называется рекурсией, а

функция, который вызывает себя, называют рекурсивной.

Вобщем случае рекурсия — это процесс определения чего-либо с использованием самого себя.

Вынесем реализованный функционал в отдельный метод, назовём его

EnumDir(см листинг 4).

static void Main(string[] args)

{

//вызываем функцию EnumDir EnumDir(@"C:\"); Console.ReadKey();

}

static void EnumDir(string dir) {//начало функции EnumDir

string[] files;

//получаем список файлов для директории dir files = Directory.GetFiles(dir); //Перебираем все файлы...

for (int i = 0; i < files.Length; i++)

{

//Для определения размера файла и других его характеристик //используем класс FileInfo

FileInfo info = new FileInfo(files[i]); //если файл не является системным И

//с момента последнего обращения к файлу прошло более 90 дней И

//размер файла более 300 мегабайт

if (((info.Attributes & FileAttributes.System) == 0) && ((DateTime.Now - info.LastAccessTime).Days > 90) && (info.Length > 300 * 1024 * 1024))

{

//Выводи информацию о файле в консоль string name = Path.GetFileName(files[i]);

Console.WriteLine("{0} (размер {1} мегабайт)", name, info.Length / 1024 / 1024);

}

}

//получаем список поддиректорий для директории dir string[] dirs = Directory.GetDirectories(dir);

//для каждой поддиректории вызываем функцию EnumDir (рекурсия) for (int i = 0; i < dirs.Length; i++)

{

EnumDir(dirs[i]);

}

}//конец функции EnumDir

Листинг 4

Шаг 7. Запустите программу, нажав клавишу F5. При запуске программы с большой долей вероятности будет выдано исключение:

System.UnauthorizedAccessException « Отказано в доступе по пути "C:\XXX\XXX»

На диске существуют директории для которых у пользователя нет прав на просмотр содержимого, это порождает такое исключение. Чтобы избежать этого можно воспользоваться конструкцией try..catch (см краткую справку). Код реализующий данный функционал приведён в листинге 5.

static void EnumDir(string dir) {//начало функции EnumDir

string[] files;

//пытаемся получить список файлов для директории dir try

{

files = Directory.GetFiles(dir); }catch(Exception e)

{

//если возникло исключение пишем информацию об ошибке Console.WriteLine("Невозможно получить список файлов из {0}",

dir); //и выходим из функции return;

}

//Перебираем все файлы...

for (int i = 0; i < files.Length; i++)

Листинг 5

Шаг 8. Запустите программу, нажав клавишу F5. Убедитесь, что программа

работает.

Контрольные вопросы.

1.Каким образом можно скопировать файл из одной директории в другую ?

2.Каким образом можно проверить, что файл с заданным именем существует на диске?

3.Каким образом можно получить список файлов для заданной директории ?

4.Что такое исключительная ситуация ?

5.Каким образом можно обрабатывать исключительные ситуации ?

6.Что такое рекурсия ?

Самостоятельное задание 2.1.

Напишите программу, которая сканирует некоторую папку (задаётся

пользователем) с учётом поддиректорий, все хранящиеся в ней файлы сортируются

по следующему принципу:

1.Все видеофайлы помещаются в папку Видео (видеофайлами считать файлы имеющие расширение avi, wmv, mkv, mp4)

2.Все аудиофайлы помещаются в папку Аудио (аудиофайлами считать файлы имеющие расширение wav, mp3, mid, wma, flac)

3.Все графические файлы помещаются в папку Изображения (графическими

файлами считать файлы расширение jpg, jpeg, png, gif, bmp)

Директории Видео, Аудио и Изображения должны создаваться в папке, указанной пользователем для сканирования. Для создания директории использовать метод

Directory.CreateDirectory.

Для определения расширения файла воспользоваться методом Path.GetExtension.

Для перемещения файлов используется метод File.Move.

Соседние файлы в папке Методичка (1 сем)