StreamWriter добавляет случайные данные

Я вижу странное поведение, когда класс StreamWriter записывает дополнительные данные в файл, используя этот код:

public void WriteToCSV(string filename)
{
    StreamWriter streamWriter = null;
    try
    {
        streamWriter = new StreamWriter(filename);
        Log.Info("Writing CSV report header information ... ");
        streamWriter.WriteLine("\"{0}\",\"{1}\",\"{2}\",\"{3}\"", ((int)CSVRecordType.Header).ToString("D2", CultureInfo.CurrentCulture), m_InputFilename, m_LoadStartDate, m_LoadEndDate);

        int recordCount = 0;

        if (SummarySection)
        {
            Log.Info("Writing CSV report summary section ... ");
            foreach (KeyValuePair<KeyValuePair<LoadStatus, string>, CategoryResult> categoryResult in m_DataLoadResult.DataLoadResults)
             {
                streamWriter.WriteLine("\"{0}\",\"{1}\",\"{2}\",\"{3}\"", ((int)CSVRecordType.Summary).ToString("D2", CultureInfo.CurrentCulture), categoryResult.Value.StatusString, categoryResult.Value.Count.ToString(CultureInfo.CurrentCulture), categoryResult.Value.Category);
                recordCount++;
             }
        }

        Log.Info("Writing CSV report cases section ... ");
        foreach (KeyValuePair<KeyValuePair<LoadStatus, string>, CategoryResult> categoryResult in m_DataLoadResult.DataLoadResults)
        {
            foreach (CaseLoadResult result in categoryResult.Value.CaseLoadResults)
            {
                if ((LoadStatus.Success == result.Status && SuccessCases) ||
                    (LoadStatus.Warnings == result.Status && WarningCases) ||
                    (LoadStatus.Failure == result.Status && FailureCases) ||
                    (LoadStatus.NotProcessed == result.Status && NotProcessedCases))
                {
                    streamWriter.Write("\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\"", ((int)CSVRecordType.Result).ToString("D2", CultureInfo.CurrentCulture), result.Status, result.UniqueId, result.Category, result.ClassicReference);
                    if (RawResponse)
                    {
                        streamWriter.Write(",\"{0}\"", result.ResponseXml);
                    }
                    streamWriter.WriteLine();
                    recordCount++;
                }
            }
        }

        streamWriter.WriteLine("\"{0}\",\"{1}\"", ((int)CSVRecordType.Count).ToString("D2", CultureInfo.CurrentCulture), recordCount);

        Log.Info("CSV report written to '{0}'", fileName);
    }
    catch (IOException execption)
    {
        string errorMessage = string.Format(CultureInfo.CurrentCulture, "Unable to write XML report to '{0}'", fileName);
        Log.Error(errorMessage);
        Log.Error(exception.Message);
        throw new MyException(errorMessage, exception);
    }
    finally
    {
        if (null != streamWriter)
        {
            streamWriter.Close();
        }
    }
}

Созданный файл содержит набор записей в каждой строке от 0 до N, например:

[Record Zero]
[Record One]
...
[Record N]

Однако созданный файл содержит либо пустые значения, либо неполные записи из более высокого уровня файла, добавленного в конец. Например:

[Record Zero]
[Record One]
...
[Record N]
[Lots of nulls]

or

[Record Zero]
[Record One]
...
[Record N]
[Half complete records]

Это также происходит в отдельных фрагментах кода, которые также используют класс StreamWriter. Кроме того, все созданные файлы имеют размеры, кратные 1024. Мне не удалось воспроизвести такое поведение на любой другой машине, и я попытался воссоздать среду. Предыдущие версии приложения не демонстрировали такого поведения, несмотря на тот же код для рассматриваемых методов.

РЕДАКТИРОВАТЬ: добавлен дополнительный код.


person void    schedule 14.06.2010    source источник
comment
Пожалуйста, добавьте рабочий код записи (например, как вы записываете байты в StreamWriter).   -  person Richard    schedule 14.06.2010
comment
Я согласен с Ричардом, вся эта обработка исключений не имеет значения. Весь соответствующий код находится внутри [Write to stream].   -  person Henk Holterman    schedule 14.06.2010
comment
Можете ли вы выполнить код в отладчике на пораженной машине? Как выглядит журнал, который вы пишете, на затронутой машине и чем он отличается (для тех же входных данных) на других машинах, которые не затронуты?   -  person Andrew Savinykh    schedule 14.06.2010
comment
Я думаю; здесь происходит какое-то плетение?   -  person Marc Gravell    schedule 14.06.2010
comment
@Marc Gravell: обоснованное беспокойство. С одной стороны, streamWriter = new StreamWriter(имя файла); использует FileShare.Read, тем самым блокируя файл для записи, поэтому даже в многопоточном сценарии мы никогда не должны видеть неполные данные. С другой стороны, я видел много странностей в многопоточных сценариях, которые поначалу не очевидны. Исходя из этого, я допускаю, что если здесь есть многопоточность, стоит внимательно посмотреть, не влияет ли она на описанное поведение.   -  person Andrew Savinykh    schedule 14.06.2010
comment
Можете ли вы включить определение любых пользовательских структур, которые вы используете?   -  person Phil Gan    schedule 14.06.2010
comment
Кроме того, перед закрытием попробуйте позвонить Flush(). У меня были ситуации, когда буферизованные данные не удалялись автоматически из StreamWriter.   -  person Phil Gan    schedule 14.06.2010
comment
Находится ли filename на локальном диске или на сетевом ресурсе (например, путь UNC)?   -  person Daniel Renshaw    schedule 14.06.2010


Ответы (1)


Есть два сценария, которые приходят на ум, когда речь идет о мусоре в конце потока:

  1. отсутствие усечения при перезаписи: если вы перезаписываете файл, но записываете меньше данных, то вы должны его обрезать. Для этого существует перегрузка при открытии файла, или вы можете использовать theStream.SetLength.
  2. заполнение буфера записи; в частности, наиболее распространенная ошибка возникает при использовании MemoryStream — вы должны либо использовать .ToArray() (чтобы получить правильное количество байтов), или использовать .GetBuffer(), но скопировать из буфера только .Length байт (все, что дальше, это мусор)

Я предполагаю, что здесь применяется "1"?

person Marc Gravell    schedule 14.06.2010
comment
streamWriter = новый StreamWriter (имя файла); использует FileMode.Create. Это всегда усекает файл. Знаете ли вы сценарий, когда это может быть неправдой? - person Andrew Savinykh; 14.06.2010
comment
Я не согласен с @zespri. Взято из документов, в конструкторе StreamWriter(String): если файл существует, он перезаписывается; в противном случае создается новый файл. - person Timores; 14.06.2010
comment
@Timores - быстрая проверка показывает, что он перезаписан и (правильно) усечен. Так что отбросьте эту идею. - person Marc Gravell; 14.06.2010