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.

Другие вопросы по тегам