Как изменить дату модификации файла в 1С с помощью Shell.Application и избежать ошибки «Плохой тип переменной»?

Программист 1С v8.3 (Обычные формы)
← На главную

При работе с файлами в 1С, особенно когда необходимо изменить их атрибуты, такие как дата создания или модификации, мы часто обращаемся к возможностям операционной системы Windows. Один из распространенных подходов — использование COM-объекта Shell.Application, который предоставляет доступ к функциям оболочки Windows. Однако, на этом пути могут возникнуть неочевидные ошибки, например, «Плохой тип переменной», которая поставила в тупик нашего коллегу.

В данном материале мы подробно рассмотрим, как правильно использовать Shell.Application для изменения даты модификации файла, выясним причину возникновения ошибки и предложим решения как для одиночных файлов, так и для пакетной обработки в цикле. Кроме того, мы заглянем за рамки Shell.Application и обсудим альтернативные и более мощные способы работы с файловыми датами.

Выясняем исходную проблему: попытка присвоить файлу свою дату модификации

Наш коллега столкнулся с необходимостью присвоить файлам произвольную дату модификации. Для этого он использовал объект Shell.Application. Давайте посмотрим на его первоначальный код:


Шел=СоздатьОбъект("Shell.Application");
Папка=Шел.NameSpace("c:\out\photo_\");
Файл=Папка.ParseName("c:\out\photo_\12.jpeg");
Д_Ф=Формат(ТекущаяДата()+2,"ДДДММГГГГ");
ДД_ф=Сред(Д_ф,4,2)+"/"+Лев(Д_ф,2)+"/"+Прав(Д_ф,4);
Файл.ModifyDate=(ДД_ф+" 01:00:00 AM");

Как отмечает автор, при работе с одним явно указанным файлом (например, "c:\out\photo_\12.jpeg"), этот код функционировал без проблем. Однако, как только он попытался подставить имя файла через переменную (что критически важно для обработки нескольких файлов), возникла ошибка: «Плохой тип переменной». Это указывает на некорректную передачу аргумента или использование объекта не по назначению, что часто встречается при взаимодействии с внешними COM-объектами.

Анализируем поведение метода ParseName объекта Shell.Application

Чтобы понять причину ошибки, давайте подробнее разберем, как работают методы NameSpace и ParseName объекта Shell.Application. Эти методы используются для навигации по файловой системе и получения объектов, представляющих файлы и папки.

  1. Мы сначала создаем объект Шел = СоздатьОбъект("Shell.Application").
  2. Затем, используя метод NameSpace(), мы указываем каталог, в котором будем работать: Папка = Шел.NameSpace("c:\out\photo_\"). Важно понимать, что объект Папка теперь представляет собой указатель на конкретную директорию.
  3. После этого, метод ParseName(), вызываемый у объекта Папка, ожидает в качестве аргумента только имя файла или подпапки, которая находится непосредственно внутри этого NameSpace. Он не требует и даже не приемлет полный путь к файлу.

В этом и заключалась основная причина ошибки. Когда автор передавал полный путь файла в ParseName после того, как NameSpace уже был определен для папки, объект ParseName не мог корректно интерпретировать такую строку, вызывая ошибку «Плохой тип переменной».

Решение для одного файла: правильное указание имени файла

Исходя из нашего анализа, решение для одного файла становится очевидным. Если мы уже определили рабочую папку с помощью NameSpace, то в ParseName необходимо передать только имя файла без указания полного пути. Давайте посмотрим, как это выглядит в коде, согласно подсказкам коллег с форума:


Шел=СоздатьОбъект("Shell.Application");
Папка=Шел.NameSpace("c:\out\photo_\"); // Указываем корневую папку
Файл=Папка.ParseName("12.jpeg"); // Передаем только имя файла
Д_Ф=Формат(ТекущаяДата()+2,"ДДДММГГГГ");
ДД_ф=Сред(Д_Ф,4,2)+"/"+Лев(Д_Ф,2)+"/"+Прав(Д_Ф,4);
Файл.ModifyDate=(ДД_ф+" 01:00:00 AM");

Теперь код для одного файла работает корректно, потому что ParseName("12.jpeg") правильно интерпретируется как файл внутри "c:\out\photo_\".

Проблема в цикле: некорректная передача полного пути

Однако, задача автора заключалась в обработке нескольких файлов в цикле. Когда он попытался применить полученные знания, ошибка «Плохой тип переменной» снова возникла. Давайте посмотрим на код, который привел к повторной ошибке:


папка_ф="c:\out\photo_";
fil="";
// ... В цикле формируется имя файла, например, ID_ = "12"
fil=папка_ф+ID_+".jpeg"; // fil = "c:\out\photo_\12.jpeg"
Файл=Папка.ParseName(fil); // Вот здесь возникает ошибка

Здесь мы видим ту же ошибку: переменная fil содержит полный путь к файлу (например, "c:\out\photo_\12.jpeg"), и этот полный путь передается в Папка.ParseName(). Как мы уже выяснили, это неверно, так как Папка уже является объектом, представляющим директорию "c:\out\photo_\", и ParseName ожидает только относительное имя файла.

Окончательное решение для обработки множества файлов в цикле

Для корректной работы в цикле нам необходимо убедиться, что в ParseName всегда передается только имя файла без пути. Мы можем модифицировать наш код следующим образом:


Шел=СоздатьОбъект("Shell.Application");
папка_ф="c:\out\photo_\"; // Путь к директории
Папка=Шел.NameSpace(папка_ф); // Определяем NameSpace для папки

// Пример цикла для обработки нескольких файлов
// Предположим, у нас есть список имен файлов или их ID
Для Каждого ИмяФайла Из СписокИменФайлов Цикл 
    // Предположим, ИмяФайла содержит только "12.jpeg" или "34.png"
    // Если ИмяФайла приходит в формате "ID_123.jpeg", то получаем чистое имя
    ИмяФайлаБезПути = ИмяФайла; // В идеале здесь должна быть логика, извлекающая только имя файла,
                               // если ИмяФайла изначально содержало полный путь.
                               // В нашем случае, ID_ = "12", поэтому ИмяФайла = ID_ + ".jpeg" = "12.jpeg"
    
    // Получаем объект файла, передавая только имя файла в ParseName
    Попытка
        Файл = Папка.ParseName(ИмяФайлаБезПути);
        
        // Формируем новую дату модификации
        Д_Ф = Формат(ТекущаяДата() + 2, "ДДДММГГГГ"); // Пример: ТекущаяДата() + 2
        ДД_ф = Сред(Д_Ф, 4, 2) + "/" + Лев(Д_Ф, 2) + "/" + Прав(Д_Ф, 4); // MM/DD/YYYY
        
        // Присваиваем новую дату модификации
        Файл.ModifyDate = (ДД_ф + " 01:00:00 AM");
        Сообщить("Дата модификации для файла " + ИмяФайлаБезПути + " успешно изменена.");
    Исключение
        Сообщить("Ошибка при обработке файла " + ИмяФайлаБезПути + ": " + ОписаниеОшибки());
    КонецПопытки;
КонецЦикла;

В этом решении мы сначала определяем объект Папка один раз для всей директории. Затем в цикле, для каждого файла, мы передаем в Папка.ParseName() только его имя (например, "12.jpeg") без указания полного пути. Это позволяет избежать ошибки «Плохой тип переменной» и корректно изменить дату модификации для каждого файла.

Обратите внимание на формат даты: (ДД_ф+" 01:00:00 AM"). Объект File.ModifyDate ожидает строку с датой и временем. Важно, чтобы формат соответствовал ожиданиям COM-объекта, который часто чувствителен к региональным настройкам системы. В приведенном примере используется формат "ММ/ДД/ГГГГ ЧЧ:ММ:СС AM/PM". Для надежности, особенно при использовании на разных операционных системах, рекомендуется проверять ожидаемый формат или использовать универсальные методы форматирования даты.

Расширяем возможности: изменение других дат и альтернативные подходы

Рассмотренный выше метод с Shell.Application успешно решает задачу изменения даты модификации файла (ModifyDate). Однако, как быть, если нам необходимо изменить дату создания (Creation Date) или дату последнего доступа (Last Access Date)? Здесь Shell.Application демонстрирует свои ограничения.

Shell.Application: только ModifyDate

Нам важно понимать, что объект Shell.Application, через полученный им объект File, предоставляет прямой доступ только к свойству ModifyDate для изменения. Для других дат, таких как дата создания, прямых методов для изменения через этот объект не предусмотрено. Для более полного контроля над атрибутами файла нам придется обратиться к другим инструментам и подходам.

Использование FileSystemObject (FSO)

Для более общего взаимодействия с файловой системой в скриптах Windows часто используется объект Scripting.FileSystemObject (FSO). Он также позволяет получать доступ к файлам и их свойствам, включая даты. Однако, как и в случае с Shell.Application, FileSystemObject в основном предоставляет методы для чтения этих дат и для изменения даты последней модификации (DateLastModified) и даты последнего доступа (DateLastAccessed).

Давайте посмотрим на пример использования FSO для изменения даты модификации:


Set fso = СоздатьОбъект("Scripting.FileSystemObject");
Set file = fso.GetFile("c:\out\photo_\12.jpeg");
file.DateLastModified = "12/31/2024 10:00:00 AM"; // Указываем новую дату и время в формате MM/DD/YYYY

Здесь мы видим, что FSO позволяет изменять DateLastModified, что функционально аналогично ModifyDate в Shell.Application. Для даты создания (CreationDate) FSO предоставляет только чтение.

Более мощные средства: PowerShell

Если нам требуется изменить именно дату создания файла (Creation Date), а также дату модификации и доступа, наиболее гибким и современным инструментом в среде Windows является PowerShell. Он предоставляет мощные командлеты и прямой доступ к объектам файловой системы, позволяя манипулировать их свойствами.

В 1С мы можем выполнять PowerShell-скрипты через командную строку или напрямую через COM-объекты PowerShell. Давайте рассмотрим пример изменения даты создания и модификации в PowerShell:


$filePath = "c:\out\photo_\12.jpeg";
$newDate = Get-Date "2024-12-31 10:00:00 AM"; // Создаем объект даты и времени

(Get-Item $filePath).CreationTime = $newDate; // Изменяем дату создания
(Get-Item $filePath).LastWriteTime = $newDate; // Изменяем дату модификации

В этом примере мы получаем объект файла с помощью Get-Item, а затем напрямую присваиваем новые значения свойствам CreationTime (дата создания) и LastWriteTime (дата модификации). Это значительно расширяет наши возможности по управлению атрибутами файлов.

Глубокий контроль: WinAPI через внешние компоненты

Для максимального и полного контроля над атрибутами файла, включая все даты, можно использовать функции Windows API (WinAPI), такие как SetFileTime. Этот метод является наиболее сложным и обычно реализуется в 1С через внешние компоненты (DLL), написанные на C++ или другом языке, или через .NET-сборки, которые могут быть загружены и использованы в 1С. Подход с WinAPI дает полный контроль, но требует глубокого понимания низкоуровневых операций с файлами и навыков разработки внешних компонентов.

Важные моменты при работе с файловыми атрибутами

Вне зависимости от выбранного метода, при работе с файловыми датами следует всегда учитывать несколько важных факторов:

  1. Права доступа: У пользователя, под которым выполняется скрипт 1С, должны быть достаточные права на изменение файлов и их атрибутов. В противном случае возникнет ошибка доступа.
  2. Формат даты и времени: При передаче даты и времени в свойства объектов, таких как ModifyDate, DateLastModified, CreationTime, критически важно соблюдать правильный формат. В скриптах Windows часто используется американский формат "ММ/ДД/ГГГГ", но это может зависеть от региональных настроек операционной системы. Всегда лучше явно указывать формат или использовать универсальные методы преобразования дат.
  3. Локализация: Региональные настройки операционной системы могут влиять на интерпретацию строк даты и времени. При разработке универсальных решений старайтесь использовать форматы, которые наименее подвержены локализационным изменениям, или явно указывать культуру для преобразования.
  4. Влияние файловой системы: Некоторые файловые системы (например, FAT32) или сетевые хранилища могут иметь ограничения на точность или возможность изменения некоторых атрибутов файла.

Заключение

Мы успешно разобрали проблему изменения даты модификации файла в 1С с использованием Shell.Application и выявили ключевую причину ошибки «Плохой тип переменной»: некорректное использование метода ParseName. Мы выяснили, что ParseName ожидает только имя файла, если NameSpace уже указал директорию. Этот простой, но важный принцип позволил нам разработать работающее решение как для одиночных файлов, так и для обработки в цикле.

Кроме того, мы расширили наши знания, рассмотрев альтернативные методы для более полного контроля над файловыми датами, включая FileSystemObject и мощный PowerShell. Для задач, требующих изменения даты создания, PowerShell является предпочтительным выбором, а для самых глубоких манипуляций — WinAPI через внешние компоненты. Всегда помните о правах доступа и корректном форматировании дат, чтобы избежать непредвиденных ошибок.

Надеемся, что этот подробный анализ поможет вам успешно справляться с задачами по управлению файловыми атрибутами в ваших проектах на 1С.

← На главную