0

我已经实现了一个 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 文件中,在多次调用它之后,它偶尔会抛出一个 IOExceptionThe 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();
    }
}

干杯。

4

3 回答 3

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。

于 2009-06-04T00:31:44.617 回答
0

如果您愿意,不妨尝试对代码进行以下修改,以帮助更多地找出故障,而不是作为永久性修复。

为打印文档添加一个重载,该文档采用 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 );        
}

如果这失败了......总是悲观主义者......我会将Transform视为可能的罪魁祸首,尽管我知道它对TextWriter没有任何作用,除了,好吧,用它写。无论如何,如果您有时间,请尝试一下,创建一次作家可能是解决方案(快速修复),让我们知道它是否有效。

于 2009-06-04T12:54:39.443 回答
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;
}
}

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

让我解决问题

于 2009-06-04T23:07:02.900 回答