如何从pdf文件中提取附件

本文关键字:提取 文件 pdf | 更新日期: 2023-09-27 17:58:47

我有大量的pdf文档,其中附有xml文件。我想提取那些附加的xml文件并阅读它们。我如何使用.net程序化地完成这项工作?

如何从pdf文件中提取附件

iTextSharp还能够提取附件。。。尽管你可能不得不使用低级别的对象来做到这一点。

在PDF中嵌入文件有两种方法:

  1. 在文件注释中
  2. 在文档级别"EmbeddedFiles"

一旦您有了来自任一源的文件规范字典,文件本身将是字典中标记为"EF"(嵌入式文件)的流。

因此,要在文档级别列出所有文件,可以(用Java)编写这样的代码:

Map<String, byte[]> files = new HashMap<String,byte[]>();
PdfReader reader = new PdfReader(pdfPath);
PdfDictionary root = reader.getCatalog();
PdfDictionary names = root.getAsDict(PdfName.NAMES); // may be null
PdfDictionary embeddedFilesDict = names.getAsDict(PdfName.EMBEDDEDFILES); //may be null
PdfArray embeddedFiles = embeddedFilesDict.getAsArray(PdfName.NAMES); // may be null
int len = embeddedFiles.size();
for (int i = 0; i < len; i += 2) {
  PdfString name = embeddedFiles.getAsString(i); // should always be present
  PdfDictionary fileSpec = embeddedFiles.getAsDict(i+1); // ditto
  PdfDictionary streams = fileSpec.getAsDict(PdfName.EF);
  PRStream stream = null;
  if (streams.contains(PdfName.UF))
    stream = (PRStream)streams.getAsStream(PdfName.UF);
  else
    stream = (PRStream)streams.getAsStream(PdfName.F); // Default stream for backwards compatibility
  if (stream != null) {
    files.put( name.toUnicodeString(), PdfReader.getStreamBytes((PRStream)stream));
  }
}

这是一个老问题,尽管如此,我认为我的替代解决方案(使用PDF小丑)可能会引起一些兴趣,因为它比以前提出的代码片段更干净(更完整,因为它在文档和页面级别都进行了迭代)

using org.pdfclown.bytes;
using org.pdfclown.documents;
using org.pdfclown.documents.files;
using org.pdfclown.documents.interaction.annotations;
using org.pdfclown.objects;
using System;
using System.Collections.Generic;
void ExtractAttachments(string pdfPath)
{
  Dictionary<string, byte[]> attachments = new Dictionary<string, byte[]>();
  using(org.pdfclown.files.File file = new org.pdfclown.files.File(pdfPath))
  {
    Document document = file.Document;
    // 1. Embedded files (document level).
    foreach(KeyValuePair<PdfString,FileSpecification> entry in document.Names.EmbeddedFiles)
    {EvaluateDataFile(attachments, entry.Value);}
    // 2. File attachments (page level).
    foreach(Page page in document.Pages)
    {
      foreach(Annotation annotation in page.Annotations)
      {
        if(annotation is FileAttachment)
        {EvaluateDataFile(attachments, ((FileAttachment)annotation).DataFile);}
      }
    }
  }
}
void EvaluateDataFile(Dictionary<string, byte[]> attachments, FileSpecification dataFile)
{
  if(dataFile is FullFileSpecification)
  {
    EmbeddedFile embeddedFile = ((FullFileSpecification)dataFile).EmbeddedFile;
    if(embeddedFile != null)
    {attachments[dataFile.Path] = embeddedFile.Data.ToByteArray();}
  }
}

请注意,您不必为空指针异常而烦恼,因为PDF Clown提供了所有必要的抽象和自动化,以确保平滑的模型遍历。

PDF Clown是一个LGPL 3库,在Java和.NET平台上都实现(我是它的首席开发人员):如果你想尝试一下,我建议你在sourceforge.NET上查看它的SVN存储库,因为它在不断发展。

查找ABCpdf库,在我看来非常简单快捷。

我所做的工作与我在网上看到的其他工作略有不同。

所以,以防万一,我想我会把这个贴在这里帮助别人。我不得不经历许多不同的迭代,以艰难的方式弄清楚我需要什么才能让它发挥作用。

我正在将两个PDF合并为第三个PDF,其中前两个PDF中的一个可能有文件附件,需要转入第三个。我完全使用ASP.NET、C#4.0、ITextSharp 5.1.2.0进行流式处理。

        // Extract Files from Submit PDF
        Dictionary<string, byte[]> files = new Dictionary<string, byte[]>();
        PdfDictionary names;
        PdfDictionary embeddedFiles;
        PdfArray fileSpecs;
        int eFLength = 0;

        names = writeReader.Catalog.GetAsDict(PdfName.NAMES); // may be null, writeReader is the PdfReader for a PDF input stream
        if (names != null)
        {
            embeddedFiles = names.GetAsDict(PdfName.EMBEDDEDFILES); //may be null
            if (embeddedFiles != null)
            {
                fileSpecs = embeddedFiles.GetAsArray(PdfName.NAMES); //may be null
                if (fileSpecs != null)
                {
                    eFLength = fileSpecs.Size;
                    for (int i = 0; i < eFLength; i++)
                    {
                        i++; //objects are in pairs and only want odd objects (1,3,5...)
                        PdfDictionary fileSpec = fileSpecs.GetAsDict(i); // may be null
                        if (fileSpec != null)
                        {
                            PdfDictionary refs = fileSpec.GetAsDict(PdfName.EF);
                            foreach (PdfName key in refs.Keys)
                            {
                                PRStream stream = (PRStream)PdfReader.GetPdfObject(refs.GetAsIndirectObject(key));
                                if (stream != null)
                                {
                                    files.Add(fileSpec.GetAsString(key).ToString(), PdfReader.GetStreamBytes(stream));
                                }
                            }
                        }
                    }
                }
            }
        }

您可以尝试Aspose.Pdf.Kit for.NET。PdfExtractor类允许您借助两种方法提取附件:ExtractAttachment和GetAttachment。请参阅附件提取示例。

披露:我在Aspose担任开发人员宣传员。