Opensource / Cross platform / Python.
Структура данных файлов 1CD уже давно ни для кого не является секретом. Благодарим за это awa. Без его статьи этой библиотеки не было бы.
В остальном история разработки крайне простая: возникло желание изучить Python. А какой лучший способ изучения языка программирования? Конечно же, написать на нем небольшой проект. В голову пришла идея написать извлекатель паролей (точнее их хэшей) из файловой базы 1С. Поначалу думал сделать простую обертку над tool_1cd, но потом решил, что это как-то не спортивно. Из готовых аналогов нашел только проприетарные библиотеки / приложения и реализацию средствами 1С (медленно, только под Windows, но все равно круто). В итоге решил написать библиотеку для Python. А потом уже и экстрактор на ней сделать.
Что из этого получилось, можно увидеть во вложении.
Как работатать:
1. Ставим модуль через pip:
pip install onec_dtools
2. Импортируем библиотеку в приложение и смотрим, что она может.
import onec_dtools with open('1Cv8.1CD', 'rb') as f: db = onec_dtools.DatabaseReader(f) print("База данных 1С (вер. {}/{})".format(db.version, db.locale)) print("Всего таблиц: {}".format(len(db.description))) if row.is_empty: continue for row in db.tables['V8USERS']: print(row.as_list(True))
В db у нас будет класс для взаимодействия файловой базой. Инициализация класса, пожалуй, самая длительная операция, т.к. она считывает всю структуру БД. После инициализации нам сразу доступна информации о версии формата файла (тестировалось все только с базами формата 8.2.14 — этого должно быть достаточно для работы со всеми актуальными версиями платформы), языка БД и описание таблиц.
Чтение таблиц БД возвращает генератор. Таким образом данные считываются и загружаются в память построчно, а не всей таблицей сразу. Этот же механизм используется при работе с полями неограниченной длины: при считывании строки они возвращают не целиковое значение, а его длину и генератор для чтения.
Вот, пожалуй, и все, что умеет библиотека на данный момент. В перспективе добавлю возможность работы с файлами конфигураций.
27.12.2024
С момент публикации этой статьи модуль был «причесан» и теперь вполне может считаться production ready.
Из основных изменений:
- Добавлена возможность работы с контейнерами по аналогии с v8unpack. Об этом даже есть отдельная статья.
- Добавлены тесты, которые не смотря на свою простоту обеспечивают 98% покрытие кода проекта.
- Появилась документация.
Если среди вас есть те, кто желает присоединиться к разработке, то добро пожаловать на Github. Что хотелось бы реализовать:
- Обратную совместимость с Python 2.7.
- Возможность работы с файлами DT. К сожалению я не нашел достаточно хорошего описания формата и не смог до конца разобраться в нем сам, поэтому буду рад помощи.
13.02.2024
Большое обновление.
- Рефакторинг механизмов чтения формата 1CD
- Новый API работы с файловой базой
- Значительно улучшена документация
- Исправлена ошибка преобразования значений типа Numeric
- Исправлена ошибка чтения значений полей, допускающих NULL
- Ускорено чтение информации о страницах размещения объектов БД
- Ускорен разбор описаний таблиц БД
- Ускорено преобразование полей типа DateTime
- Преобразование значение в полях таблиц теперь происходит в момент обращения к ним, а не в момент чтения строк
05.09.2024
- Добавлена поддержка 8.3.8
24.02.2024
- Добавлена возможность распаковки EFD файлов (файлы поставки конфигурации)
Спасибо через pip найдем, я бы советовал убрать из начала названия «1C» и заменить на что-нибудь другое, ато могут придраться.
Автор молодец, только ради спортивного интереса можно покопаться в структуре файловой базы. Но надо бы убрать из названия 1с, а то могут быть проблемы. Да и вообще наверняка программа нарушает лицензионное соглашение.
(2) pumbaE, (3) MishaHD,
От греха подальше переименую 1С в onec пожалуй.
Нарушений лицензии я тут никаких не вижу, тем более аналогичных решений достаточно и существуют они давно.
(3) MishaHD,
совсем не наверняка и не очевидно, что нарушает.
https://github.com/Infactum/1C-dtools
(2) pumbaE, на гитхабе ищется в две секунды
Сам хотел такое написать на питоне, с удовольствем посмотрю ваше творение.
Ну так ссылку то ты дашь на свое творение??
(11) doctorov_s, стоит быть внимательнее немного.
Или вам мало того, что пакет опубликован в PiPy, и есть исходники во вложении к статье / ссылка на гитхаб в комментариях?
Я тут недавно для 7-ки задел подобное
https://github.com/WorldException/v7py
(0)
В python 2 не работает:
Показать
(17) Asis, на данный момент заявлена поддержка python 3.4 и 3.5.
Возможно заработает и на более ранних версиях 3.х — не тестировал.
Я в курсе, что Python 2.x по прежнему очень популярен, но в моим планах обеспечить его поддержку пока нет. Если желаете помочь в этом — добро пожаловать на гитхаб.
P.S. Указанная ошибка должна устраниться просто переименованием _datetime в datetime. Но я не думаю, что это будет единственная причина несовместимости с python 3
Это же github! Дорабатывайте, делайте свою ветку или делайте pull request автору. У меня на python 2.7.8 немного не завелась — поправил, работает (на более ранних версиях может не работать).
Кстати, автору большое спасибо — отличное начинание и хороший код.
А зачем совместимость с Python 2.7? Люди обычно думают, как бы сделать совместимость с 3.х. Вообще проблемы поставить несколько версий интерпретатора под разные нужды быть не должно.
(20) Cujoko, на самом деле полно людей, которые принципиально до сих пор предпочитают python 2.x.
Я сам ничего бэкпортировать не буду, но если найдется желающий — почему бы и нет? Это ж опенсорс.
Меня больше работа с DT интересует.
Обновлено. Теперь в части чтения 1CD работает намного быстрее и читать строки можно не только итеративно, но и по индексу. Так же исправлено много разных ошибок.
Добавил поддержку 8.3.8, благодаря описанию из этойстатьи . Вроде бы сейчас onec_dtools единственная open source библиотека, которая работает с этим форматом.
.. так бы и ставил лайки после каждого обновления 🙂 спасибо, что не забрасываете это неблагодарное дело!
по строению dt файла есть инфа?
(25) Нету.
Если бы было готовое описание формата, то я бы уже добавил его в библиотеку.
А так надо за хекс редактор садиться. В планах есть, но пока не до этого.
(26)а как тип распаковывает dt в таблицы?http://expert.chistov.pro/public/183180/
(27) Описания формата DT нет в открытом доступе насколько мне известно. Это вовсе не означает, что никто в нем не разобрался.
Про сабж по ссылке мне известно, но это коммерческий продукт. Очевидно, что его автор помогать мне не будет.
Собственно по распаковке EFD я тоже к нему обращался, т.к. у него был плагин для Total Commander, и он готов был предоставить исходники, но сказал, что они были утеряны. Поэтому пришлось самому разбираться. Видимо DT ждет та же судьба.
В бою не пробовал, но дело вы делаете правидное однозначно!
(0) Отправил Вам pull request на githab в библиотеку — добавил многопоточности при распаковке.
На сильно допиленной ERP2 результат довольно обнадеживающий — порядка 3х минут против 12ти в исходном варианте.
Но на маленьких базах результат, наоборот, ухудшится наверное..
(но там и дельта по времени будет совсем незначительна с другой стороны)
(31)
https://github.com/pruidzeko/onec_dtools
Версия с многопоточностью доступна тут:
(31) Дошли наконец руки нормально посмотреть..
Как я понимаю основной задачей у вас было добиться ускорения распаковки. Вижу, что успех есть, но к коду довольно много претензий.
Во-первых вы используете многопоточность, которая в силу GIL в Python толком не работает. Исключение, на сколько я помню, операции ввода/вывода. Но т.к. в скрипте идет работа с файловой системой, то мы все равно ограничены отсутствием параллельность операций работы с диском (если конечно у вас не NVMe SSD). Единственное, что тут реально можно выполнить параллельно — это разархивация файлов верхнего уровня. Поэтому накидал свой примертут .
Как работает:
— Поднимаем с данные всех внутренних файлов контейнера. Если конфигурация большая, то нужен будет python x64
— Отдаем эту информацию пулу субпроцессов на обработку. Количество процессов берется по числу ядер системы, поэтому тут мы легко получим 100% CPU
— Если распакованный файл не является контейнером, то отдаем данные пишущему процессу. Иначе разбираем его на субфайлы (они уже не будут упакованы).
В целом это должно давать хороший прирост производительности. Хотя Python и скорость работы это вещи слабо совместимые.
P.S. Как-то очень долго у вас ERP распаковывается. Типовая конфигурация (~650МБ) у меня разбирается за ~35 секунд даже в стоковом режиме. Проблема в основном в диске, на самом деле.
О, спасибо!
(33)
Удивили.. у меня на работе, SSD Samsung 970EVO 250Gb на шине PCIe, c NVMe
i5-6400 3.1 ГГц, 8 Гб ОЗУ
Python 3.7 / x64 использовался..
ERP, конечно, была сильно «искаверканная» — но такая разница колоссальная с Вашими данными.. попробую типовую спарсить..
Еще Касперский стоит, но рабочие папки для парсинга в исключениях. Удалить нет никакой возможности из-за политик безопасности.
===
А поделитесь, пожалуйста, Вашей конфигурацией компьютера. Если не сложно, поподробнее.. и используется ли антивирус и какой.
(34) Тестировалось все на относительно старом компе.
Какой-то Касперский с дефолтными настройками стоит.
Вот пример распаковки измененной ERP ~1.2ГБ
Показать
А можно-ли с помощью этой библиотеки тип и версию конфигурации посмотреть? ) Как сформировать запрос чтобы на выходе получить нечто вроде — Бухгалтерия предприятия — 3.0.64.54?..
И еще, не по теме вопроса ) в примере кода из описания у вас написано:
Не должно-ли быть как-то так?:
(36) Извлечь версию конфигурации из контейнера конфигурации можно прочитав внутренний файл root. В нем будет идентификатор файла с нужной вам информацией.
Если надо прямо из конфигурации базы данных информацию получить, то наверное надо ее предварительно прочитать. Полагаю, она где-то в таблице v8config. В общем нужно смотреть и пробовать — это не сложно.
Другое дело что библиотека просто дает базовый функционал работы с контейнерами и прочими файлами платформы. Остальное — это примеры использования. Такого примера, что вас интересует, у меня нет.
А насчет примера в описании: да, в статье ошибка. На github пример содержит корректный код.
(37) Библиотека замечательная и похоже действительно уникальная ) буду вникать по возможности, но пока я не знаком с ней на столько тонко, прошу разъяснить некоторые моменты хотя-бы в общих чертах… Процесс чтения таблицы CONFIG оказался весьма продолжительным, вероятно предпочтительней считывать техническую информацию из root-файла (это один из способов, если я вас правильно понял) и вот вопрос как это сделать или в каком направлении копать?.. )
Запрос — db.tables[‘CONFIG’][40957].as_list(True)
Выдает следующее — [‘root’, datetime.datetime(2018, 7, 11, 12, 0, 38), datetime.datetime(2018, 7, 11, 12, 0, 38), 0, 46, b'{xbf{x7fxb5x91Nxaax81x99x99YJx92x91xaex89ix8ax99xaex89ex92x89nxa2x91x81x81xaex81x99axb2YRxa2yx8axa9x99xa5N-x00′, 0]
Запрос — db.tables[‘CONFIG’][40958].as_list(True)
Выдает примерно тоже самое — [‘version’, datetime.datetime(2018, 7, 11, 12, 0, 38),..
Вероятно это дата создания. дата модификации, еще параметры, и какая-то бинарная строка данных…
(38) А хотя нет, все в порядке ) нашел. действительно не сложно. Спасибо — библиотека отличная.
(38) Бинарные данные просто упакованы zlib. Разбирается так:
Дальше думаю без проблем разберетесь.
(40) Да разобрался. большое спасибо и огромный респект за такой основательный труд. )