При работе в среде 1С:Предприятие 7.7 программисты часто сталкиваются с проблемой «молчаливого вылета» (краша) системы при попытке обработать очень длинные строки. Типичный сценарий — получение через API большого JSON-ответа (объемом 5-10 Мб и более), попытка сохранить его в файл через ADODB.Stream или распарсить с помощью MSScriptControl. Программа просто закрывается без каких-либо сообщений об ошибках. В этой статье мы разберем причины такого поведения и рассмотрим проверенные способы обхода ограничений «семерки».
Для начала проанализируем ситуацию с точки зрения архитектуры системы. В 1С 7.7 строковая переменная технически может хранить довольно большие объемы данных, однако проблема кроется в механизме взаимодействия с внешними COM-объектами (такими как ADODB.Stream, Scripting.FileSystemObject или MSScriptControl.ScriptControl). Выясним причину краша: 1С 7.7 хранит строки в однобайтовой кодировке (ANSI/Windows-1251). При передаче строки в COM-объект платформа обязана преобразовать её в двухбайтовый формат BSTR (Unicode/UTF-16). В этот момент происходит следующее:
Рассмотрим способы, которые позволяют обойти это ограничение и успешно выполнить задачу.
Если нам нужно сохранить большую строку (например, ТекстЖсон) в файл, мы не можем передать её целиком в метод WriteText. Решение заключается в том, чтобы «скармливать» данные объекту небольшими частями. Проанализируем пример кода, который позволяет это сделать:
// Предположим, ТекстЖсон — это строка длиной 6 000 000 символов
Стрим = СоздатьОбъект("ADODB.Stream");
Стрим.Type = 2; // adTypeText
Стрим.charset = "windows-1251";
Стрим.Open();
Порция = 100000; // Определяем размер блока (100 Кб)
КвоПорций = Цел(СтрДлина(ТекстЖсон) / Порция);
КвоПорций = КвоПорций + ?(КвоПорций * Порция = СтрДлина(ТекстЖсон), 0, 1);
Для СчетчикПорций = 1 По КвоПорций Цикл
НачПоз = 1 + (СчетчикПорций - 1) * Порция;
// Используем функцию Сред() для выделения части строки
Стрим.WriteText(Сред(ТекстЖсон, НачПоз, Порция));
КонецЦикла;
Стрим.SaveToFile(ФайлЖсон, 2); // 2 = adSaveCreateOverWrite
Стрим.Close();
Стрим = 0;
В данном примере мы разбиваем строку на блоки по 100 000 символов. Функция Сред() работает внутри 1С достаточно быстро, а ADODB.Stream постепенно накапливает данные в своем внутреннем буфере, не вызывая переполнения при передаче параметров.
Разберем альтернативный, чисто «семерочный» метод. Объект Текст в 1С 7.7 на удивление стабильно работает с большими объемами данных при записи на диск. Если формат выгрузки (кодировка) позволяет, можно воспользоваться следующим подходом:
ТекстФайл = СоздатьОбъект("Текст");
ТекстФайл.ДобавитьСтроку(ТекстЖсон);
ТекстФайл.Записать(ПутьКФайлу);
Однако стоит помнить, что объект Текст всегда записывает данные в кодировке Windows-1251 (ANSI) и добавляет символы перевода строки, что может быть критично для JSON. Если требуется сохранить файл строго в определенной кодировке (например, UTF-8 без BOM), лучше придерживаться Способа 1.
Когда файл успешно сохранен, возникает вторая проблема — парсинг. Использование scriptCtrl.run("parseJSON", ТекстЖсон) снова приведет к вылету, так как мы опять пытаемся передать гигантскую строку как параметр функции. Посмотрим, как можно извернуться в этой ситуации.
Рассмотрим стратегию «внутреннего чтения»: вместо того чтобы передавать текст из 1С в скрипт, мы заставим сам скрипт прочитать файл с диска. Для этого внутри кода JScript можно использовать объект Scripting.FileSystemObject или тот же ADODB.Stream. Таким образом, данные попадут в память скриптового движка напрямую, минуя «хрупкий» механизм передачи параметров 1С.
Пример логики внутри скрипта:
| function loadAndParseJSON(filePath) {
| var stream = new ActiveXObject("ADODB.Stream");
| stream.Type = 2;
| stream.Charset = "utf-8";
| stream.Open();
| stream.LoadFromFile(filePath);
| var content = stream.ReadText();
| stream.Close();
| return JSON.parse(content);
| }
В 1С нам останется только вызвать функцию, передав ей путь к файлу, что является короткой строкой и никогда не вызовет падения системы:
Рез = scriptCtrl.Run("loadAndParseJSON", ПутьКФайлу);
Если «религия позволяет» использовать сторонние расширения, настоятельно рекомендуем обратить внимание на компоненту 1С++. В ней реализован класс BinaryData, который позволяет работать с сырыми данными в памяти гораздо эффективнее стандартных средств.
Также существуют специализированные решения для парсинга JSON (например, классы KOP или внешние компоненты на базе .NET), которые используют потоковое чтение. Потоковый парсинг (SAX-подобный) не загружает всё дерево объектов в память сразу, а обрабатывает элементы один за другим. Это единственный способ надежно обрабатывать файлы размером в сотни мегабайт в условиях ограничений 32-битной архитектуры 1С 7.7.
Важный совет: если вам необходимо разобрать JSON в таблицу значений или список значений 1С, старайтесь выполнять основную фильтрацию данных внутри JavaScript-кода. Возвращайте в 1С только уже обработанные, «похудевшие» данные. Помните, что создание 100 000 элементов в СписокЗначений или строк в ТаблицаЗначений внутри 1С 7.7 — процедура медленная, и лучше подготовить данные в массивах JS, а затем перенести их в 1С одним циклом.
Подведем итог: главная заповедь при работе с большими текстами в 1С 7.7 — избегать прямой передачи сверхдлинных строк в методы COM-объектов. Используйте запись порциями, чтение через файлы и внешние компоненты, и ваша программа будет работать стабильно.