将Word doc/docx文件转换为PDF时,File System Watcher停止工作 [英] File System Watcher stops working when converting Word doc/docx files to PDF

查看:189
本文介绍了将Word doc/docx文件转换为PDF时,File System Watcher停止工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Powershell脚本,用于将 .doc/ .docx文件自动转换为* .pdf. 该脚本对于第一个文件运行良好.但是,如果我将另一个文件放在监视的文件夹中,则监视程序不会触发事件.

I have a Powershell script for automatic converting .doc/.docx files to *.pdf. The script is running well for the first file. But if I put another file in the watched folder, the watcher doesn't trigger an event.

这是完整的脚本.如果我注释掉所有$ doc变量,则脚本可以多次运行而不会出现任何问题.我是否忽略/忽略了某些东西?

Here is the complete script. If I comment out the all $doc variables, the script is running multiple times without any problems. Did I ignore/overlook something?

$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "$Env:DropboxRoot"
$watcher.Filter = "*.doc*"
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true

Add-type -AssemblyName Microsoft.Office.Interop.Word


$action  = {

$name = (get-item $Event.SourceEventArgs.FullPath).BaseName

### DON'T PROCESS WORD BACKUP FILES (START WITH A TILDE ~)
if(!($name.startsWith("~"))){

    write-host Triggered event from $Event.SourceEventArgs.FullPath
    $inputFilePath = $Event.SourceEventArgs.FullPath

    $parentPath = (get-item $inputFilePath).Directory
    $filename = (get-item $inputFilePath).BaseName
    $pdfDir = "$parentPath\PDF"

    if(!(Test-Path -Path $pdfDir)){
        New-Item -ItemType directory -Path $pdfDir
    }

    ###Execute PDF generate script
    write-host Create word object
    $word = New-Object -ComObject "Word.Application"


    ######define the parameters######
    write-host Define parameters
    $wdExportFormat =[Microsoft.Office.Interop.Word.WdExportFormat]::wdExportFormatPDF

    $OpenAfterExport = $false

    $wdExportOptimizeFor = [Microsoft.Office.Interop.Word.WdExportOptimizeFor]::wdExportOptimizeForOnScreen
    $wdExportItem = [Microsoft.Office.Interop.Word.WdExportItem]::wdExportDocumentContent
    $IncludeDocProps = $true
    $KeepIRM = $false #Don't export Inormation Rights Management informations
    $wdExportCreateBookmarks = [Microsoft.Office.Interop.Word.WdExportCreateBookmarks]::wdExportCreateWordBookmarks #Keep bookmarks
    $DocStructureTags = $true #Add additional data for screenreaders
    $BitmapMissingFonts = $true 
    $UseISO19005_1 = $true #Export as PDF/A

    $outputFilePath = $pdfDir + "\" + $filename + ".pdf" 


    $doc = $word.Documents.Open($inputFilePath)
     $doc.ExportAsFixedFormat($OutputFilePath,$wdExportFormat,$OpenAfterExport,`
                     $wdExportOptimizeFor,$wdExportRange,$wdStartPage,$wdEndPage,$wdExportItem,$IncludeDocProps,`
                    $KeepIRM,$wdExportCreateBookmarks,$DocStructureTags,$BitmapMissingFonts,$UseISO19005_1)

    $doc.Close()
    $word.Quit()

    [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($doc)
    [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($word)
    [GC]::Collect()
    [GC]::WaitForPendingFinalizers()    

 }
}

$created = Register-ObjectEvent $watcher -EventName "Created" -Action    $action
$renamed = Register-ObjectEvent $watcher -EventName "Renamed" -Action $action


while($true) {
    sleep 5
}`

推荐答案

您的脚本存在一些问题,可以找到更多的调试逻辑.

Your script has a few issues, that more debugging logic could find.

在某些情况下,(Get-Item System.Management.Automation.PSEventArgs.SourceEventArgs.FullPath)返回null.由于未知原因,似乎每个转换的文档都会发生一次.也许与〜Temp"文件有关.

In some cases, (Get-Item System.Management.Automation.PSEventArgs.SourceEventArgs.FullPath) returns null. For unknown reasons, this seems to happen once for every document that gets converted. Perhaps it has to do with the "~Temp" files.

随后,if(!($name.startsWith("~")将引发异常.

使用$inputFilePath = $Event.SourceEventArgs.FullPath时,您的变量是FileInfo,实际上您想将字符串传递给$word.Documents.Open($inputFilePath).

When you use $inputFilePath = $Event.SourceEventArgs.FullPath, your variable is a FileInfo, and really you want to pass a string to $word.Documents.Open($inputFilePath).

最后,有时BaseName为null.不知道为什么,但是代码可以对此进行测试,也可以使用其他方法剖析FullPath以获取名称和路径部分.

Lastly, sometimes BaseName is null. Not sure why but the code could test for that or use other means to dissect the FullPath to get names and path parts.

所有这些,一旦您开始使用,我的个人经验就是,在PowerShell上在Word上调用COM对象进行此转换是不可靠的(Word挂起,〜Temp文件被获取留下来的话,您必须从任务管理器中删除Word,PowerShell中的COM调用将永远不会返回).我的测试表明,调用C#控制台应用程序进行转换要可靠得多.您可以完全使用C#编写此目录监视程序和转换器,并完成相同的任务.

All that said, once you get this working, my personal experience is that calling the COM object on Word to do this conversion in PowerShell is unreliable (Word hangs, ~Temp files get left behind, you have to kill Word from task manager, the COM calls in PowerShell never return). My testing shows that calling a C# console app to do the conversion is much more reliable. You could write this directory watcher and converter completely in C# and accomplish the same task.

假设您仍然想将PowerShell观察器和C#Word转换为PDF转换器两者结合起来,以下是我想出的解决方案.该脚本运行大约一分钟,因此您可以在ISE或控制台中进行测试.从控制台按一个键退出.在退出之前,脚本会通过注销事件来干净地退出,这在ISE中进行测试时非常有帮助. 针对您打算如何运行脚本进行相应的更改.

Assuming you still want to combine the two, a PowerShell watcher, and a C# Word to PDF converter, below is a solution I came up with. The script runs for about a minute so you can test in the ISE or Console. From the Console press a key to exit. Before exiting, the script exits cleanly by unregistering the events which is quite helpful while testing in the ISE. Change this accordingly for how you intend to run the script.

PowerShell监视程序

$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "d:\test\docconvert\src"
$watcher.Filter = "*.doc*"
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true

# copy this somehwere appropriate
# perhaps in same directory as your script
# put on a read-only share, etc.
$wordToPdf = 'd:\test\docconvert\WordToPdf\WordToPdf\bin\Debug\WordToPdf.exe'

$action  = {
    try 
    {
        Write-Host "Enter action @ $(Get-Date)"

        $fullPathObject = (Get-Item $Event.SourceEventArgs.FullPath)

        if (!($fullPathObject))
        {
            Write-Host "(Get-Item $Event.SourceEventArgs.FullPath) returned null."
            return
        }

        $fullPath = ($fullPathObject).ToString()
        Write-Host "Triggered event from $fullPath"

        $fileName = Split-Path $FullPath -Leaf

        if ($fileName -and ($fileName.StartsWith("~")))
        {
            Write-Host "Skipping temp file"
            return
        }

        # put pdf in same dir as the file
        # can be changed, but a lot easier to test this way
        $pdfDir = Split-Path $FullPath -Parent
        $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileName)
        $outputFilePath = Join-Path $pdfDir $($baseName + ".pdf")
        Write-Host "outputFilePath is: '$outputFilePath'"

        # call c# WordToPdf to do conversion because
        # it is way more reliable than similar calls
        # from PowerShell
        & $wordToPdf $fullPath $outputFilePath

        if ($LASTEXITCODE -ne 0)
        {
            Write-Host "Conversion result: FAIL"
        }
        else
        {
            Write-Host "Conversion result: OK"
        }
    }
    catch
    {
        Write-Host "Exception from ACTION:`n$($_ | Select *)"
    }
    finally
    {
        Write-Host "Exit action @ $(Get-Date)"
    }
}

$created = Register-ObjectEvent $watcher -EventName "Created" -Action $action
$renamed = Register-ObjectEvent $watcher -EventName "Renamed" -Action $action

$count = 12
while($count--) {
    Write-Output "run/sleep ($count)..."
    sleep 5

    # will exit from console, not ISE
    if ([console]::KeyAvailable) {
        $key = [console]::ReadKey()
        break
    }
}

$created | % {Unregister-Event $_.Name}
$renamed | % {Unregister-Event $_.Name}

C#WordToPdf转换器

为参数添加适当的错误检查...

添加对COM Microsoft.Office.Interop.Word

using System;
using Microsoft.Office.Interop.Word;

namespace WordToPdf
{
    class Program
    {
        static int Main(string[] args)
        {
            Console.WriteLine($"Converting: {args[0]} to {args[1]}");
            var conversion = new DocumentConversion();
            bool result = conversion.WordToPdf(args[0], args[1]);

            if (result)
            {
                return 0;
            }
            else {
                return 1;
            }
        }
    }

    public class DocumentConversion
    {
        private Microsoft.Office.Interop.Word.Application Word;
        private object Unknown = Type.Missing;
        private object True = true;
        private object False = false;

        public bool WordToPdf(object Source, object Target)
        {
            bool ret = true;

            if (Word == null) Word = new Microsoft.Office.Interop.Word.Application();

            try
            {
                Word.Visible = false;
                Word.Documents.Open(ref Source, ref Unknown,
                     ref True, ref Unknown, ref Unknown,
                     ref Unknown, ref Unknown, ref Unknown,
                     ref Unknown, ref Unknown, ref Unknown,
                     ref Unknown, ref Unknown, ref Unknown,
                     ref Unknown, ref Unknown);
                Word.Application.Visible = false;
                Word.WindowState = WdWindowState.wdWindowStateMinimize;

#if false
                object saveFormat = Microsoft.Office.Interop.Word.WdSaveFormat.wdFormatPDF;

                Word.ActiveDocument.SaveAs(ref Target, ref saveFormat,
                    ref Unknown, ref Unknown, ref Unknown,
                    ref Unknown, ref Unknown, ref Unknown,
                    ref Unknown, ref Unknown, ref Unknown,
                    ref Unknown, ref Unknown, ref Unknown,
                    ref Unknown, ref Unknown);
#else
                Word.ActiveDocument.ExportAsFixedFormat(
                    (string)Target, WdExportFormat.wdExportFormatPDF,
                    false, WdExportOptimizeFor.wdExportOptimizeForOnScreen,
                    WdExportRange.wdExportAllDocument, 0, 0,
                    WdExportItem.wdExportDocumentContent, true, false,
                    WdExportCreateBookmarks.wdExportCreateWordBookmarks,
                    true, true, true);
#endif
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                ret = false;
            }
            finally
            {
                if (Word != null)
                {
                    // close the application
                    Word.Quit(ref Unknown, ref Unknown, ref Unknown);
                }
            }

            return ret;
        }
    }
}

这篇关于将Word doc/docx文件转换为PDF时,File System Watcher停止工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆