При работе с файлами в 1С 7.7 часто возникает задача по изменению их кодировки, например, для соответствия требованиям форматов обмена. Классический способ — использование VBScript через объект MSScriptControl.ScriptControl. Однако такой подход может вести себя нестабильно: на одних файлах скрипт работает идеально, а на других падает с ошибкой «Ошибка выполнения Microsoft VBScript: Недопустимый вызов или аргумент процедуры». Давайте вместе разберемся, почему так происходит и как написать надежный код для конвертации.
Проанализируем ситуацию. У нас есть процедура, которая читает файл, преобразует его содержимое из кодировки UTF-8 в Windows-1251 и пытается записать результат обратно в тот же файл. Ошибка возникает в самый последний момент — при записи данных.
В ходе отладки выясняется, что проблема не в путях к файлам и не в правах доступа. Если проанализировать содержимое «проблемного» файла, можно обнаружить в нем символы, которые есть в стандарте Unicode (и, соответственно, в кодировке UTF-8), но отсутствуют в целевой кодировке Windows-1251.
Ключевая причина — несовместимость символов. В рассматриваемом случае «виновником» оказался символ рубля (₽). Кодировка Windows-1251 была создана давно и не содержит многих современных символов, которые были добавлены в Unicode позже. Когда скрипт пытается записать в файл символ, для которого нет представления в Windows-1251, он не может этого сделать и генерирует ошибку «Недопустимый аргумент».
Это касается не только символа рубля, но и любых других символов, не входящих в стандартный набор CP1251: эмодзи, специфических математических или графических символов и т.д.
Давайте посмотрим на первоначальный вариант кода, который приводит к ошибке. Он использует комбинацию объектов MSScriptControl.ScriptControl, Scripting.FilesystemObject и ADODB.Stream.
Процедура глИзменитьКодовуюСтраницуФайла(имяФайла, исходнКодировка, нужнаяКодировка) Экспорт
ScrptCtrl = СоздатьОбъект("MSScriptControl.ScriptControl");
ScrptCtrl.Language = "VBScript";
ScrptCtrl.AddCode("
|Function StrConv(Text,SourceCharset,DestCharset)
| Set Stream=CreateObject(""ADODB.Stream"")
| Stream.Type=2
| Stream.Mode=3
| Stream.Open
| Stream.Charset=DestCharset
| Stream.WriteText Text
| Stream.Position=0
| Stream.Charset=SourceCharset
| StrConv=Stream.ReadText
|End Function
|
|sub ConvertCodepage( fileName, SourceCharset, DestCharset )
| set fs = CreateObject(""Scripting.FilesystemObject"")
| originalText = fs.openTextFile(fileName,1).readAll()
| convertedText = strConv(originalText, SourceCharset, DestCharset )
| fs.openTextFile(fileName,2,true).write(convertedText)
|end sub
|
|");
CodeObject = ScrptCtrl.Modules("Global").CodeObject;
CodeObject.ConvertCodepage(имяФайла, исходнКодировка, нужнаяКодировка);
КонецПроцедуры
Что здесь происходит:
originalText с помощью fs.openTextFile(fileName,1).readAll().StrConv, которая использует ADODB.Stream для конвертации строки в памяти.convertedText записывается обратно в файл через fs.openTextFile(fileName,2,true).write(convertedText).Слабое место — последняя строка. Метод write объекта FileSystemObject не умеет корректно обрабатывать ситуацию, когда в передаваемой строке есть неподдерживаемые символы для текущей системной кодировки. Он просто «падает» с ошибкой.
Чтобы избежать падения скрипта и обеспечить корректную обработку неподдерживаемых символов, следует отказаться от использования FileSystemObject для операций чтения/записи и полностью положиться на возможности объекта ADODB.Stream. Он умеет работать с файлами напрямую и более гибко управляет кодировками.
Итоговый рабочий код, который решает проблему, выглядит так:
Процедура ПреобразоватьКодировкуФайла(ИмяФайла, КодировкаОткуда, КодировкаКуда)
// Создаем объект для работы с потоками данных
ADODBStream = CreateObject("ADODB.Stream");
// --- Шаг 1: Чтение исходного файла в правильной кодировке ---
ADODBStream.Type = 2; // Тип потока: текстовый
ADODBStream.Charset = КодировкаОткуда; // Указываем исходную кодировку (например, "UTF-8")
ADODBStream.Open();
// Загружаем содержимое файла в поток
ADODBStream.LoadFromFile(ИмяФайла);
// Считываем все содержимое потока в текстовую переменную
Text = ADODBStream.ReadText();
ADODBStream.Close();
// --- Шаг 2: Запись текста в новой кодировке ---
ADODBStream.Charset = КодировкаКуда; // Указываем целевую кодировку (например, "Windows-1251")
ADODBStream.Open();
// Записываем текст в поток
ADODBStream.WriteText(Text);
// Сохраняем содержимое потока в файл, перезаписывая его (параметр 2)
ADODBStream.SaveToFile(ИмяФайла, 2);
ADODBStream.Close();
ADODBStream = "";
КонецПроцедуры
Проанализируем ключевые отличия этого подхода:
LoadFromFile(ИмяФайла): Вместо того чтобы читать файл через FileSystemObject, мы используем нативный метод ADODB.Stream. Он корректно загружает данные в поток с учетом указанной в Charset кодировки.SaveToFile(ИмяФайла, 2): Аналогично, для записи используется метод SaveToFile. Он берет содержимое потока, преобразует его в указанную целевую кодировку и сохраняет в файл.Важный момент: При таком подходе, если ADODB.Stream встречает символ, который невозможно представить в целевой кодировке, он не генерирует ошибку, а автоматически заменяет его на знак вопроса (?). Это позволяет сохранить целостность файла и успешно завершить операцию конвертации, что и требовалось для решения исходной задачи.
Помимо основного решения, стоит рассмотреть и другие полезные практики.
1. Использование временного файла. Чтение из файла и одновременная запись в него же — потенциально рискованная операция. Более надежный алгоритм — работать с временным файлом:
Этот подход предотвращает потерю данных, если в процессе записи произойдет сбой.
2. Предварительная замена символов. Если вам нужно не просто заменить неподдерживаемые символы на «?», а на что-то осмысленное, можно перед конвертацией выполнить замену вручную средствами 1С. Например, заменить символ рубля на строку "руб.".
// ... код до считывания текста в переменную Text ...
Text = СтрЗаменить(Text, "₽", "руб.");
// ... далее код записи в новой кодировке ...
3. Использование внешних компонент. Для 1С 7.7 существует множество внешних компонент (например, FormEx, 1CPP, Karlik), которые предоставляют мощные и оптимизированные функции для работы со строками и кодировками. Часто их использование оказывается проще и быстрее, чем написание VBScript-оберток.
В заключение, проблема с падением скрипта перекодировки почти всегда связана с наличием в исходных данных символов, несовместимых с целевой кодировкой. Использование прямого функционала ADODB.Stream для загрузки и сохранения файлов — самый простой и надежный способ решить эту проблему в среде 1С 7.7.