合并XPS文件留下打开的文件句柄来记录参考

我通过IIS Web应用程序合并XPS文件,但在合并过程中,它使文档引用文件句柄保持打开状态。 在Windows WPF或控制台应用程序中,我不担心这些句柄,因为它们会在应用程序关闭后发布。 回收应用程序池也会有效地关闭手柄。 但是,由于缓存和性能的原因,我无法仅仅关闭应用程序池来关闭文件句柄。

合并完成后有没有办法关闭这些文件句柄? 我尝试了几种不同的合并方法,但下面的代码给了我最好的结果:

private DocumentPaginator CreateMergedDocument(IEnumerable<string> xpsFiles) {   
  using ( MemoryStream mergedStream = new MemoryStream() ) {
    using ( var pkg = Package.Open( mergedStream, FileMode.Create, FileAccess.ReadWrite ) ) {
      var pack = "pack://merged.xps";
      var uri = new Uri( pack, UriKind.Absolute );
      PackageStore.AddPackage( uri, pkg );
      using ( XpsDocument mergedDocument = 
          new XpsDocument( pkg, CompressionOption.Maximum, pack ) ) {
        FixedDocumentSequence seqNew = new FixedDocumentSequence();

        foreach ( string sourceDocument in xpsFiles ) {
          using ( XpsDocument xpsOld = 
              new XpsDocument( sourceDocument, FileAccess.Read ) ) {
            FixedDocumentSequence seqOld = xpsOld.GetFixedDocumentSequence();

            foreach ( DocumentReference dr in seqOld.References ) {
              DocumentReference newDocumentReference = new DocumentReference();
              newDocumentReference.Source = dr.Source;
              ( newDocumentReference as IUriContext ).BaseUri = 
              ( dr as IUriContext ).BaseUri;
              seqNew.References.Add( newDocumentReference );
            }
          }
        }

        XpsDocumentWriter xpsWriter = XpsDocument.CreateXpsDocumentWriter( mergedDocument );
        xpsWriter.Write( seqNew );

        PackageStore.RemovePackage( uri );

        return seqNew.DocumentPaginator;
      }
    }
  }
}

我跟踪了打开xpsWriter.Write(seqNew)代码行的文件句柄。 这是预期的,因为它需要加载文件以复制到新的FixedDocumentSequence 。 但是,如果XpsDocumentWriter是一次性的并清理其非托管资源/文件句柄,那将会很不错。

在我的研究中,我尝试了其他一些方法。 我尝试过的一种方法是将每个页面直观地写入SerializerWriterCollator 。 我研究过的另一种方法是处理FixedPage内容,并将URI更新为复制的图像和字体流,并将原始XAML写回到XmlWriter 。 没有太好的工作。 使用页面可视SerializerWriterCollatorSerializerWriterCollator ,我在合并的XPS上获得了不正确的页面大小,并且它正在切断内容。 使用原始的XmlWriter方法,它混淆了合并XPS中的一些图像,并错误地显示了一些页面内容。


经过一番更多的研究后,我发现用于在STA线程中运行我的函数的原始代码没有正确释放文件句柄和非托管资源。 我们有一个自定义线程类,它具有调用一个动作并在线程上运行连接的自定义实现。 操作方法完成后,线程未正确退出。 为了解决这个问题,我把代码封装在一个类似于下面的代码块中:

private static readonly TaskScheduler _staScheduler = new StaTaskScheduler( 1 );

[Route( "merge" )]
[HttpGet]
public async Task<HttpResponseMessage> MergeXps() {
  var paginator = await Task<DocumentPaginator>.Factory.StartNew(
    () =>
      {
        var xpsFiles = Directory.GetFiles( "C:Xps", "*.xps" );
        var documentPaginator = CreateMergedDocument( xpsFiles );

        return documentPaginator;
      },
    CancellationToken.None,
    TaskCreationOptions.None,
    _staScheduler );

  var response = new HttpResponseMessage();
  response.Content = new StringContent( $"Merged Document Page Count: {paginator.PageCount}" );
  response.StatusCode = HttpStatusCode.OK;
  return response;
}
链接地址: http://www.djcxy.com/p/40553.html

上一篇: Merging XPS files leaves open file handles to document references

下一篇: How to delete files programatically?