如何在 C 语言中不调用 Flush() 的情况下从刚刚写入的流中读取数据#

How to read from a stream you've just written to without calling Flush() in C#

提问人:amber 提问时间:9/1/2023 更新时间:9/18/2023 访问量:96

问:

我有一些代码使用第三方库 EDIFabric,它写入流,我需要捕获该输出并使用它来通过 StreamReader 返回字符串。

    // Build out the memory stream we'll use to conver to a string.
    using (var stream = new MemoryStream())
    {
        using (var writer = new X12Writer(stream))
        {
            writer.Write("Write EDI values to the stream"); // Not valid EDI output...

            writer.Flush();
            // Flush() is obsolete and generates a CS0618 compiler warning, "Type or member is obsolete"

            stream.Seek(0, SeekOrigin.Begin); // Return to the beginning of the stream
        }

        using StreamReader reader = new(stream);

        // If I omit the flush, the returned string is empty
        return reader.ReadToEnd(); // Returns the stream as a string
    }

任何不包括使用 Flush() 的建议?

C net-core 内存流 c#-7.0

评论

3赞 madreflection 9/2/2023
移出内部块。在其块末端的处置应该为您冲洗。这假设已正确实施。我认为它们已经过时了,因为您应该使用块。有太多不好的例子,人们在流媒体和作家上使用,因为他们没有块。stream.SeekusingwriterusingwriterX12WriterFlushusingFlushCloseusing
0赞 amber 9/6/2023
@madreflection 这成功了。你想把它添加为一个答案,这样你就可以得到它的荣誉吗?

答:

2赞 Alexei Levenkov 9/2/2023 #1

在编写器(针对该流)将其更改提交到流之前,无法从流中读取数据。一些写入器允许在任何时候提交所有缓冲数据,但不是全部 - 通常写入器支持的数据格式需要特定的块大小或一些其他限制,限制可以写入流的部分数据量。

如果您需要获取完整的数据 - 最安全的选择是释放编写器并查找要启动的流(如问题中的代码所示)或在相同的数据上创建一个新流(据我所知,编写器不需要在构造函数中支持“保持流打开”选项)。我对这门课一无所知,但他们可能不希望有人因为上述原因而调用,并且应该立即提交整个流以产生有效的结果。X12WriterFlush

// re-creating a stream from a disposed memory stream.  
var freshStream = new MemoryStream(srteam.ToArray());

如果您对部分数据没问题 - 请查看有关“C# tee 流”的问题,例如将文件重定向到流 C# 以在将数据提交到流时捕获数据。

1赞 amber 9/18/2023 #2

这个问题的解决方案源自 @madreflection 上面的评论,只需将 移出内部块即可。stream.Seek()using

// Build out the memory stream we'll use to conver to a string.
using (var stream = new MemoryStream())
{
    using (var writer = new X12Writer(stream))
    {
        writer.Write("Write EDI values to the stream"); // Not valid EDI output...
    }
    
    stream.Seek(0, SeekOrigin.Begin);

    using StreamReader reader = new(stream);
    return reader.ReadToEnd(); // Returns the stream as a string
}