Лекция 8 Обработка исключений Работа с файлами Обработка исключений Работа с файлами • Работа с файловой системой • Операции с потоками Возвращаемое значение • Не всегда возможно (конструкторы) • Не сразу проявляется • Непонятно, что конкретно произошло • Усложняет код Глобальная переменная • Не проходит в многопоточной среде Вызов определенной функции или завершение программы • Не проходит, если библиотеки независимы Обработка исключений Ошибке ставится в соответствие некоторый объект – исключение (exception) Объект-исключение должен иметь тип, который является потомком System.Exception При возникновении ошибочной ситуации генерируется (выбрасывается) исключение if(j < 0 || j > 3) throw new IndexOutOfRangeException(); Прерывается обычный ход выполнения операторов Если нет обработчика исключения, то приложение будет аварийно завешено. Блок обработки исключений имеет следующий вид: try { // Код, требующий корректного восстановления или очистки ресурсов } [catch [(exception_type1 [name_1])] { // Код восстановления, после возникновения исключения exception_type1 } … catch(exception_typeN [name_N]) { // Код восстановления, после возникновения исключения exception_typeN } ] [finally { // Код очисти ресурсов, после операций в блоке try // Этот код выполняется всегда, вне зависимости от наличия исключения } ] Блок try – обязательный Блоки catch и finally могут отсутствовать, однако хотя бы один из них должен присутствовать После генерации исключения рассматриваются блоки в порядке возрастания удаленности • Сначала смотрится статическая вложенность – вложенность блоков кода (внутри метода) • Затем смотрится динамическая вложенность – порядок вызовов в стеке В них просматриваются все обработчики (catch) сверху вниз. Если тип сгенерированного исключения – потомок типа, указанного в блоке catch, блок catch выбирается для обработки этого исключения Если найден блок catch, соответствующий исключению, то до выполнения кода в блоке catch выполняются все внутренние блоки finally (если имеются). После обработки исключения выполнение в каком-то блоке catch, все остальные блоки catch игнорируются. Блок finally выполняется всегда при выходе из блока обработки исключения, независимо от того возникло ли исключение или нет, обработано ли оно или нет. Блок finally выполнится всегда. Если исключение возникло и обработано, то выполнение продолжается с кода, следующего за обработавшим исключение try-catch-finally блоком (сначала выполнив блок finally) Если при возникновении исключения не находится подходящий блок catch, т.е. исключение остается не обработанным, то выполнение программы аварийно завершается. В C# 6 добавлена возможность фильтрации исключений try { // Код, требующий корректного восстановления или очистки ресурсов } [catch (Exception ex) when (condition) { // Код восстановления, после возникновения исключения Exception при условии выполнения выражения condition } … catch (Exception ex) // Код восстановления, после возникновения исключения Exception при условии, что не подошли предыдущие блоки catch (с их условиями) } ] [finally { // Код очисти ресурсов, после операций в блоке try // Этот код выполняется всегда, вне зависимости от наличия исключения } ] Способы восстановления после исключения try { // Читаем файл } catch (FileNotFoundException e) { throw e; } catch (FileLoadException) { throw; } catch (IOException e) { throw new MyException("Что-то не так при работе с файлом", e); } catch (Exception) { // Все ок. Не генерируем новое исключения } Еще раз сгенерировать то же исключение для передачи информации о нем коду, расположенному выше в стеке; Сгенерировать исключение другого типа для передачи дополнительной информации коду, расположенному выше в стеке; Позволить программному потоку выйти из блока catch естественным образом Базовый класс для всех исключений Поле Message – описание возникшего исключения Поле Source – ссылка на объект, сгенерировавший исключение, или на сборку, в которой возникло исключение Поле StackTrace – стек вызовов Поле InnerExeption – “предыдущее” исключение (при дальнейшей передачи исключения) При создании своего типа исключения необходимо наследоваться от типа System.Exeption Исключения Обработка исключений Работа с файлами • Работа с файловой системой • Операции с потоками Пространство имен System.IO Работа с файловой системой • Диски: DriveInfo • Папки: DirectoryInfo, Directory, FileSystemInfo • Файлы: File, FileInfo, FileSystemInfo Работа с путями • Path Наблюдение за изменениями в файловой системе • FileSystemWatcher Работа с потоками (чтение/запись файла) • Stream, производные от него и классы обертки Два способа работы: • File, Directory – статические классы • FileInfo, DirectoryInfo • Многие методы похожие FileSystemInfo • Базовый для FileInfo и DirectoryInfo DriveInfo • Информация о диске • Не связан с FileSystemInfo Экземпляр представляет один диск DriveInfo drive = new DriveInfo("c"); • DriveInfo drive = new DriveInfo(@"\\server\share"); • Информация о диске системы • • • • • • • • Name – имя диска DriveType – тип диска. Например: Fixed, CDRom IsReady – готов ли к использованию (например для CD Rom) VolumeLabel – метка тома DriveFormat – тип файловой системы TotalSize – размер диска AvailableFreeSpace – размер свободного места … Получение всех дисков • Статически метод GetDrives() DriveInfo[] drives = DriveInfo.GetDrives(); Абстрактный класс Базовый класс для DirectoryInfo и FileInfo Свойства файла/папки • Name – название файла, папки • FullName – полное имя, т.е. с полным путем • Extension - расширение • Exists() – существует ли такой файл / папка • CreationTime, LastAccessTime – время создания / последнего доступа (изменения) • Attributes - атрибуты (только на чтение) • … Экземпляр DirectoryInfo представляет одну папку файловой системы Наследник от FileSystemInfo Создание объекта (но не физической папки на диске) • DirectoryInfo windowsFolder = new DirectoryInfo(@"c:\Windows"); Получение информации о файлах и папках • • • GetDirectories() – получение подпапок. Возможен поиск по шаблону и поиск во всех дочерних папках DirectoryInfo[] folders = GetDirectories(); DirectoryInfo[] folders = di.GetDirectories(“my*”); DirectoryInfo[] folders = di.GetDirectories(“my*”, SearchOption.AllDirectories); GetFiles() – получение файлов FileInfo[] files = folder.GetFiles(); FileInfo[] files = folder.GetFiles("*.txt”, SearchOption.TopDirectoryOnly); GetFileSystemInfos() – получение всех файлов/папок Операции с папками • Create() – создание папки по текущему объекту DirectoryInfo FileSystemInfo[] fsi = folder.GetFileSystemInfos(); new DirectoryInfo(@"c:\MyDir").Create(); • CreateSubdirectory() - создание подпапки текущего каталога • Delete() – удаление текущей папки • MoveTo () – перемещение текущей папки Класс Directory имеет практически такие же методы, но в статическом исполнении • Directory.CreateDirectory(path); Экземпляр FileInfo представляет один файл файловой системы Наследник от FileSystemInfo Создание объекта (но не физического файла на диске) • FileInfo file = new FileInfo(“c:\\test.txt”); Свойства (в добавление к свойствам FileSystemInfo) Directory, DirectoryName – папка DirectoryInfo или полное имя папки (с полным путем) • IsReadOnly – файл только для чтения • Length – размер файла в байтах • Операции с файлами целиком Create(), CreateText() – создание файла • CopyTo() – копирование файла • Delete() – удаление текущего файла • MoveTo () – перемещение текущего файла • Операции с содержимым файла • Create(), CreateText(), OpenRead(), OpenText(), OpenWrite(), AppendText() Класс File имеет практически такие же методы, но в статическом исполнении • File.Delete(“c:\\myText.txt”); Статический класс Работа с путями • Комбинирование путей • GetInvalidPathChars, GetInvalidFileNameChars, IsPathRooted, HasExtension Работа с временными папками • Combine, ChangeExtension Проверки • GetPathRoot, GetDirectoryName, GetFullPath, GetFileName, GetFileNameWithoutExtension, GetExtension GetTempPath , GetTempFileName Не изменяет сами объекты, т.е. не переименовывает и не перемещает (исключение GetTempFileName - создаёт физически файл на диске) Не проверяет наличие объектов физически Проверяет валидность задания путей. Например проверяет допустимость символов Полезным может быть также статический класс Environment Слушает сообщения об изменениях в файловой системе и генерирует события Настройка: • Path – папка за изменениями которой нужно следить • Filter – задает фильтр объектов за которыми следить • NotifyFilter – задает за какими изменениями следить (Attributes, CreationTime, DirectoryName, FileName, LastAccess, LastWrite, Security, Size) • Начало слежения – установка свойства EnableRaisingEvents = true Генерирует события • Changed, Created, Deleted, Renamed Работа с файлами каталогами Класс Stream • Представляет файл, порт, область памяти и т.д. как поток байт • Абстрактный класс • Запись, чтение, перемещение указателя Реализация конкретных потоков в наследниках Классы обертки. …Reader / ….Writer • Чтение из / запись в поток • BinaryReader/BinaryWriter – бинарные чтение/запись • StreamReader/StreamWriter – текстовые чтение/запись • Понятие кодировки (Encoding) Возможности • CanRead – можно ли читать • CanWrite – можно ли писать • CanSeek – можно ли двигать курсор Чтение • int Read(byte[] buffer, int offset, int count) Запись • void Write(byte[] buffer, int offset, int count) Текущая позиция • long Position {get; set; } Перемещение • long Seek(long offset, SeekOrigin origin); Закрытие потока • void Close() • void Dispose() Stream FileStream поток из файла SqlFileStream MemoryStream поток из памяти NetworkStream поток из сети … PipeStream Поток данных из именованных каналов UnmanagedMemoryStream поток неуправляемых данных CryptoStream – предоставляет шифрование потока BufferedStream – добавляет буферизацию GZipStream, DeflateStream – предоставляют возможность сжатия потока BinaryReader/BinaryWriter, StreamReader/StreamWriter – предоставляют удобные способы чтения/записи в поток Классы обертки. Оборачивают конкретный поток Бинарный доступ к потоку Чтение/запись встроенных типов • ReadXXX() / WriteXXX() • XXX = Int32, Single, Double, … «Подсмотреть» следующий символ • PeekChar() Кодировка по умолчанию UTF8 Классы обертки. Оборачивают конкретный поток Текстовый доступ к потоку Чтение/запись строк • ReadLine() – чтение строки • ReadToEnd() – сразу весь файл • Write() – запись строки • WriteLine() – запись строки + символ новой строки Параметры аналогичны функциям консоли System.Text.Encoding Определяет преобразование • char (Unicode) <=> byte [] GetEncoding() получает кодировку по Encoding • Имени: GetEncoding(“windows-1251”) • Номеру: GetEncoding(1251) Использование: • StreamReader sr = new StreamReader(stream, Encoding.Unicode); TextReader/TextWriter – базовые классы • StreamReader/StreamWriter – из потока • StringReader/StringWriter – из строки Стандартные потоки • Console.In – поток ввода • Console.Out – поток вывода • Console.Error – поток ошибок Текстовый ввод-вывод