При попытке загрузить в 1С объемный файл выгрузки (например, базу недействительных паспортов весом более 1 ГБ) разработчики нередко сталкиваются с ситуацией, когда данные считываются лишь частично. Попытка открыть такой файл через COM-объект Microsoft Excel упирается ровно в 1 048 576 строк, а использование Microsoft ADO с драйвером Excel нередко ограничивает выборку 65 536 строками. Разберем по шагам, почему возникают эти ограничения и как правильно организовать быстрое и стабильное чтение файлов огромного объема средствами платформы 1С:Предприятие.
Проанализируем природу исходного файла. Несмотря на то что операционная система Windows может по умолчанию сопоставлять файлы с расширением CSV приложению Microsoft Excel, файл CSV не является рабочей книгой Excel. Это обычный текстовый документ с разделителями.
Когда мы пытаемся прочитать файл через COM-объект Excel.Application или настраиваем строку подключения ADO с указанием драйвера электронной таблицы (Extended Properties="Excel 12.0..."), вступают в силу жесткие внутренние лимиты форматов Microsoft Excel:
Кроме того, драйверы семейства Microsoft Jet / ACE OLEDB имеют собственное ограничение на размер обрабатываемой базы в 2 ГБ, а в 32-разрядной среде они быстро вызывают ошибки нехватки оперативной памяти. Следовательно, использование COM-объекта Excel или драйвера Excel для чтения текстовых файлов размером в гигабайты является архитектурной ошибкой.
Рассмотрим основной штатный механизм платформы, предназначенный именно для таких задач — объект ЧтениеCSV. Главное преимущество этого объекта заключается в потоковой обработке: он не загружает весь многогигабайтный файл в оперативную память целиком, а считывает его порциями. При этом он корректно обрабатывает экранированные кавычки, многострочные поля и спецсимволы.
Посмотрим на пример организации чтения файла с пакетной записью в базу данных:
ПараметрыЧтения = Новый ПараметрыЧтенияCSV();
ПараметрыЧтения.РазделительПолей = ";";
ПараметрыЧтения.РазделительСтрок = Символы.ПС;
ФайлДляЧтения = Новый ЧтениеCSV;
ФайлДляЧтения.Открыть(ПутьКФайлу, ПараметрыЧтения);
СчетчикСтрок = 0;
РазмерПакета = 10000;
НачатьТранзакцию();
Попытка
Пока ФайлДляЧтения.Прочитать() Цикл
МассивДанныхСтроки = ФайлДляЧтения.ПолучитьСтроку();
// Обработка полученных колонок строки
Серия = МассивДанныхСтроки[0];
Номер = МассивДанныхСтроки[1];
// Логика добавления данных в коллекцию или набор записей
СчетчикСтрок = СчетчикСтрок + 1;
Если СчетчикСтрок % РазмерПакета = 0 Тогда
ЗафиксироватьТранзакцию();
НачатьТранзакцию();
КонецЕсли;
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ФайлДляЧтения.Закрыть();
ВызватьИсключение;
КонецПопытки;
ФайлДляЧтения.Закрыть();
Если структура файла предельно проста (например, две колонки чисел без переносов строк внутри ячеек) или требуется максимальная гибкость в разборе, разберем работу с объектом ЧтениеТекста. Здесь критически важно считывать данные исключительно методом ПрочитатьСтроку() внутри цикла.
Важно: никогда не используйте методы Прочитать() без параметров или загрузку в ДвоичныеДанные для гигабайтных файлов — это гарантированно приведет к критической ошибке платформы Недостаточно памяти, особенно на 32-разрядных рабочих процессах сервера или клиентах.
Посмотрим, как выглядит реализация потокового чтения:
ТекстовыйФайл = Новый ЧтениеТекста(ПутьКФайлу, КодировкаТекста.ANSI);
Счетчик = 0;
СтрокаФайла = ТекстовыйФайл.ПрочитатьСтроку();
Пока СтрокаФайла <> Неопределено Цикл
// Пропускаем пустые строки при необходимости
Если Не ПустаяСтрока(СтрокаФайла) Тогда
ЗначенияКолонок = СтрРазделить(СтрокаФайла, ",;");
// Выполняем полезную работу с массивом ЗначенияКолонок
Счетчик = Счетчик + 1;
КонецЕсли;
СтрокаФайла = ТекстовыйФайл.ПрочитатьСтроку();
КонецЦикла;
ТекстовыйФайл.Закрыть();
Если архитектура решения строго требует применения Microsoft ADO (например, при выборке с фильтрацией по SQL), проанализируем настройку правильного драйвера. Вместо драйвера Excel необходимо указать драйвер для текстовых файлов (Microsoft Text Driver или провайдер ACE с типом Text). В параметре Data Source при этом указывается путь к папке, а имя файла выступает в роли таблицы в SQL-запросе:
КаталогФайла = "C:\Files\";
ИмяФайла = "list_of_expired_passports.csv";
СтрокаПодключения = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + КаталогФайла + ";Extended Properties=""Text;HDR=Yes;FMT=Delimited"";";
Соединение = Новый COMОбъект("ADODB.Connection");
Соединение.Open(СтрокаПодключения);
Команда = Новый COMОбъект("ADODB.Command");
Команда.ActiveConnection = Соединение;
Команда.CommandText = "SELECT * FROM [" + ИмяФайла + "]";
Выборка = Команда.Execute();
Пока Не Выборка.EOF Цикл
// Чтение колонок через Выборка.Fields
Выборка.MoveNext();
КонецЦикла;
Выборка.Close();
Соединение.Close();
Однако помните, что штатные механизмы ЧтениеCSV и ЧтениеТекста в современной платформе 1С работают быстрее внешних COM-библиотек, не требуют установки дополнительных драйверов Microsoft Access Database Engine на сервер и не зависят от разрядности операционной системы.
Рассмотрим практические советы при обработке многомиллионных массивов данных:
НачатьТранзакцию() и ЗафиксироватьТранзакцию(), чтобы не переполнять журнал транзакций СУБД.COPY в PostgreSQL или утилита bcp в MS SQL Server) во внешнюю таблицу с последующим подключением через объект ВнешниеИсточникиДанных.