Тема: Программный доступ с свойствам чертежа (аналог dwgprops)

Доброго времени суток всем!
Есть потребность перебирать dwg файлы в определенной папке и основываясь на дате создания чертежа выполнять с ним определенные действия.
Путем экспериментов удалось выяснить что дата создания чертежа, отображаемая операционной системой, не всегда корректна, в то время как дата отображаемая на вкладке "статистика" в свойствах файла вроде бы то, что нужно (ибо мне нужна именно дата создания чертежа и не пересохранения).
Нашел возможность получать эту дату через свойство DataBase.TDCreate (TDUCreate), но для получения этого свойства приходится открывать чертеж. В папке, которую надо проверять а данный момент более 15 000 чертежей и открывать каждый для проверки этой даты не хотелось бы.
Так вот сам вопрос:
Можно ли получить дату создания чертежа, которая отображена на вкладке "статистика" свойств чертежа (или в свойства TDCreate) не открывая сам чертеж? (ведь ОС эти данные как-то отображает, видимо используя какую-нибудь библиотеку...)

PS: В качестве языка программирования пользуюсь C#, программа для перебора файлов в папке оформлена как плагин для autocad (dll)
PPS: С# только изучаю...

Re: Программный доступ с свойствам чертежа (аналог dwgprops)

Это информация, специфичная для AutoCAD. Т.е. ты будешь видеть эту вкладку только если у тебя установлен AutoCAD. Соответственно и читать обозначенную информацию следует с помощью API, предоставляемого Autodesk. Иными словами - только через загрузку базы данных чертежа. Открывать чертёж нет необходимости.

Re: Программный доступ с свойствам чертежа (аналог dwgprops)

ohitmano пишет:

Можно ли получить дату создания чертежа, которая отображена на вкладке "статистика" свойств чертежа (или в свойства TDCreate) не открывая сам чертеж? (ведь ОС эти данные как-то отображает, видимо используя какую-нибудь библиотеку...)

Можно. И можно даже без установленного AutoCAD: http://www.theswamp.org/index.php?topic … #msg415688

Re: Программный доступ с свойствам чертежа (аналог dwgprops)

Спасибо за ответы. Может кому пригодится, выкладываю написанный на с# проект для чтения метаданных dwg файла без использования autocad. Это почти полный копипаст с темы ссылка из предыдущего поста , просто переписанный на c#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace DwgMetadataRead
{
    //Данный материал основан на текстах из форума по дресу http://www.theswamp.org/index.php?topic=36419.msg415688#msg415688
    class Program
    {
        static void Main(string[] args)
        {
            Dictionary<string, string> dwgFileMetadataInfo = new Dictionary<string, string>();
            ReadData(@"D:\temp\test.dwg", dwgFileMetadataInfo);
            foreach( string s in dwgFileMetadataInfo.Keys)
                Console.WriteLine("{0} --> {1}", s, dwgFileMetadataInfo[s]);
        }
        static void ReadData(string fileName, Dictionary<string, string> dwgFileMetadataInfo)
        {
            using (FileStream fs = new FileStream(fileName, FileMode.Open))
            {
                using (BinaryReader br = new BinaryReader(fs))
                {
                    //Первые 6 байт в файле акада представляют версию в которой был сохранен файл
                    string acadVersion = new string(br.ReadChars(6));
                    int acadVersionNUmber;
                    bool isUnicode = true;
                    switch (acadVersion)
                    {
                        case "AC1027":
                            acadVersionNUmber = 2013;
                            break;
                        case "AC1024":
                            acadVersionNUmber = 2010;
                            break;
                        case "AC1021":
                            acadVersionNUmber = 2007;
                            break;
                        case "AC1018":
                            acadVersionNUmber = 2004;
                            isUnicode = false;
                            break;
                        //Поддержка формата Autocad 2000 отсутсвует, ибо мне он не нужен, сори.
                        //case "AC1015":
                        //    acadVersionNUmber = 2000;
                        //    break;
                        default:
                            throw new ApplicationException("Файл данной версии AUTOCAD не поддерживается или он создан не в ПО AUTOCAD");
                            //break;
                    }
                    //Console.WriteLine("{0} --> {1}", acadVersion, acadVersionNUmber);
                    dwgFileMetadataInfo.Add("acad version", acadVersionNUmber.ToString());
                    //По адресу 0х20 в фале акада находится значение, которое содердит адрес по которому
                    //начинаются метаданые файла (немного запутанно, но как есть)
                    fs.Seek(0x20, SeekOrigin.Begin);
                    //Считаем адрес в переменную
                    uint si = br.ReadUInt32();
                    //переместимся по адрусу, который находится в переменной si
                    fs.Seek(si, SeekOrigin.Begin);
                    /* Теперь считаем метаданные файла именно в строго определенном порядке:
                     * title, subject, author, keywords, comments, lastSavedBy, revisionNumber??, hyperlinkBase */
                    if (isUnicode)
                        FillDict(dwgFileMetadataInfo, br, ReadUnicode);
                    else FillDict(dwgFileMetadataInfo, br, ReadASCII);
                    /* Сразу за полем hyperlinkBase в фале идут данные про время редактирования
                     * время создания и время последнего изменения
                     * данные имеют формат: <Юлианская дата (JDN)>.<кол-во милисекунд>
                     * Каждое значение предстваляет собой 4х байтовое число
                     * Нам придется сконвертировать юлианскую дату в григорианскую
                     * JDN даст нам дату, а милисекунды - время */
                    uint tet1 = br.ReadUInt32();//Время редактирования файла JDN = на всех моих файлах это значение было равно 1
                    uint tet2 = br.ReadUInt32();//Нас по идее интересуют только милисекунды
                    uint cdt1 = br.ReadUInt32();//Время создания файла JDN
                    uint cdt2 = br.ReadUInt32();//Время создания файла милисекунды
                    uint mdt1 = br.ReadUInt32();//Время последнего изменения файла JDN
                    uint mdt2 = br.ReadUInt32();//Время последнего изменения файла милисекунды
                    //Добавим в словарь даты, кроме времени редактирования, мне она не интересна
                    dwgFileMetadataInfo.Add("creation date", String.Format("{0:yyyy-MM-dd HH:mm}", CalculateDates(cdt1, cdt2)));
                    dwgFileMetadataInfo.Add("modification date", String.Format("{0:yyyy-MM-dd HH:mm}", CalculateDates(mdt1, mdt2)));
                }
            }

        }
        private static string ReadUnicode(BinaryReader br)
        {
            //Считаем длинну в байтах следующего поля
            int len = br.ReadInt16();
            if (len > 0)
            {
                Char[] buffer = new Char[len];
                for (int i = 0; i < len; i++)
                {
                    //Так как символ юникода представляется 2мя байтами, то использует функцию ReadInt16
                    //Сконвертируем полученное число в символ и запишем в массив
                    buffer[i] = Convert.ToChar(br.ReadInt16());
                }
                //Соберем из массива символов строку, убрав лишний мусор
                return new String(buffer).TrimEnd(Convert.ToChar(0));
            }
            else
                return String.Empty;
        }
        private static string ReadASCII(BinaryReader br)
        {
            //Считаем длинну в байтах следующего поля
            int len = br.ReadInt16();
            if (len > 0)
            {
                //Прочитаем всю строку целиком и уберем лишний мусор
                string s = Encoding.ASCII.GetString(br.ReadBytes(len));
                return s.TrimEnd(Convert.ToChar(0));
            }
            else
                return String.Empty;
        }
        private static DateTime CalculateDates(long jdInt, long jdFrac)
        {
            /* Функция служит для конвертации юлианской даты в григорианскую
             * не желательно использовать для вычисления общего времени редактирования
             * Материал взят с сайта http://krutov.org/algorithms/julianday/, также были исправлены опечатки в тексте */
            long A, B, C, D, E, monthNumber, yearNumber;// Просто промедуточные коэффициенты
            double dayOfMonth;
            if (jdInt < 2299161)
            {
                A = jdInt;
            }
            else
            {
                long a = (long)((jdInt - 1867216.25)/36524.25);
                A = jdInt + 1 + a - (long)(a/4);
            }
            B = A + 1524;
            C = (long)((B - 122.1)/365.25);
            D = (long)(365.25*C);
            E = (long)((B - D)/30.6001);
            dayOfMonth = Convert.ToDouble(String.Format("{0},{1}", (B - D - (long)(30.6001 * E)), jdFrac));
            if ((E == 14) || (E == 15)) monthNumber = E-13;
                else if (E < 14) monthNumber = E-1;
            else monthNumber = 0;
            if (monthNumber > 2) yearNumber = C - 4716;
            else if (monthNumber == 2 || monthNumber == 1)
                yearNumber = C - 4715;
            else yearNumber = 0;
            //Console.WriteLine("{0:yyyy-MM-dd HH:mm}", new DateTime(year: (int)yearNumber, month: (int)monthNumber, day: (int)dayOfMonth).AddMilliseconds(jdFrac).ToLocalTime());
            return new DateTime(year: (int)yearNumber, month: (int)monthNumber, day: (int)dayOfMonth).AddMilliseconds(jdFrac).ToLocalTime();
        }
        private static void FillDict(Dictionary<string, string> dict, BinaryReader br, Func<BinaryReader, string> fillFunc)
        {
            //Поскольку мы имеем 8 полей, то вызываем функцию считывания 8 раз
            dict.Add("title", fillFunc(br));
            dict.Add("subject", fillFunc(br));
            dict.Add("author", fillFunc(br));
            dict.Add("keywords", fillFunc(br));
            dict.Add("comments", fillFunc(br));
            dict.Add("lastSavedBy", fillFunc(br));
            dict.Add("revisionNumber", fillFunc(br));
            dict.Add("hyperlinkBase", fillFunc(br));
        }
    }
}
Hwd пишет:

Это информация, специфичная для AutoCAD. Т.е. ты будешь видеть эту вкладку только если у тебя установлен AutoCAD. Соответственно и читать обозначенную информацию следует с помощью API, предоставляемого Autodesk. Иными словами - только через загрузку базы данных чертежа. Открывать чертёж нет необходимости.

Подскажите пожалуйста, как можно просто загрузить базу данных чертежа без его открытия.

Re: Программный доступ с свойствам чертежа (аналог dwgprops)

ohitmano пишет:

Подскажите пожалуйста, как можно просто загрузить базу данных чертежа без его открытия.

В этом примере можно глянуть, как экспортировать определение блока из чертежа, не открывая его. Там как раз используется загрузка базы данных без открытия документа.

Re: Программный доступ с свойствам чертежа (аналог dwgprops)

Спасибо за ответ.. слона-то я и не заметил.. третий день на этом сайте, а этой статейки не заметил..