csv FileHelpers WriteStream不写入数据

q7solyqu  于 9个月前  发布在  其他
关注(0)|答案(1)|浏览(114)

我需要读取一个固定宽度的文件,将记录Map到另一种类型,然后将该数据写入CSV流。我试图使用FileHelpers来完成此操作,但WriteStream似乎无法将任何数据写入流。
FixedWidthType.cs(要读取的类型)

[FixedLengthRecord, IgnoreFirst(2), IgnoreLast(1)]
public class FixedWidthType
{
    [FieldFixedLength(6), FieldTrim(TrimMode.Right)]
    public string BranchCode { get; set; }
    // ...
}

字符串
CsvType.cs(要写入的类型)

[DelimitedRecord("|")]
public class CsvType
{
    public string BranchCode { get; set; }
    // ...
}


Program.cs

var readerEngine = new FileHelperEngine<FixedWidthType>();
var writerEngine = new FileHelperEngine<CsvType>();

var file = File.ReadAllBytes("fixedWidthFile.txt");

using (var sr = new MemoryStream(file))
using (var reader = new StreamReader(sr))
using (var sw = new MemoryStream())
using (var writer = new StreamWriter(sw))
{
    // read fixedwidth data
    var fixedWidthRecords = readerEngine.ReadStream(reader);

    var csvRecords = fixedWidthRecords.Select(r => new CsvType
    {
        BranchCode = r.BranchCode,
        // ...
    }).ToList();

    Console.WriteLine(csvRecords.Count()); // output: 2

    // write csv data
    writerEngine.WriteStream(writer, csvRecords);

    Console.WriteLine(sw.ToArray().Count()); // output: 0

    File.WriteAllBytes("newfile.csv", sw.ToArray());
}


上面的代码写了一个空白文件。ps:我知道我可以使用writerEngine.WriteFile来完成上面的工作(顺便说一句,这确实有效),但我特别需要一个流在我的情况下。写上面的文件的目的只是为了查看输出。

mqxuamgl

mqxuamgl1#

在关闭TextWriter和/或其底层Stream(通过显式.Close().Dispose()调用-或implicitly via a using(){} block or using; statement也将刷新它)时,如果您打算在写入Stream后从Stream回读 * 而不关闭它,那么您需要刷新TextWriter,因为它有自己的缓冲区,您可能还需要通过设置.Position来 * 倒带 * 流-并利用leaveOpen: true

var readerEngine = new FileHelperEngine<FixedWidthType>();
var writerEngine = new FileHelperEngine<CsvType>();

Byte[] inputBytes = File.ReadAllBytes("fixedWidthFile.txt");

UTF8Encoding utf8 = new UTF8Encoding( encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true ); // Using the default UTF8Encoding can lead to unexpected proplems: see https://stackoverflow.com/questions/5266069/streamwriter-and-utf-8-byte-order-marks

using (MemoryStream inputStream = new MemoryStream( inputBytes ))
using (StreamReader reader = new StreamReader( inputStream ) )
using (MemoryStream outputStream = new MemoryStream())
using (StreamWriter writer = new StreamWriter( outputStream, utf8, bufferSize: 4096, leaveOpen: true ) )
{
    var fixedWidthRecords = readerEngine.ReadStream(reader);

    var csvRecords = fixedWidthRecords
        .Select(r => new CsvType
        {
            BranchCode = r.BranchCode,
            // ...
        })
        .ToList();

    Console.WriteLine( "csvRecords.Count: {0}", csvRecords.Count ); // output: 2

    // write csv data
    writerEngine.WriteStream( writer, csvRecords );

    writer.Flush();
    outputStream.Flush(); // <-- This isn't necessary for a MemoryStream, but will be for a FileStream.

#if OPTION_1

    // Avoid `ToArray()` as that will do an allocation+copy.
    Console.WriteLine( outputStream.Position );
    Console.WriteLine( outputStream.GetBuffer().Length );

    ReadOnlySpan<Byte> msContents = outputStream.GetBuffer().AsSpan( 0, outputStream.Position );

    File.WriteAllBytes( "newfile.csv", msContents );

#elif OPTION_2

    // Close `writer` here (which will also flush it), because we set `leaveOpen: true` the MemoryStream can be reused:
    writer.Dispose();
    // Rewind the MemoryStream:
    outputStream.Position = 0;
    
    using( FileStream fileOutputStream = File.OpenWrite( "newfile.csv" ) )
    {
        await outputStream.CopyToAsync( fileOutputStream );
    }

#endif

}

字符串

  • 但是 * 如果你看看你的程序的应用逻辑,你实际上不需要Flush任何东西,只要把你的代码改为:
var readerEngine = new FileHelperEngine<FixedWidthType>();
var writerEngine = new FileHelperEngine<CsvType>();

UTF8Encoding utf8 = new UTF8Encoding( encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true ); // Using the default UTF8Encoding can lead to unexpected proplems: see https://stackoverflow.com/questions/5266069/streamwriter-and-utf-8-byte-order-marks

using( FileStream   fixedWidthInputFS     = new FileStream( "fixedWidthFile.txt", FileAccess.Read, FileShare.None, FileMode.Open ) )
using( StreamReader fixedWidthInputReader = new StreamReader( fixedWidthInputFS ) )
using( FileStream   outputFS              = new FileStream( "output.dat", FileAccess.Write, FileShare.None, FileMode.CreateNew ) )
using( StreamWriter outputWriter          = new StreamWriter( outputFS, utf8 ) ) // <-- Watch out for the default encoding possibly being UTF8 with BOM, 
{
    var csvRecords = readerEngine.ReadStream( fixedWidthInputReader )
        .Select(r => new CsvType
        {
            BranchCode = r.BranchCode,
            // ...
        });

    writerEngine.WriteStream( outputWriter, csvRecords );
}

  • Protip:当StreamTextWriter/TextReader仅用于输入和/或输出时,您应该在它们的名称中添加“输入”或“输出”(或“输入”/“输出”),以使其更容易理解。

相关问题