Как читать «расширенные» теги файлов MS Word без Office.Interop?

У меня есть файл .docx с пользовательскими свойствами, указанными только для файлов MS Office. Свойства файла

Если я попытался открыть тот же файл на компьютере без установленного MS Office, то на вкладке сведений о файле нет свойства «Теги».

Мне нужно прочитать Tags в моем коде С#.

Я попробовал это решение и получил индекс Tags как 18. Затем я использовал следующий код:

public class TagsReader : ITagsReader
{
    private const int keywordsIndex = 18;

    public string Read(string filePath)
    {
        var fullPath = Path.GetFullPath(filePath);

        var directoryName = Path.GetDirectoryName(fullPath);
        Folder dir = GetShell32Folder(directoryName);
        var fileName = Path.GetFileName(fullPath);

        FolderItem item = dir.ParseName(fileName);
        return dir.GetDetailsOf(item, keywordsIndex);
    }

    private Folder GetShell32Folder(string folderPath)
    {
        var shellAppType = Type.GetTypeFromProgID("Shell.Application");
        var shell = Activator.CreateInstance(shellAppType);
        return (Folder)shellAppType.InvokeMember("NameSpace",
        BindingFlags.InvokeMethod, null, shell, new object[] { folderPath });
    }
}

Но это не работает для компьютеров без установленного MS Office. Он работает только для .doc файлов, но не для .docx. Сейчас я использовал решение на основе Interop, которое не стабильно, ресурсоёмко и требует установки MS Office на сервер:

public class WordTagsReader : ITagsReader
{
    private readonly string[] availableFileExtensions = { ".docx" };
    public string Read(string filePath)
    {
        var fileExtension = Path.GetExtension(filePath);
        if (!availableFileExtensions.Contains(fileExtension))
            return null;

        dynamic application = null;
        dynamic document = null;
        var tags = string.Empty;
        try
        {
            var typeWord = Type.GetTypeFromProgID("Word.Application");
            application = Activator.CreateInstance(typeWord);
            application.Visible = false;
            application.DisplayAlerts = false;
            var fullFilePath = Path.GetFullPath(filePath);
            document = application.Documents.Open(fullFilePath);
            tags = document.BuiltInDocumentProperties["Keywords"].Value;
        }
        finally
        {
            if (document != null)
            {
                document.Close();
                document = null;
            }
            if (application != null)
            {
                application.Quit();
                application = null;
            }
        }

        return tags;
    }
}

Этот код может время от времени давать сбои и оставлять запущенные экземпляры MS Word, которые потребляют ресурсы и блокируют файл. У меня много обработчиков работало одновременно и потом я не могу отделить "левые" инстансы от нормально отработанных и чистых ресурсов.

Это причина поиска альтернативного решения. Есть ли способ прочитать определенные (пользовательские) свойства, такие как Tags, без использования Office.Interop?


person Vadim Martynov    schedule 15.02.2016    source источник
comment
ТС всем за ответы.   -  person Vadim Martynov    schedule 15.02.2016


Ответы (3)


Вы можете использовать теплую лампу для чтения в формате .docx. Что-то вроде этого:

using System.IO.Packaging;

var package = Package.Open(ms, FileMode.Open, FileAccess.ReadWrite);
var corePart = package.GetPart(new Uri("/docProps/core.xml", UriKind.Relative))
XDocument settings;
using (TextReader tr = new StreamReader(settingsPart.GetStream()))
    settings = XDocument.Load(tr);

XNamespace cp = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties"
var tags = settings.Root.Element(cp + "keywords");

Нет необходимости использовать дополнительные библиотеки или SDK. Только System.IO, только хардкор!

person Alexey Trofimuk    schedule 15.02.2016
comment
Нужно ли вообще получать часть (точно не знаю)? Как насчет var tags = package.PackageProperties.Keywords; - person ; 15.02.2016

Я предлагаю использовать Open Xml SDK для этого open xml является «новым» стандартом для офиса. Чтение тегов будет возможно с помощью этого кода: (обратите внимание, что для этого вам нужно использовать пространство имен DocumentFormat.OpenXml.Packaging)

string tags = "";
using(var doc = WordProcessingDocument.Open("filename",false)
    tags = doc.PackageProperties.KeyWords;

Использование open xml не требует установки каких-либо офисных приложений на компьютере, поэтому он идеально подходит для использования на серверах или в вашем примере для чтения/редактирования документов на компьютерах, на которых не установлен офис.

person Alexander Derck    schedule 15.02.2016
comment
Я протестирую ваше решение как можно скорее сегодня, TY. - person Vadim Martynov; 15.02.2016
comment
Спасибо Вам за Ваш вопрос. Сначала я был удивлен, что мне нужно добавить WindowsBase .dll для использования OpenXml SDK. Кроме того, я получаю FileFormatException (Файл содержит поврежденные данные.) для файла, который правильно открылся с помощью Interop. Я не могу изменить формат файла, потому что это входной поток документов от наших клиентов. Могу ли я использовать Open XML с файлами, созданными в MS Word и сохраненными в формате .docx? - person Vadim Martynov; 15.02.2016
comment
Открытый xml предназначен только для файлов docx, единственный способ преобразовать doc в docx (afaik) - это открыть его и сохранить с помощью слова: / Если вы имеете дело со старыми документами, то вашим единственным решением будет интероп, я боюсь. - person Alexander Derck; 15.02.2016
comment
У меня нет проблем с доком. Кроме того, я протестировал и ваше решение, и решение @AlexeyTrofimuk, и оно отлично работает, большое спасибо. OpenXml — действительно большая библиотека, и я не хочу добавлять эту ссылку только для одной нетипичной операции, и для меня лучше использовать ручной анализ. В следующий раз я буду использовать OpenXml для подобных задач, потому что это действительно благодарная библиотека! - person Vadim Martynov; 15.02.2016
comment
@VadimMartynov Да, вы можете делать почти все с SDK. Но это действительно довольно массивно, если вам нужно только проверить теги - person Alexander Derck; 15.02.2016

В настоящее время корпорация Майкрософт не рекомендует и не поддерживает автоматизацию приложений Microsoft Office из любого автоматического неинтерактивного клиентского приложения или компонента (включая ASP, ASP.NET, DCOM и службы NT), поскольку Office может работать нестабильно. поведение и/или взаимоблокировка при запуске Office в этой среде.

Если вы создаете решение, работающее в контексте на стороне сервера, вы должны попытаться использовать компоненты, которые были сделаны безопасными для автоматического выполнения. Или вы должны попытаться найти альтернативы, которые позволяют хотя бы части кода выполняться на стороне клиента. Если вы используете приложение Office из решения на стороне сервера, у приложения не будет многих необходимых возможностей для успешной работы. Кроме того, вы рискуете стабильностью всего решения. Подробнее об этом читайте в статье Соображения по автоматизации Office на стороне сервера.

В качестве временного решения вы можете использовать Open XML SDK, см. Welcome to the Open XML SDK 2.5 для Office для получения дополнительной информации. Или используйте любые сторонние компоненты, предназначенные для выполнения на стороне сервера. Например, взгляните на Aspose.

person Eugene Astafiev    schedule 15.02.2016