我有大量的pdf文档,附有xml文件。我想提取那些附加的xml文件并读取它们。如何使用.net以编程方式执行此操作?
答案 0 :(得分:7)
iTextSharp也能够提取附件......虽然您可能必须使用低级别对象来执行此操作。
有两种方法可以在PDF中嵌入文件:
从任一源获得文件规范字典后,文件本身将成为字典中标记为“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));
}
}
答案 1 :(得分:4)
这是一个老问题,尽管如此,我认为我的替代解决方案(使用PDF Clown)可能会引起一些兴趣,因为它更清晰(更完整,因为它在文档和页面级别都进行了迭代) )比之前提出的代码片段:
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存储库因为它在不断发展。
答案 2 :(得分:2)
在我看来,寻找ABCpdf - 图书馆,非常简单快捷。
答案 3 :(得分:2)
我的工作与我在网上看到的任何其他内容略有不同。
所以,为了以防万一,我想我会在这里发帖来帮助别人。我不得不经历许多不同的迭代来弄清楚 - 艰难的方式 - 我需要它才能让它发挥作用。
我正在将两个PDF合并为第三个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));
}
}
}
}
}
}
}
答案 4 :(得分:1)
您可以尝试Aspose.Pdf.Kit for .NET。 PdfExtractor类允许您使用两种方法提取附件:ExtractAttachment和GetAttachment。请参阅example of attachment extraction。
披露:我在Aspose担任开发人员传播者。