【问题标题】:C# PDF Delete - File 'being used by another process'C# PDF 删除 - 文件“被另一个进程使用”
【发布时间】:2013-03-23 16:58:58
【问题描述】:

我已经广泛搜索了这个问题的答案。我知道为什么我会收到异常,但我无法在我的代码中找到它的原因。

基本上,我的代码创建了四个单独的 PDF 文件,将它们合并到一个大 PDF 文件中,然后删除原始的四个文件。一切都很好,除了我在尝试删除文件时收到 IOException,因为它们“正在被另一个进程使用”。

这是我用来合并文件的代码:

private static Document MergeFiles(string[] fileNames, string finalFileName)
{
    Document doc = new Document(PageSize.A4, 20, 20, 25, 25);
    if (fileNames.Length > 0)
    {
        int a = 0;
        PdfReader reader = new PdfReader(fileNames[a]);
        int n = reader.NumberOfPages;
        FileStream output = new FileStream("C:\\temp\\" + finalFileName, FileMode.Create);
        PdfWriter writer = PdfWriter.GetInstance(doc, output);
        doc.Open();
        PdfContentByte cb = writer.DirectContent;
        PdfImportedPage page;
        int rotation;

        while (a < fileNames.Length)
        {
            int i = 0;
            while (i < n)
            {
                i++;
                doc.SetPageSize(reader.GetPageSizeWithRotation(i));
                doc.NewPage();
                page = writer.GetImportedPage(reader, i);
                rotation = reader.GetPageRotation(i);
                if (rotation == 90 || rotation == 270)
                    cb.AddTemplate(page, 0, -1f, 1f, 0, 0, reader.GetPageSizeWithRotation(i).Height);
                else
                    cb.AddTemplate(page, 1f, 0, 0, 1f, 0, 0);
            }
            a++;
            if (a < fileNames.Length)
            {
                reader = new PdfReader(fileNames[a]);
                n = reader.NumberOfPages;
            }
        }
    }
    doc.Close();
    return doc;
}

这里是删除文件的代码:

private static void DeleteFile(string[] fileNames)
{
    if (fileNames != null)
    {
        for (int x = 0; x < fileNames.Length; x++)
        {
            if(!fileNames[x].Equals(""))
                System.IO.File.Delete(fileNames[x]);
        }
    }
}

任何帮助将不胜感激。当我合并文档时,我假设循环中的某个地方没有关闭(阅读器/作者),但我尝试了很多不同的组合,但似乎没有任何效果。真的开始烦我了。

更新 谢谢大家的cmets。我已将代码修改为:

private static Document MergeFiles(string[] fileNames, string finalFileName)
{
    Document doc = new Document(PageSize.A4, 20, 20, 25, 25);
    if (fileNames.Length > 0)
    {
        while (a < fileNames.Length)
        {
            using (PdfReader reader = new PdfReader(fileNames[a]))
            using (FileStream output = new FileStream("C:\\temp\\" + finalFileName, FileMode.Create))
            using (PdfWriter writer = PdfWriter.GetInstance(doc, output))
            {
                int n = reader.NumberOfPages;
                doc.Open();
                PdfContentByte cb = writer.DirectContent;
                PdfImportedPage page;
                int rotation;

                int i = 0;
                while (i < n)
                {
                    i++;
                    doc.SetPageSize(reader.GetPageSizeWithRotation(i));
                    doc.NewPage();
                    page = writer.GetImportedPage(reader, i);
                    rotation = reader.GetPageRotation(i);
                    if (rotation == 90 || rotation == 270)
                        cb.AddTemplate(page, 0, -1f, 1f, 0, 0, reader.GetPageSizeWithRotation(i).Height);
                    else
                        cb.AddTemplate(page, 1f, 0, 0, 1f, 0, 0);
                }
                a++;
                if (a < fileNames.Length)
                {
                    n = reader.NumberOfPages;
                }
            }
        }
    }
    doc.Close();
    return doc;
}

它可以编译,但在运行时出现错误,指向 Using 循环的右括号:

System.ObjectDisposedException was unhandled
  Message=Cannot access a closed file.

【问题讨论】:

  • 也许在 using 语句中实例化 PdfReader(fileName[a])?
  • 一些建议:不要返回 Document 对象,一旦关闭它就没有任何意义。要么返回一个成功的布尔值,文件名(可能不是因为你传入它),要么可能切换到MemoryStream 并返回字节数组。如果您的原始四个文档足够小,我也会将它们分别创建为MemoryStream,并且只需使用字节数组即可。这样您就不必担心会撞到磁盘。
  • 克里斯,我最终选择了您的解决方案并使用了 MemorySteam 和字节数组。它最终变得更快、更容易,没有与 PdfReaders 等相关的问题。感谢您的建议!

标签: c# pdf itextsharp ioexception delete-file


【解决方案1】:

您没有处置任何您的资源。

PdfReaderPdfWriterFileStream 都实现了 IDisposable。这些都需要是 Disposed 或包裹在 using 块中(最好是后者)。

我猜是 PdfReader 实例使这些文件保持打开状态。

附:在方法结束时仅Close 它们是不够的,因为如果在这些调用执行之前发生任何异常,这将使它们“永久”打开(或只要进程运行)。要么将你的清理工作放在 finally 块中,要么只使用 using

【讨论】:

  • 非常感谢,亚伦。您能否提供一个快速示例,说明在这种情况下如何实例化 using 语句?我是 Using 语句的新手(截至昨天!):)
  • 对不起,我应该澄清一下。我知道使用该语句的一般方式,但我不完全确定在这种情况下如何使用它。例如。我已经完成了'using(PDFReader reader = new PDFReader(fileNames[0])) { //code }',除了我收到一个编译错误'无法分配给阅读器,因为它是这一行上的'使用变量',在里面使用块:'reader = new PdfReader(fileNames[a]);'
  • @BennyO'Neill,关于您的最新编辑,请尝试在doc.Close 之前设置writer.CloseStream = false
  • 嗨,伙计,这也没用。我怀疑程序集本身存在问题。我根据您的所有建议(以及 MSDN 论坛中的其他一些建议)进行了大量调整,并创建了一个完全可行的解决方案,但不断抛出一个没有任何意义的异常。 Anywho,上面有人建议使用我已经完成的字节数组,现在它似乎可以完美地工作。感谢您的所有帮助和建议!
【解决方案2】:

虽然您正在关闭文档 (doc.Close();),但您并没有关闭文件流、写入器和读取器。

doc.Close();之后添加这个:

writer.Close();
output.Close();
reader.Close();

【讨论】:

    猜你喜欢
    • 2018-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多