Получение IOException при множественной записи в файл - PullRequest
0 голосов
/ 04 июня 2009

Я реализовал конструктор файлов 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

Это может быть проблемой блокировки?

Может ли это быть решено:

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

EDIT:

Вот мой след стека:

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 голосов
/ 04 июня 2009

Если вы хотите, как насчет того, чтобы попробовать следующие моды в коде, чтобы больше помочь в поиске ошибки, чем в качестве постоянного исправления.

Добавить перегрузку для печати документа, который принимает параметр 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, кроме как писать с ним. В любом случае, если у вас есть время, попробуйте, писатель может быть решением (быстрое решение), дайте нам знать, если он работает.

0 голосов
/ 05 июня 2009

Привет всем спасибо за ваши ответы.

Я нашел решение, которое работает для меня. Немного хакерский, но он делает свою работу.

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;
}
}

По сути, идея заключается в том, чтобы попытаться запустить его пару раз и, если проблема не устраняется, выдать ошибку.

Получает меня через вопрос

0 голосов
/ 04 июня 2009

Только одна вещь может вызвать это. Другой процесс пишет в файл. Другой процесс может быть даже вашим.

Я предлагаю вам добавить блоки 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.

...