Работа с несколькими книгами и внешними данными

До сих пор весь код в этой главе работал внутри одной книги. Но в реальной работе данные часто приходят снаружи: коллега прислал отдельный файл Excel, бухгалтерия выгрузила таблицу в CSV, часть цифр лежит в базе Access. Эта тема — про то, как код дотягивается за пределы своей книги: открывает и закрывает другие файлы Excel, читает и пишет обычные текстовые файлы, и в общих чертах — как достучаться до внешней базы данных.

К концу темы ты сможешь:
— открыть, переключиться на другую и закрыть книгу Excel из кода;
— объяснить разницу между ThisWorkbook и ActiveWorkbook;
— прочитать данные из текстового файла или CSV построчно и разложить их по ячейкам;
— записать данные из Excel в текстовый файл;
— знать, какой объект в VBA отвечает за подключение к внешней базе данных вроде Access.

Открытие, переключение и закрытие книг

Чтобы код мог работать с другим файлом Excel, книгу сперва нужно открыть — методом Workbooks.Open, указав путь к файлу. Если книга понадобится дальше по коду, её сразу сохраняют в переменную через Set.

Dim otchet As Workbook
Set otchet = Workbooks.Open("C:\Отчёты\Продажи.xlsx")

Как только книга открыта этим кодом, она сразу становится ActiveWorkbook — той, что сейчас на переднем плане. А ThisWorkbook — это всегда та книга, в которой лежит сам выполняющийся код, и она не меняется, даже если на экране открылась и стала активной другая книга. Разница ощущается сразу, если код открывает вторую книгу: ThisWorkbook по-прежнему указывает на первую, а ActiveWorkbook — уже на вторую, только что открытую.

ThisWorkbook           - книга, где лежит САМ КОД. Не меняется никогда.
ActiveWorkbook          - книга, которая СЕЙЧАС на переднем плане.
                          Меняется, стоит открыть или переключиться на другую.

Открыли Workbooks.Open("Продажи.xlsx") из кода в книге "Макросы.xlsm":

  ThisWorkbook   -> всё ещё "Макросы.xlsm" (там лежит код)
  ActiveWorkbook -> уже "Продажи.xlsx" (её только что открыли)

Закрывают книгу методом Close, и по нему сразу видно, что делать с несохранёнными изменениями: otchet.Close SaveChanges:=True — сохранит их перед закрытием, otchet.Close SaveChanges:=False — закроет и отбросит, не сохраняя. Если нужно закрыть сразу ВСЕ открытые книги, их перебирают циклом For Each — так же, как в прошлой теме перебирали коллекцию листов.

Dim wb As Workbook
For Each wb In Workbooks
    wb.Close SaveChanges:=True
Next wb

Осторожно. Если среди закрываемых книг окажется та, где лежит сам этот код, поведение непредсказуемо — код закрывает книгу, из которой сам же выполняется. На практике такой код кладут в отдельную книгу-инструмент, а не в рабочую книгу с данными.

Импорт и экспорт: чтение и запись текстовых файлов и CSV

CSV-файл — это обычный текст, где значения одной строки разделены запятой. Чтобы прочитать его в VBA, файл сначала открывают на чтение: Open путь For Input As #1. Дальше построчно читают командой Line Input, а каждую прочитанную строку разбирают на отдельные значения функцией Split — она рвёт строку по указанному разделителю и возвращает массив кусочков.

Dim stroka As String
Dim znacheniya() As String
Dim i As Integer

Open "C:\Данные\zakazy.csv" For Input As #1
i = 1
Do While Not EOF(1)
    Line Input #1, stroka
    znacheniya = Split(stroka, ",")
    Cells(i, 1).Value = znacheniya(0)   ' первый столбец строки CSV
    Cells(i, 2).Value = znacheniya(1)   ' второй столбец строки CSV
    i = i + 1
Loop
Close #1

Условие Not EOF(1) проверяет, не дошли ли до конца файла (EOF — End Of File); пока строки не кончились, цикл продолжает читать дальше. После того как файл дочитан до конца, его обязательно закрывают командой Close #1 — так же, как закрывают книгу Excel.

Строка CSV:  "Иванов,25,Москва"

Split(строка, ",")  ->  массив из ТРЁХ элементов (индексы с 0, как у любого массива)

  znacheniya(0) = "Иванов"
  znacheniya(1) = "25"
  znacheniya(2) = "Москва"

Записывают данные в текстовый файл похожим образом, только открывают его на запись — Open путь For Output As #1, а не For Input. Дальше в файл пишут командой Write # — она удобна тем, что сама расставляет запятые между значениями и берёт текст в кавычки, то есть готовит строку сразу в формате CSV, который потом можно снова прочитать обратно.

Open "C:\Отчёты\export.csv" For Output As #1
Write #1, "Иванов", 120
Write #1, "Петров", 340
Close #1

Не перепутай с Print #. Есть похожая команда Print # — она тоже пишет в файл, но записывает текст «как есть», без автоматических запятых и кавычек. Если файл потом снова читают программой (в том числе своим же кодом VBA), удобнее Write # — он сразу готовит правильный CSV-формат.

Кратко: базы данных и веб-запросы из VBA

CSV — не единственный внешний источник. Иногда данные лежат в настоящей базе данных, например Access. Напрямую формулой Excel до неё не дотянуться, а из VBA — можно. Для соединения с файлом базы (.accdb) используют объект Connection из библиотеки ADO (ActiveX Data Objects) — через него выполняют обычный SQL-запрос. Результат запроса — набор найденных строк — приходит в виде отдельного объекта, Recordset; по нему можно пройтись циклом и разложить значения по ячейкам, точно так же, как из CSV.

Ещё один внешний источник — не файл на диске, а интернет: с помощью объекта XMLHTTP код VBA умеет отправлять HTTP-запрос и получать ответ от веб-сервиса (например, актуальный курс валюты). Тема нишевая и для большинства офисных задач не нужна — если интересно, загляни в необязательную практику ниже.

Проверь себя

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

Асохранить результат Workbooks.Open в переменную через Set
Бничего, книга и так доступна по имени файла без переменной
Впереименовать книгу сразу после открытия
Гобъявить переменную типа String и записать в неё путь к файлу

Подсказка: Workbooks.Open возвращает объект книги — его нужно куда-то поместить, чтобы не потерять.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Книга открыта кодом через Workbooks.Open. Какой книгой она сразу становится?

АActiveWorkbook
БThisWorkbook
Вникакой — статус нужно назначить отдельной командой
ГPersonalWorkbook

Подсказка: Только что открытый файл оказывается на переднем плане.

Онлайн-проверка ответа появится позже

Задание. В книге otchet есть несохранённые изменения. Сохранятся ли они при выполнении этой команды? Ответь одним словом: да или нет.

Исходный код для этого задания:

otchet.Close SaveChanges:=False

Подсказка: Параметр SaveChanges равен False — подумай, что это означает буквально.

✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Код в книге «Макросы.xlsm» открывает через Workbooks.Open книгу «Продажи.xlsx». Чему в этот момент равен ThisWorkbook?

А«Макросы.xlsm» — книга, где лежит сам код, не меняется
Б«Продажи.xlsx» — книга, открытая последней
Вобеим книгам одновременно
ГThisWorkbook исчезает, пока открыта вторая книга

Подсказка: ThisWorkbook и ActiveWorkbook — это про разные вещи: где лежит код и что сейчас на переднем плане.

Онлайн-проверка ответа появится позже

Задание. Открыто пять книг Excel. Сколько из них останется открытыми после выполнения этого кода? Впиши число.

Исходный код для этого задания:

Dim wb As Workbook
For Each wb In Workbooks
    wb.Close SaveChanges:=True
Next wb

Подсказка: Цикл проходит по коллекции Workbooks и закрывает КАЖДУЮ книгу без исключения.

✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Какая команда открывает текстовый файл для последующего построчного чтения?

АOpen путь For Input As #1
БOpen путь For Output As #1
ВWorkbooks.Open путь
ГLine Input путь

Подсказка: Нужен режим ЧТЕНИЯ уже существующего файла, а не записи в новый.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Какая функция разбивает строку CSV на отдельные значения по разделителю (например, по запятой)?

АSplit
БJoin
ВTrim
ГFormat

Подсказка: Она возвращает массив кусочков строки.

Онлайн-проверка ответа появится позже

Задание. Сколько элементов окажется в массиве znacheniya? Впиши число.

Исходный код для этого задания:

stroka = "Смирнова,31,Казань"
znacheniya = Split(stroka, ",")

Подсказка: Посчитай, на сколько частей запятая режет эту строку.

✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.

Онлайн-проверка ответа появится позже

Задание. Тебе нужно получить из этого массива город («Казань»). Под каким индексом он лежит? Впиши число.

Исходный код для этого задания:

stroka = "Смирнова,31,Казань"
znacheniya = Split(stroka, ",")

Подсказка: Индексы у массива, который вернул Split, начинаются с 0 — посчитай, какой по счёту элемент город.

✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Что проверяет условие Not EOF(1) в цикле построчного чтения файла?

Ане дошли ли до конца файла — пока строки не кончились, читать можно дальше
Бне пустой ли файл целиком
Вне открыт ли этот же файл в другой программе
Гне превышен ли лимит в 1 строку

Подсказка: EOF расшифровывается как End Of File.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Чем команда Write # отличается от Print # при записи в текстовый файл?

АWrite # сама расставляет запятые между значениями и берёт текст в кавычки — готовит строку в формате CSV
БWrite # работает быстрее, чем Print #
ВPrint # умеет писать числа, а Write # — только текст
Гразницы нет, это два названия одной и той же команды

Подсказка: Одна из команд просто печатает текст как есть, другая сама готовит его к повторному чтению.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Чтобы обратиться из VBA к внешней базе данных вроде Access, обычно используют объект…

АConnection (из библиотеки ADO)
БWorkbook
ВCollection
ГRange

Подсказка: Это тот же объект, что открывает соединение с файлом базы .accdb.

Онлайн-проверка ответа появится позже

Контрольный вопрос. В каком виде обычно приходит результат SQL-запроса к базе данных через ADO?

Аобъект Recordset — набор найденных строк
Бобычный текстовый файл CSV
Вмассив VBA, объявленный через Dim
Гновая книга Excel

Подсказка: Это набор строк, которые вернул запрос, — по нему потом проходят циклом.

Онлайн-проверка ответа появится позже

Итог

Итог. Workbooks.Open открывает другую книгу и сразу делает её ActiveWorkbook; ThisWorkbook всегда указывает на книгу с самим кодом и не меняется. Close SaveChanges:=True/False решает судьбу несохранённых изменений; For Each по коллекции Workbooks закрывает разом все открытые книги. Текстовый файл читают через Open…For Input As, построчно — Line Input, а строку CSV разбирают функцией Split на массив значений (индексы с 0); конец файла проверяет EOF(). Пишут в файл через Open…For Output As и Write # — она сама готовит строку в формате CSV, в отличие от Print #, который пишет текст как есть. К внешней базе данных (Access) обращаются через объект Connection (ADO), а результат SQL-запроса приходит как Recordset.

Практика (необязательная)

Задание для практики. Создай текстовый файл zakazy.csv с тремя строками вида «Товар,Количество,Цена» (например, «Ноутбук,2,45000»). Напиши макрос, который откроет файл (Open…For Input), построчно прочитает данные (Line Input + Split) и перенесёт их в таблицу на листе. Затем посчитай в Excel сумму по каждой строке (количество × цена) и запиши результат обратно в новый файл itogi.csv через Open…For Output и Write #.

Если хочешь пойти дальше (нишевая, необязательная тема): посмотри, как VBA обращается к внешним источникам за пределами обычных файлов — CreateObject("ADODB.Connection") для запроса к базе Access через SQL, или CreateObject("MSXML2.XMLHTTP") для запроса к веб-сервису (например, получить текущий курс валюты). Для большинства офисных задач это не понадобится — но знать, что такая возможность есть, полезно.

← Назад · ↑ В начало урока · ⌂ К навигатору курса

Школа Виктора Комлева