При работе с файлами формата DBF с помощью встроенного объекта XBase разработчики 1С нередко сталкиваются с ошибкой: «Длина имени файла превысила 8 символов». При этом имя самого файла может состоять ровно из 8 символов (например, passport.dbf), что вызывает недоумение. Разберем подробнее, почему возникает данное исключение, какие технические ограничения накладывает платформа 1С и как правильно решить проблему.
Проанализируем самый распространенный сценарий, с которым столкнулся автор темы. Посмотрим на исходный пример кода:
ФайлДанных = КаталогВременнойБазы + "passport.dbf";
ФайлИндекса = КаталогВременнойБазы + "passport.cdx";
Файл = Новый XBase;
Файл.ОткрытьФайл(ФайлДанных, ФайлИндекса, Истина);
Если переменная КаталогВременнойБазы возвращает путь без закрывающего слеша на конце (например, "C:\Temp" вместо "C:\Temp\"), в результате сложения строк формируется путь "C:\Temppassport.dbf".
Встроенный парсер объекта XBase выделяет имя файла после последнего найденного разделителя пути (\). В результате имя файла воспринимается платформой как "Temppassport" (12 символов), что превышает допустимый лимит стандарта 8.3. Расширение файла и точка при этом в подсчет символов имени не входят.
Чтобы избежать подобных ошибок, разберем по шагам правильное формирование пути:
Каталог = КаталогВременнойБазы;
Если Прав(Каталог, 1) <> "\" И Прав(Каталог, 1) <> "/" Тогда
Каталог = Каталог + "\";
КонецЕсли;
ФайлДанных = Каталог + "passport.dbf";
ФайлИндекса = Каталог + "passport.cdx";
Файл = Новый XBase;
Файл.ОткрытьФайл(ФайлДанных, ФайлИндекса, Истина);
Объект XBase в 1С базируется на классической спецификации dBASE III / FoxPro и строго соблюдает стандарт имен DOS 8.3. Выясним основные технические ограничения объекта XBase:
.dbf, так и файлов индексов .cdx/.idx) не может быть длиннее 8 символов без учета расширения.ПолучитьИмяВременногоФайла(): стандартный метод ПолучитьИмяВременногоФайла(".dbf") формирует длинный GUID-хеш, превышающий 8 символов. Попытка открыть такой файл напрямую через XBase всегда завершится ошибкой..cdx не может превышать 254 байта, а для .idx — 100 байт.Если вам необходимо прочитать файл, имя которого заведомо длиннее 8 символов и изменить его в источнике нельзя, рассмотрим несколько вариантов решения.
Когда требуется программно сформировать временный файл для работы через XBase, генерируем короткое имя вручную:
ИмяФайла = Лев(Строка(Новый УникальныйИдентификатор()), 8) + ".dbf";
ПолныйПуть = КаталогВременныхФайлов() + ИмяФайла;
ТаблицаDBF = Новый XBase;
ТаблицаDBF.Поля.Добавить("CODE", "S", 10);
ТаблицаDBF.СоздатьФайл(ПолныйПуть);
ТаблицаDBF.ЗакрытьФайл();
Если файл поступает от сторонней системы с длинным именем, мы можем скопировать его во временную папку с коротким именем перед чтением, выполнить обработку и затем удалить временный файл:
ФайлИсточник = Новый Файл(ПутьКДлинномуФайлу);
ВременныйПуть = КаталогВременныхФайлов() + "tempdata.dbf";
КопироватьФайл(ФайлИсточник.ПолноеИмя, ВременныйПуть);
ТаблицаDBF = Новый XBase;
ТаблицаDBF.ОткрытьФайл(ВременныйПуть);
Пока ТаблицаDBF.Следующая() Цикл
// Обработка строк DBF
КонецЦикла;
ТаблицаDBF.ЗакрытьФайл();
УдалитьФайлы(ВременныйПуть);
Если файловая система поддерживает короткие псевдонимы 8.3, можно получить короткий путь через Windows Script Host:
FSO = Новый COMОбъект("Scripting.FileSystemObject");
ФайлWindows = FSO.GetFile(ПутьКДлинномуФайлу);
КороткийПуть = ФайлWindows.ShortPath;
ТаблицаDBF = Новый XBase;
ТаблицаDBF.ОткрытьФайл(КороткийПуть);
// Обработка данных
ТаблицаDBF.ЗакрытьФайл();
Для прямого доступа к файлам DBF с любыми именами без использования XBase можно использовать подключение через ADO:
ФайлИнфо = Новый Файл(ПутьКФайлу);
КаталогФайла = ФайлИнфо.Путь;
ИмяФайла = ФайлИнфо.Имя;
Соединение = Новый COMОбъект("ADODB.Connection");
Соединение.Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + КаталогФайла + ";Extended Properties=dBASE IV;");
Команда = Новый COMОбъект("ADODB.Command");
Команда.ActiveConnection = Соединение;
Команда.CommandText = "SELECT * FROM [" + ИмяФайла + "]";
Выборка = Команда.Execute();
Пока Не Выборка.EOF Цикл
// Чтение значений: Выборка.Fields("ИмяПоля").Value
Выборка.MoveNext();
КонецЦикла;
Соединение.Close();