VBA: два способа узнать, открыт ли файл
У меня есть два метода, которые, я чувствую, должны сказать, открыт файл или нет.
Способ 1 (ошибка: индекс вне диапазона):
If Not Workbooks(filename) Is Nothing Then
Workbooks.Open (filename)
End If
Способ 2:
If Not IsWorkbookOpen(filename) Then
Workbooks.Open (filename)
End If
куда IsWorkbookOpen()
является:
Private Function IsWorkbookOpen(wbname) As Boolean
Dim wBook As Workbook
Set wBook = Nothing
On Error Resume Next
Set wBook = Workbooks(wbname)
If wBook Is Nothing Then
IsWorkbookOpen = False
Else: IsWorkbookOpen = True
End If
End Function
Помимо On Error Resume Next
Метод 1 выглядит почти так же, как метод 2.
Может ли кто-нибудь объяснить, почему метод 1 дает ошибку, которую он делает?
Спасибо.
3 ответа
Они оба дают нижний индекс ошибки вне диапазона. Но в методе 2 вы подавляете эту ошибку с помощью On Error Resume Next
,
Sub SeeError()
On Error Resume Next
Debug.Print Workbooks("DoesNotExist").Name
Debug.Print Err.Description
End Sub
Это печатает "Subscript Out of Range" в "Немедленном окне". Оператор On Error не останавливает возникновение ошибки, он просто обрабатывает ее. Метод 1 не обрабатывает ошибки, поэтому действует обработка ошибок по умолчанию (остановить выполнение и сообщить об ошибке).
VBA пытается оценить все части, прежде чем он оценивает условный оператор. Так что, если у меня есть переменная myvar = "xyz"
и попробуйте запустить следующие строки...
If IsNumeric(myvar) And Round(myvar, 1) = 3 Then
'you will get an error before the IF is evaluated
End If
она не будет работать. VBA оценит IsNumeric(myvar)
хорошо, тогда попробуй оценить Round(myvar, 1) = 3
и получить ошибку, прежде чем он проверит все условия. Поэтому VBA сообщит вам об ошибке до того, как выполнит AND
оператор. Если бы VBA имел оценку короткого замыкания, он работал бы нормально, так как первая часть была бы оценена как ложная.
Но следующее будет работать
If IsNumeric(myvar) Then
If Round(myvar, 1) = 3 Then
'second IF statement is not touched since first IF statement evaluates to false
End If
End If
Это работает, потому что IsNumeric(myvar)
оценивается как ложное и поэтому пропускает вложенный оператор.
Так что ошибка это бросает на Workbooks(filename)
просто выдаст ошибку, если вы не скажете, чтобы она продолжалась дальше. Таким образом, метод, который я использую
On Error Resume Next
Set wb = Workbooks(file)
If wb Is Nothing Then
Set wb = Application.Workbooks.Open(dir & "\" & file, ReadOnly:=True)
End If
On Error GoTo 0
Отредактировано, чтобы дать более подробную информацию и правильно отразить, что второй пример не будет оценен, а также предоставить полезное решение для рассматриваемого вопроса.
Workbooks(filename)
пытается получить элемент с идентификатором (или "индексом") filename
из коллекции Workbooks
, Если в коллекции нет такого элемента, вы получите ошибку "Subscript out of range". (Итак, в двух словах: этот код не будет работать всякий раз, когда файл не открыт. Вы, вероятно, не хотите этого.)
Однако знание о том, что такой доступ потерпит неудачу, если файл не открыт, т.е. возникла ошибка, используется во втором методе. Код пытается получить элемент с идентификатором filename
от Workbooks
коллекция и назначить ее переменной wBook
, Если это не удается, значение переменной wBook
остановимся Nothing
, Если это успешно, переменная wBook
будет содержать ссылку на соответствующий объект Workbook.