Обработка ошибок Исключения Оператор Try
Здесь нас интересуют только исключения, то есть ошибки выполнения (см. 1.3.8).
Суть проблемы. Многие функции, процедуры и вообще операторы, которыми вы пользуетесь в VB, вовсе не обязаны при любых обстоятельствах успешно завершать свою работу. Например, пусть вы запустили процедуру, в которой встречается оператор копирования файла 13.txt из папки c:\temp в папку c:\temp\222:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim a = 3
File.Copy("c:\temp\13.txt", "c:\temp\222\13.txt")
MsgBox("Ура! Файл скопирован!")
Dim b = 8
End Sub
но забыли предварительно создать файл 13.txt в папке c:\temp. Метод File.Copy не может выполнить свою работу, VB выдает сообщение об ошибке и работа приложения прерывается. Говорят, что было выброшено исключение. Не в том смысле, что выброшено в мусорное ведро, а в том смысле, как выбрасывают лозунги, флаги, то есть выброшено из небытия в зону нашего внимания. Рядовой пользователь, работающий с вашим приложением, окажется в затруднительном положении. Он совсем не обязан разбираться в английском тексте сообщения, и если он даже догадается, в чем дело, и создаст нужный файл, все равно приложение надо будет запускать заново, так как оно прервано. Вы, как программист, должны учитывать, что с вашим приложением будут работать рядовые пользователи, причем даже не очень квалифицированные. Поэтому при программировании вы должны предугадать все возможные неправильные действия пользователя (за исключением выбрасывания компьютера в форточку), чтобы при таких действиях приложение, во-первых, не прерывалось, а во-вторых – выдавало вразумительное сообщение на русском языке и советы по выходу из затруднительной ситуации.
Кое-что в этом направлении мы уже делали в 7.7, предохраняя калькулятор от арифметических действий над текстом и от деления на ноль. Но там мы именно предохраняли проект от ошибок, не допускали их возникновения, не разрешали арифметических действий над текстом и деления на ноль. Здесь же мы будем рассматривать ситуации, когда о недопущении ошибки мы не смогли позаботиться, ошибка поэтому все же произошла и теперь нам нужно ее «обезвредить».
Таким образом, одна из целей достигнута – программа не прерывается. Поговорим о второй цели – о выдаче вразумительного сообщения с советами.
Вся обработка ошибки состоит в выполнении операторов, написанных нами между строками Catch и End Try. У меня обработка пока очень простая и не очень полезная. Сначала, как видите, выполняется оператор Beep(), чтобы привлечь внимание пользователя. Затем выдается сообщение об ошибке. Суть сообщения определяется свойством Message объекта ex. Если ошибка произошла из-за отсутствия файла 13.txt в папке c:\temp, то сообщение будет таким:
Рис. 19.2
Как видите, сообщение Message выводится на английском языке. Переводится оно так: «Не могла найти файл c:\temp\13.txt». Если вы знаете английский, то понимаете, в чем дело, нажимаете ОК, создаете файл, затем снова запускаете процедуру. Все в порядке.
Выводим собственные сообщения (по-русски). Ну а как насчет русского языка? Действительно, нас никто не заставляет выводить сообщение ex.Message. Давайте вместо
MsgBox("При выполнении процедуры произошла следующая ошибка: " & ex.Message)
напишем по-русски так:
MsgBox("Ошибка: файл c:\temp\13.txt не существует. Создайте его и снова нажмите на кнопку.")
Вот это другое дело! Никакого английского и все понятно. И все бы хорошо, но тут нас ждет опасность. Дело в том, что при выполнении копирования файла причин у ошибки может быть несколько. Пусть, например, в папке 222 файл 13.txt уже есть, а вы снова запускаете процедуру копирования. Если вы заметили, наша File.Copy не допускает записи скопированного файла на место старого. Следовательно возникнет ошибка. Вот какое сообщение выдаст наш англоязычный MsgBox:
Рис. 19.3
что означает: «Файл c:\temp\222\13.txt уже существует». Новый же MsgBox обманет нас, на все случаи жизни заявляя, что он не может найти файл c:\temp\13.txt.
При моей простой обработке и не могло быть иначе. Чтобы справиться с ситуацией, усложним обработку ошибки. Вот что теперь мы поместим в процедуру между строками Catch и End Try:
Catch ex As Exception
Beep()
If Not File.Exists("c:\temp\13.txt") Then
MsgBox("Ошибка: файл c:\temp\13.txt не существует. Создайте его и снова нажмите на кнопку.")
ElseIf File.Exists("c:\temp\222\13.txt") Then
MsgBox("Ошибка: файл c:\temp\\222\13.txt уже существует. Сотрите его и снова нажмите на кнопку.")
Else
MsgBox("Произошла непонятная ошибка при копировании")
End If
End Try
Здесь мы использовали метод Exists класса File, который принимает значение True, если файл существует, и False – если нет. Поскольку кроме двух разобранных ошибок мыслимы и другие, неведомые для нас, я все же включил в оператор If третью ветвь, в которой честно сознаюсь в своей некомпетентности.
Заключение. Здесь я описал обработку исключений только в самых общих чертах. Также я не останавливался на подробностях грамматики и работы оператора Try. Вы должны знать, что не все ошибки отлавливаются так просто. Например, если вы обратитесь к дискете, но забудете вставить ее в дисковод, компьютер напомнит вам об этом сообщением на английском языке и вам будет трудно избавиться от английского.