0

XMLドキュメントを取り込んでxsl変換を適用し、ファイルに追加するcsvファイルビルダーを実装しました。

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

このcsvファイルに追加するxmlドキュメントが多数あり、複数回呼び出した後、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();
    }
}

乾杯。

4

3 に答える 3

0

返信ありがとうございます。

私は自分に合った解決策を思いつきました。少しハッキーですが、それは仕事をします。

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 に答える
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

これを引き起こす原因は 1 つだけです。別のプロセスがファイルに書き込み中です。他のプロセスは、あなた自身のものでさえあるかもしれません。

そのファイルを書き込むことができる領域の周りに 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 に答える