В работе с информационной системой 1С часто возникает необходимость оптимизации хранения больших объемов данных, таких как изображения. Представьте ситуацию: вы загрузили в базу данных 1С порядка 800 изображений в формате PNG, каждое размером около 1 МБ. Это неизбежно привело к значительному увеличению размера базы, что негативно сказалось на ее производительности и скорости работы. Стандартным и эффективным решением в таких случаях является перенос файлов из самой базы на дисковое хранилище (так называемые «тома»), а также оптимизация формата изображений для уменьшения их размера.
В данном материале мы рассмотрим комплексный подход к решению этой проблемы: от оптимизации хранения до пакетного обновления данных в самой 1С после внешней конвертации файлов.
Исходная проблема заключалась в том, что большое количество PNG-файлов (около 800 штук), размещенных непосредственно в базе 1С, существенно замедлило ее работу. Первым шагом к решению стало правильное стратегическое решение: базу перенесли в SQL, а сами файлы отделили от базы на дисковое хранилище. Это первый и очень важный шаг, так как он предотвращает рост размера информационной базы за счет бинарных данных и улучшает общую производительность.
Однако даже при хранении файлов на диске, формат PNG для фотографий, особенно больших, не является оптимальным с точки зрения объема. PNG лучше подходит для изображений с прозрачностью, логотипов или графики с четкими границами, тогда как JPG обеспечивает гораздо лучшую степень сжатия для фотографий, хоть и является форматом с потерями. Поэтому возникла идея:
Последний пункт — самый критичный и является предметом нашего детального рассмотрения: как пакетно переписать записи о файлах в 1С, изменив расширение с .png на .jpg?
Прежде чем приступать к изменению данных, мы должны понимать, как 1С хранит информацию о присоединенных файлах. В типовых конфигурациях 1С, таких как 1С:Управление нашей фирмой (УНФ), для хранения сведений о прикрепленных файлах к объектам (например, к номенклатуре) используется специальный справочник. В нашем случае, для картинок номенклатуры, это Справочник.НоменклатураПрисоединенныеФайлы.
Этот справочник содержит несколько ключевых реквизитов, которые критически важны для управления файлами:
Расширение: В этом реквизите хранится расширение файла (например, "png", "jpg").ПутьКФайлу: Это реквизит хранит относительный путь к файлу в томе хранения. Важно отметить, что этот путь часто включает в себя и само имя файла вместе с расширением. Например, это может выглядеть как "20210813\IMG_7739.jpg".Том: Этот реквизит содержит ссылку на элемент справочника "Тома хранения файлов", который указывает на физическую папку на сервере, где хранятся файлы.Мы должны понимать, что изменение расширения файла на диске и изменение его записи в базе — это две разные, но взаимосвязанные операции. После того как мы физически заменим файлы на диске, нам обязательно нужно обновить записи в 1С, чтобы система корректно отображала и обращалась к новым файлам.
Прежде чем мы перейдем к коду, давайте подробнее рассмотрим, почему выбранный подход с внешней конвертацией и хранением в томах является наиболее эффективным для решения подобной задачи в 1С.
Хранение больших бинарных данных, таких как изображения, непосредственно в информационной базе (в СУБД) приводит к ее стремительному росту. Это увеличивает время выполнения резервного копирования, тестирования и исправления, а также может замедлять работу многих операций, связанных с чтением и записью данных. Перенос файлов на дисковое хранилище (тома) предотвращает быстрый рост размера информационной базы, поскольку в базе хранятся только ссылки на файлы, а не сами файлы.
Когда файлы хранятся в томах на диске, 1С не тратит ресурсы на чтение и запись больших бинарных данных непосредственно из/в СУБД. Вместо этого система обращается к файловой системе сервера, что зачастую быстрее и эффективнее, особенно для большого количества файлов или файлов значительного размера. Это улучшает производительность доступа к файлам, их загрузки и отображения.
Использование формата PNG для фотографий большого размера значительно увеличивает объем данных по сравнению с JPG. PNG является форматом без потерь, что идеально для изображений с прозрачностью или четкими границами, но избыточно для большинства фотографий. JPG, являясь форматом с потерями, обеспечивает гораздо лучшую степень сжатия для фотографий при сохранении приемлемого качества. Конвертация PNG в JPG, как предложено в теме, является очень эффективным способом уменьшения общего размера хранилища и, как следствие, положительно сказывается на скорости работы с файлами. При конвертации мы можем регулировать степень сжатия, чтобы найти оптимальный баланс между размером файла и качеством изображения.
Платформа 1С действительно имеет объект Картинка и метод Преобразовать для работы с изображениями. Однако этот метод, согласно некоторым источникам, может быть ограничен конвертацией в определенные форматы (например, только в BMP и PNG), а не из PNG в JPG для всех версий платформы. Это делает внешнюю пакетную конвертацию с помощью специализированных инструментов (таких как IrfanView или онлайн-конвертеры) более надежным и универсальным решением для массовой обработки изображений.
Для корректной работы с файлами, хранящимися на диске, мы должны предварительно настроить тома хранения файлов в 1С. Это специальные папки на сервере, в которых физически будут лежать файлы. В настройках программы 1С можно установить флажок "Хранить файлы в томах на диске" и определить сами тома. Важно отметить, что путь уже созданному тому нельзя изменить, и том нельзя удалить, пока на него ссылаются файлы. Также возможно настроить правила размещения файлов в томах в зависимости от их вида или свойств.
Теперь, когда мы полностью понимаем контекст и преимущества выбранного подхода, перейдем к основной задаче — обновлению записей в базе 1С. Предполагается, что вы уже выполнили следующие шаги:
Теперь нам нужно, чтобы 1С "узнала" о новых расширениях. Для этого мы создадим внешнюю обработку, которая будет выполнять пакетное изменение реквизитов Расширение и ПутьКФайлу в справочнике НоменклатураПрисоединенныеФайлы.
Рассмотрим код, который был предложен и успешно применен в аналогичной ситуации. Создайте новую внешнюю обработку в конфигураторе 1С и добавьте в нее следующий код:
&НаСервереБезКонтекста
Процедура КомандаВыполнитьНаСервере(РасширениеИсходное,РасширениеКонечное)
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| НоменклатураПрисоединенныеФайлы.Ссылка КАК Ссылка
|ИЗ
| Справочник.НоменклатураПрисоединенныеФайлы КАК НоменклатураПрисоединенныеФайлы
|ГДЕ
| НоменклатураПрисоединенныеФайлы.Расширение = &РасширениеИсходное
| //И НоменклатураПрисоединенныеФайлы.ТипХраненияФайла = ЗНАЧЕНИЕ(Перечисление.ТипыХраненияФайлов.ВТомахНаДиске)";
Запрос.УстановитьПараметр("РасширениеИсходное", РасширениеИсходное);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
ДлинаИсходногоРасширения = СтрДлина(РасширениеИсходное);
Пока Выборка.Следующий Цикл
Попытка
СпрОбъект = Выборка.Ссылка.ПолучитьОбъект();
СпрОбъект.Расширение = РасширениеКонечное;
СпрОбъект.ПутьКФайлу = Лев(СпрОбъект.ПутьКФайлу,СтрДлина(СпрОбъект.ПутьКФайлу) - ДлинаИсходногоРасширения) + РасширениеКонечное;
СпрОбъект.Записать();
Исключение
// Тут надо обработать ошибку. Например, вывести сообщение в Журнал регистрации.
// Сообщить("Ошибка при обработке файла " + Выборка.Ссылка.Наименование + ": " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура КомандаВыполнить(Команда)
РасширениеИсходное = "png";
РасширениеКонечное = "jpg";
КомандаВыполнитьНаСервере(РасширениеИсходное,РасширениеКонечное);
КонецПроцедуры
Давайте разберем этот код по частям, чтобы полностью понять его логику и функциональность:
КомандаВыполнитьНаСервере(РасширениеИсходное, РасширениеКонечное):
Эта серверная процедура является ядром нашей обработки. Она выполняется на стороне сервера 1С, что обеспечивает более быстрый доступ к данным и обработку больших объемов информации без участия клиентской части.
Инициализация запроса: Мы создаем новый объект Запрос. С его помощью мы будем выбирать все записи из справочника НоменклатураПрисоединенныеФайлы, которые соответствуют нашему условию.
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| НоменклатураПрисоединенныеФайлы.Ссылка КАК Ссылка
|ИЗ
| Справочник.НоменклатураПрисоединенныеФайлы КАК НоменклатураПрисоединенныеФайлы
|ГДЕ
| НоменклатураПрисоединенныеФайлы.Расширение = &РасширениеИсходное
| //И НоменклатураПрисоединенныеФайлы.ТипХраненияФайла = ЗНАЧЕНИЕ(Перечисление.ТипыХраненияФайлов.ВТомахНаДиске)";
В тексте запроса мы выбираем Ссылка на элементы справочника НоменклатураПрисоединенныеФайлы. Условие ГДЕ НоменклатураПрисоединенныеФайлы.Расширение = &РасширениеИсходное позволяет нам отфильтровать только те файлы, у которых текущее расширение совпадает с исходным (в нашем случае "png").
Обратите внимание на закомментированную строку //И НоменклатураПрисоединенныеФайлы.ТипХраненияФайла = ЗНАЧЕНИЕ(Перечисление.ТипыХраненияФайлов.ВТомахНаДиске). Если вы абсолютно уверены, что все обрабатываемые файлы хранятся в томах на диске (что рекомендуется), и вы хотите ограничить выборку только ими, вы можете раскомментировать эту строку. Однако, если у вас в базе присутствуют файлы, хранящиеся непосредственно в информационной базе (что менее оптимально для больших файлов), и вы также хотите их обработать, то эту строку следует оставить закомментированной.
Установка параметров и выполнение запроса:
Запрос.УстановитьПараметр("РасширениеИсходное", РасширениеИсходное);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Здесь мы присваиваем значение параметру &РасширениеИсходное (например, "png") и выполняем запрос. Полученный результат запроса затем преобразуется в объект Выборка, по которому мы будем итерироваться.
Расчет длины исходного расширения:
ДлинаИсходногоРасширения = СтрДлина(РасширениеИсходное);
Эта переменная нам понадобится для корректного обновления реквизита ПутьКФайлу, чтобы "отрезать" старое расширение.
Цикл по результатам запроса:
Пока Выборка.Следующий Цикл
//...
КонецЦикла;
Мы используем цикл Пока Выборка.Следующий Цикл для последовательного перебора всех найденных ссылок на присоединенные файлы.
Получение объекта и изменение реквизитов:
Попытка
СпрОбъект = Выборка.Ссылка.ПолучитьОбъект();
СпрОбъект.Расширение = РасширениеКонечное;
СпрОбъект.ПутьКФайлу = Лев(СпрОбъект.ПутьКФайлу,СтрДлина(СпрОбъект.ПутьКФайлу) - ДлинаИсходногоРасширения) + РасширениеКонечное;
СпрОбъект.Записать();
Исключение
// Обработка ошибок
КонецПопытки;
Внутри цикла для каждой ссылки мы выполняем следующее:
СпрОбъект = Выборка.Ссылка.ПолучитьОбъект();: Мы получаем объект справочника. Важно: работа с объектами (ПолучитьОбъект, изменение реквизитов, Записать) обеспечивает соблюдение всех механизмов записи 1С, включая вызов событий и проверку данных. Для 800 файлов это приемлемый и безопасный подход, хотя для миллионов записей можно рассмотреть более низкоуровневые прямые изменения регистров сведений, что, однако, требует большей осторожности.СпрОбъект.Расширение = РасширениеКонечное;: Мы устанавливаем новое расширение для файла (например, "jpg") в соответствующем реквизите.СпрОбъект.ПутьКФайлу = Лев(СпрОбъект.ПутьКФайлу,СтрДлина(СпрОбъект.ПутьКФайлу) - ДлинаИсходногоРасширения) + РасширениеКонечное;: Это ключевая строка для обновления пути. Мы используем функцию Лев(), чтобы "отрезать" от текущего значения ПутьКФайлу старое расширение, а затем конкатенируем (склеиваем) оставшуюся часть пути с новым расширением. Например, если ПутьКФайлу был "20210813\IMG_7739.png" и исходное расширение "png" (длиной 3 символа), то мы получим "20210813\IMG_7739" и добавим к нему "jpg", в результате чего путь станет "20210813\IMG_7739.jpg". Это критически важно, так как поле ПутьКФайлу также содержит расширение.СпрОбъект.Записать();: Мы сохраняем все изменения в базе данных.Попытка...Исключение очень важен. Он позволяет продолжить выполнение обработки даже в случае возникновения ошибки при записи какого-либо конкретного файла. Мы рекомендуем добавить в блок Исключение вывод подробного сообщения об ошибке в Журнал регистрации 1С или в отдельное окно, чтобы можно было проанализировать, с какими файлами возникли проблемы.КомандаВыполнить(Команда):
Эта клиентская процедура отвечает за запуск серверной части. Она будет доступна пользователю в форме обработки.
&НаКлиенте
Процедура КомандаВыполнить(Команда)
РасширениеИсходное = "png";
РасширениеКонечное = "jpg";
КомандаВыполнитьНаСервере(РасширениеИсходное,РасширениеКонечное);
КонецПроцедуры
Здесь мы жестко задаем исходное расширение как "png" и конечное как "jpg". Затем просто вызываем серверную процедуру КомандаВыполнитьНаСервере, передавая ей эти параметры. При необходимости, можно вынести эти параметры на форму обработки в виде полей ввода, чтобы пользователь мог гибко задавать расширения для конвертации.
Перед тем как применять подобное решение на практике, особенно на рабочей базе, мы настоятельно рекомендуем принять во внимание следующие важные моменты:
КРИТИЧЕСКИ ВАЖНО всегда сначала выполнять подобные операции на **тестовой базе**, которая является точной копией вашей рабочей базы. Это позволит убедиться в корректности работы обработки, проверить все сценарии и исключить любые непредвиденные последствия без риска для основной работы предприятия.
Перед началом любых манипуляций с данными на **рабочей базе** обязательно сделайте **полную и актуальную резервную копию** информационной базы 1С. Также не забудьте создать резервную копию самих томов с файлами на диске. Это ваша "подушка безопасности" на случай непредвиденных проблем.
Убедитесь, что после внешней конвертации имена файлов (без расширения) и их расположение в томах на диске **не изменились**. Если файлы будут перемещены или переименованы (помимо изменения расширения), 1С не сможет найти их по обновленным путям, даже если записи в базе будут исправлены. Строгая привязка "один к одному" между старым PNG и новым JPG по местоположению и имени (до расширения) обязательна.
При конвертации из PNG в JPG вы можете регулировать степень сжатия. Экспериментируйте с различными настройками, чтобы найти оптимальный баланс между размером файла и приемлемым качеством изображения. Чрезмерное сжатие может привести к заметной потере качества, особенно на детальных изображениях.
Пользователь, под которым будет запускаться данная обработка, должен иметь достаточные права доступа для чтения и изменения данных в справочнике НоменклатураПрисоединенныеФайлы. В противном случае, обработка завершится с ошибкой прав доступа.
Для предотвращения деградации производительности при отображении изображений в динамических списках 1С (например, в списках номенклатуры с картинками) рекомендуется использовать коллекции изображений и индексы. Загрузка каждой картинки по отдельности для отображения в списке может сильно замедлить интерфейс.
Помимо работы с файлами, общая производительность 1С с большими объемами данных улучшается за счет множества других факторов. К ним относятся оптимизация запросов (использование индексов), применение мощных серверных решений (клиент-серверный вариант работы), а также регулярное обслуживание базы данных, включая очистку кэша и тестирование/исправление.
Мы видим, что этот подход позволяет эффективно решить проблему массовой миграции и оптимизации изображений в 1С. Путем комбинации внешней конвертации файлов и программного обновления записей в базе данных, мы значительно улучшаем производительность системы, уменьшаем занимаемое дисковое пространство и оптимизируем работу с большими объемами медиаконтента.