【发布时间】:2021-06-07 21:14:05
【问题描述】:
我正在使用 PDFsharp 将大量文件(存储在磁盘上)合并为一个 PDF。有时 PDF 可以大到 700MB。我正在使用提供的示例代码,基本上创建一个输出PdfDocument,向其中添加页面,然后调用 outputDocument.Save(destinationPath),因此使用的内存量与生成的文档大小大致相同。
有没有办法将更改流式传输到文件以避免内存消耗?如果没有,有没有办法利用 MigraDoc 做到这一点?
更新
根据评论中的建议,我整理了一些代码来关闭和重新打开文档,虽然内存使用受到控制并且文件确实增长了,但它似乎并没有附加页面。如果我将“路径”设置为包含 3000 个单页文件的列表,我仍然会得到一个 500 页的文档。代码如下:
var destinationFile = "c:\\test.pdf";
var directory = Path.GetDirectoryName(destinationFile);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
var fs = new FileStream(destinationFile, FileMode.OpenOrCreate, FileAccess.ReadWrite);
var outputDocument = new PdfDocument(fs);
var count = 0;
// Iterate files (paths is a List<string> collection)
foreach (string path in paths)
{
var inputDocument = PdfReader.Open(path, PdfDocumentOpenMode.Import);
// Iterate pages
for (int idx = 0; idx < inputDocument.PageCount; idx++)
{
// Get the page from the external document...
PdfPage page = inputDocument.Pages[idx];
// ...and add it to the output document.
outputDocument.AddPage(page);
}
inputDocument.Dispose();
count++;
if (count % 500 == 0 || count == paths.Count)
{
outputDocument.Close();
fs.Close();
fs.Dispose();
if (count < paths.Count)
{
fs = new FileStream(destinationFile, FileMode.Append, FileAccess.Write);
outputDocument = new PdfDocument(fs);
}
}
}
更新 2
这是一些使用 PDFReader 关闭和重新打开文档的新代码。程序正在合并 2000 个 4 页 140KB PDF,输出文件为 273MB。我试过没有关闭和重新打开,关闭和重新打开每 1000、500、250 和 100 个文件。结果如下:
无间隔:21 秒,最大内存 330MB 1000 间隔:30 秒,最大内存 490MB 500 间隔:55 秒,最大内存 710MB 250间隔:1分35秒,最大内存780MB 100间隔:2分55秒,最大内存850mb
class Program
{
public static void Main(string[] args)
{
var files = new List<string>();
var basePath = AppDomain.CurrentDomain.BaseDirectory;
for (var i = 0; i < 2000; i++)
{
files.Add($"{basePath}\\sample.pdf");
}
DoMerge(files, $"{basePath}\\output.pdf");
}
private static void DoMerge(List<string> paths, string destinationFile)
{
var directory = Path.GetDirectoryName(destinationFile);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
var outputDocument = new PdfDocument();
var count = 0;
// Iterate files
foreach (string path in paths)
{
// Open the document to import pages from it.
try
{
var inputDocument = PdfReader.Open(path, PdfDocumentOpenMode.Import);
// Iterate pages
for (int idx = 0; idx < inputDocument.PageCount; idx++)
{
// Get the page from the external document...
PdfPage page = inputDocument.Pages[idx];
// ...and add it to the output document.
outputDocument.AddPage(page);
}
inputDocument.Dispose();
count++;
if (count % 500 == 0 || count == paths.Count)
{
outputDocument.Save(destinationFile);
outputDocument.Close();
outputDocument.Dispose();
if (count < paths.Count)
{
outputDocument = PdfReader.Open(destinationFile, PdfDocumentOpenMode.Import);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
}
}
}
【问题讨论】:
-
您必须使用
PdfReader.Open打开输出文档以添加更多页面。 -
@IlikedtheoldStackOverflow 我也尝试过,同时使用 PdfDocumentOpenMode.Modify 和 PdfDocumentOpenMode.Import。内存使用永远不会下降。老实说,我不希望它 PdfReader.Open() 将整个文档加载到内存中。所以如果文档不断增长,每次我打开它都会占用更多内存,不是吗?
-
PDFsharp 在使用时会初始化一些成员。新添加的页面比打开文档中的“空闲”页面需要更多内存。关闭并重新打开目标文件是一种行之有效的技巧。但是在 32 位模式下运行时,限制仍然是 2 GiB。可能500个文件的间隔太长了。