Word com объект не работает - PullRequest
0 голосов
/ 19 декабря 2018

НАЗНАЧЕНИЕ СКРИПТА

Идея сценария состоит в том, чтобы рекурсивно извлечь текст из большого количества документов и обновить поле в базе данных SQL Azure, используя извлеченный текст.В основном мы переходим от поиска документов по содержимому Windows к полнотекстовому поиску SQL для повышения скорости.

ВЫПУСК

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

foreach ($list in (Get-ChildItem ( join-path $PSScriptRoot "\FileLists\*" ) -include *.txt )) {

    ## Word object
    $word = New-Object -ComObject word.application
    $word.Visible = $false
    $saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatText")
    $word.DisplayAlerts = 0


    Write-Output ""
    Write-Output "################# Parsing $list"
    Write-Output ""

    $query = "INSERT INTO tmp_CachedText (tCachedText, tOID)
              VALUES "

    foreach ($file in (Get-Content $list)) {
        if ($file -like "*-*" -and $file -notlike "*~*") {

            Write-Output "Processing: $($file)"
            Try {
                $doc = $word.Documents.OpenNoRepairDialog($file, $false, $false, $false, "ttt")

                if ($doc) {
                    $fileName = [io.path]::GetFileNameWithoutExtension($file)
                    $fileName = $filename + ".txt"
                    $doc.SaveAs("$env:TEMP\$fileName", [ref]$saveFormat)
                    $doc.Close()


                    $4ID = $fileName.split('-')[-1].replace(' ', '').replace(".txt", "")
                    $text = Get-Content -raw "$env:TEMP\$fileName"
                    $text = $text.replace("'", "''")

                    $query += "
                    ('$text', $4ID),"
                    Remove-Item -Force "$env:TEMP\$fileName"

                    <# Upload to azure #>
                    $query = $query.Substring(0,$query.Length-1)
                    $query += ";"

                    Invoke-Sqlcmd @params -Query $Query -ErrorAction "SilentlyContinue"

                    $query = "INSERT INTO tmp_CachedText (tCachedText, tOID)
                      VALUES "
                }
            }
            Catch {
                Write-Host "$($file) failed to process" -ForegroundColor RED;
                continue
            }
        }
    }
    Remove-Item -Force $list.FullName


    Write-Output ""
    Write-Output "Uploading to azure"
    Write-Output ""


    <# Upload to azure #>
    Invoke-Sqlcmd @params -Query $setQuery -ErrorAction "SilentlyContinue"


    $word.Quit()
    TASKKILL /f /PID WINWORD.EXE
}

По сути, он анализирует папку с файлами .txt, которые содержат x количество путей к документам, создает инструкцию обновления T-SQL и работает сБаза данных SQL Azure после полного анализа каждого файла.Файлы генерируются следующим образом:

if (!($continue)) {
    if ($pdf){
        $files = (Get-ChildItem -force -recurse $documentFolder -include *.pdf).fullname
    }
    else {
        $files = (Get-ChildItem -force -recurse $documentFolder -include *.doc, *.docx).fullname
    }


    $files | Out-File (Join-Path $PSScriptRoot "\documents.txt")
    $i=0; Get-Content $documentFile -ReadCount $interval | %{$i++; $_ | Out-File (Join-Path $PSScriptRoot "\FileLists\documents_$i.txt")}
}

Переменная $ interval определяет, сколько файлов должно быть извлечено для каждой конкретной загрузки в Azure.Первоначально у меня был объект слова, созданный вне цикла, и никогда не закрывался до конца.К сожалению, это, похоже, не работает, так как каждый раз, когда скрипт попадает в файл, который он не может открыть, каждый последующий файл завершится ошибкой, пока не достигнет конца внутреннего цикла foreach foreach ($file in (Get-Content $list)) {.

Это означает, что для получения ожидаемого результата мне нужно запустить его с интервалом 1, который занимает слишком много времени.

Ответы [ 2 ]

0 голосов
/ 19 декабря 2018

Это выстрел в темноте

Но для меня это звучит так, как будто причина его неудачи в том, что объект Word Com теперь запрашивает какое-то действие из-за невозможности открыть файл, поэтому все последующие элементыв цикле тоже не получится.Это может объяснить, почему это работает, если вы установите $Interval в 1, потому что когда его 1, он закрывается и открывает объект Com каждый раз, и это занимает вечность (я делал это с Excel).

Что вы можетеdo находится в вашем операторе catch, закройте и откройте новый объект Word Com, который должен позволить вам продолжить цикл (но он будет немного медленнее, если потребуется многократно открывать объект Com).

Если вы хотите еще больше отладить проблему, установите объект Com видимым и медленно просматривайте вашу программу, не взаимодействуя с Word.Это покажет вам, что происходит с Word, и если есть какие-либо подсказки, которые вызывают зависание приложения.

Конечно, если вы хотите запустить его на полной скорости, вам нужно будет определить, какие документы вы не можете открыть до этого, или вы могли бы использовать многопоточность, открыв несколько объектов Word Com, которые позволят вам загрузитьнесколько документов одновременно.

0 голосов
/ 19 декабря 2018

Что касается ...

ПРОБЛЕМА

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

... затем проверьте это, как указано здесь ...

Как проверить, есть ли пароль для файла слова?

$filename = "C:\path\to\your.doc"

$wd = New-Object -COM "Word.Application"

try {
  $doc = $wd.Documents.Open($filename, $null, $null, $null, "")
} catch {
  Write-Host "$filename is password-protected!"
}

...и пропустите файл, чтобы избежать сбоя оставшихся файлов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...