在多次写入文件时获取IOException

时间:2009-06-04 00:22:59

标签: c# csv ioexception

我已经实现了一个csv文件构建器,它接受一个xml文档,对它应用xsl变换并将其附加到文件中。

public class CsvBatchPrinter : BaseBatchPrinter
{
    public CsvBatchPrinter() : base(".csv")
    {
        RemoveDiatrics = false;
    }

    protected override void PrintDocuments(System.Collections.Generic.List<XmlDocument> documents, string xsltFileName, string directory, string tempImageDirectory)
    {
        base.PrintDocuments(documents, xsltFileName, directory, tempImageDirectory);

        foreach (var file in new DirectoryInfo(tempImageDirectory).GetFiles())
        {
            var destination = directory + file.Name;
            if (!File.Exists(destination))
                file.CopyTo(destination);
        }
    }

    protected override void PrintDocument(XmlDocument document, string xsltFileName, string directory, string tempImageDirectory)
    {
        StringUtils.EscapeQuotesInXmlNode(document);
        if (RemoveDiatrics)
        {
            var docXml = StringUtils.RemoveDiatrics(document.OuterXml);
            document = new XmlDocument();
            document.LoadXml(docXml);
        }

        using (var writer = new StreamWriter(string.Format("{0}{1}{2}", directory, "batch", FileExtension), true, Encoding.ASCII))
        {
            Transform(document, xsltFileName, writer);
        }
    }

    public bool RemoveDiatrics { get; set; }
}

我有大量的xml文档要添加到此csv文件中,并且在多次调用之后,它偶尔会抛出IOException The process cannot access the file 'batch.csv' because it is being used by another process.

这会是某种锁定问题吗?

可以通过以下方式解决:

lock(this)
{
    using (var writer = new StreamWriter(string.Format("{0}{1}{2}", directory, "batch", FileExtension), true, Encoding.ASCII))
    {
        Transform(document, xsltFileName, writer);
    }
}

修改

这是我的堆栈跟踪:

at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.StreamWriter.CreateFile(String path, Boolean append)
at System.IO.StreamWriter..ctor(String path, Boolean append, Encoding encoding, Int32 bufferSize)
at System.IO.StreamWriter..ctor(String path, Boolean append, Encoding encoding)
at Receipts.Facade.Utilities.BatchPrinters.CsvBatchPrinter.PrintDocument(XmlDocument document, String xsltFileName, String directory, String tempImageDirectory) in CsvBatchPrinter.cs:line 37
at Receipts.Facade.Utilities.BatchPrinters.BaseBatchPrinter.PrintDocuments(List`1 documents, String xsltFileName, String directory, String tempImageDirectory) in BaseBatchPrinter.cs:line 30
at Receipts.Facade.Utilities.BatchPrinters.CsvBatchPrinter.PrintDocuments(List`1 documents, String xsltFileName, String directory, String tempImageDirectory) in CsvBatchPrinter.cs:line 17
at Receipts.Facade.Utilities.BatchPrinters.BaseBatchPrinter.Print(List`1 documents, String xsltFileName, String destinationDirectory, String tempImageDirectory) in BaseBatchPrinter.cs:line 23
at Receipts.Facade.Modules.FinanceDocuments.FinanceDocumentActuator`2.printXmlFiles(List`1 xmlDocuments, String tempImagesDirectory) in FinanceDocumentActuator.cs:line 137

和我的基类:

public abstract class BaseBatchPrinter : IBatchPrinter
{
    private static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
    protected readonly string FileExtension;

    protected BaseBatchPrinter(string fileExtension)
    {
        FileExtension = fileExtension;
    }

    public void Print(List<XmlDocument> documents, string xsltFileName, string destinationDirectory, string tempImageDirectory)
    {
        Log.InfoFormat("Printing to directory: {0}", destinationDirectory);
        PrintDocuments(documents, xsltFileName, destinationDirectory, tempImageDirectory);
    }

    protected virtual void PrintDocuments(List<XmlDocument> documents, string xsltFileName, string directory, string tempImageDirectory)
    {
        foreach (var document in documents)
        {
            PrintDocument(document, xsltFileName, directory, tempImageDirectory);
        }
    }

    /// <summary>
    /// Needs to Call Transform(XmlDocument document, string xsltFileName, string directory)
    /// </summary>
    protected abstract void PrintDocument(XmlDocument document, string xsltFileName, string directory, string tempImageDirectory);

    protected void Transform(XmlDocument document, string xsltFileName, StreamWriter writer)
    {
        //TODO: look into XslCompiledTransform to replace the XslTransform
        var xslTransform = new XslTransform();
        xslTransform.Load(xsltFileName);
        xslTransform.Transform(createNavigator(document), null, writer);
    }

    protected string CreateFileName(string directory, XmlDocument doc)
    {
        var conId = createNavigator(doc).SelectSingleNode(Config.SELECT_CONSTITUENT_ID_XPATH).Value;
        return string.Format(@"{0}{1}{2}", directory, conId, FileExtension.IndexOf('.') > -1 ? FileExtension : "." + FileExtension);
    }

    protected XPathNavigator createNavigator(XmlDocument document)
    {
        return document.DocumentElement == null ? document.CreateNavigator() : document.DocumentElement.CreateNavigator();
    }
}

干杯。

3 个答案:

答案 0 :(得分:0)

只有一件事可以导致这种情况。另一个过程是写入文件。另一个过程甚至可能是你自己的过程。

我建议你在可以编写该文件的区域周围添加try / catch块。在catch块中,抛出一个新的异常,添加完整的文件路径:

var filePath = string.Format("{0}{1}{2}", directory, "batch", FileExtension);
try {
    using (var writer = new StreamWriter(filepath, true, Encoding.ASCII)) {
        Transform(...);
    }
}
catch (IOException ex) {
    throw new Exception(
        String.Format("Exception while transforming file {0}", filePath),
        ex);
}

发布您收到的完整异常,包括任何InnerException和堆栈跟踪。

您还需要确保您的文件副本是否可以写入batch.csv。

答案 1 :(得分:0)

如果您愿意,可以尝试将以下mod添加到代码中以帮助更多地找到错误,而不是作为永久修复。

为打印带有StreamWriter参数的文档添加重载。 修改base.PrintDocuments如下:

using ( var writer = new StreamWriter ( string.Format ( "{0}{1}{2}", directory, "batch", FileExtension ), true, Encoding.ASCII ) )
{
    foreach ( var document in documents )
    {
        PrintDocument ( document, xsltFileName, directory, tempImageDirectory, writer );
    }
}

protected override void PrintDocument ( XmlDocument document, string xsltFileName, string directory, string tempImageDirectory, StreamWriter writer )
{
    if ( RemoveDiatrics )
    {
        var docXml = document.OuterXml;
        document = new XmlDocument ( );
        document.LoadXml ( docXml );
    }

   Transform ( document, xsltFileName, writer );        
}

如果失败了...总是悲观主义者......我会把变形视为可能的罪魁祸首,虽然我知道它对TextWriter没有任何作用,除了,好吧,用它写。 无论如何,如果你有时间,请试一试,创建一次编写器可能是解决方案(快速修复),让我们知道它是否有效。

答案 2 :(得分:0)

嘿,谢谢你的回复。

我想出了一个适合我的解决方案。有点hacky但它​​确实起作用。

protected override void PrintDocument(XmlDocument document, string xsltFileName, string directory, string tempImageDirectory)
{
    StringUtils.EscapeQuotesInXmlNode(document);
if (RemoveDiatrics)
{
    var docXml = StringUtils.RemoveDiatrics(document.OuterXml);
    document = new XmlDocument();
    document.LoadXml(docXml);
}

IOException ex = null;
for (var attempts = 0; attempts < 10; attempts++)
{
    ex = tryWriteToFile(document, directory, xsltFileName);
    if (ex == null)
        break;
}

if (ex != null)
    throw new ApplicationException("Cannot write to file", ex);
}

private IOException tryWriteToFile(XmlDocument document, string directory, string xsltFileName)
{
try
{
    using (var writer = new StreamWriter(new FileStream(string.Format("{0}{1}{2}", directory, "batch", FileExtension), FileMode.Append, FileAccess.Write, FileShare.Read), Encoding.ASCII))
    {
        Transform(document, xsltFileName, writer);
    writer.Close();
    }
    return null;
}
catch (IOException e)
{
    return e;
}
}

基本上,它背后的想法是尝试运行它几次,如果问题仍然存在,则抛出错误。

让我了解问题