流读C#的变化?

Roy*_*mir 0 .net c# stream

我已经看过这个代码示例 - 从Stream读入缓冲区:

byte[] buffer = new byte[1024 * 32];
int bytesRead;

while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
    //...
}
Run Code Online (Sandbox Code Playgroud)

但是看第二个参数stream.Read(..,0,..)缓冲区从零开始的字节偏移量,开始存储从当前流中读取的数据.

那么每次偏移是0吗?谁说它不会覆盖这些索引的数据?

恰恰相反:我也看到了这个例子:

 int read, offset = 0;
     while(count > 0 && (read = source.Read(buffer, offset, count)) > 0) {
        offset += read;
        count -= read;
    }
Run Code Online (Sandbox Code Playgroud)

所以这里的偏移量在每次读数后都会被抵消(这对我来说似乎更合乎逻辑)

但我必须遗漏一些东西:

我的观察是对的吗?我什么时候应该使用每个案例?

NB,我的pov是网络流:发送文件.

Adr*_*tti 5

它们都是有用的代码示例,只是在不同的场景中.让我们选择你的第一个例子来添加一些代码:

Socket socket = ...;

byte[] buffer = new byte[1024 * 32];
int bytesRead;

while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
    socket.BeginSend(buffer, 0, bytesRead , SocketFlags.None, null, null);
    // Wait for completion doing something else? 
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下buffer,每次重复使用,然后是,数据将被覆盖,这是预期的行为,因为你在时间读取一个块,你使用它然后继续.

你的第二个例子是相当不同的:你填充buffer与读取数据,但你不读所有的数据都在一起,你读一个较小的块每次然后offset在目标buffer必须增加.

他们有什么不同?在第一种情况下,缓冲区可以根据需要小(理想情况下甚至是一个字节),多次读取将消耗输入流.在第二种情况下,缓冲区必须足够大,以容纳您需要的所有数据.

// Note we need to know file size in advance and buffer must be big enough
// to accommodate all data we need
int read, offset = 0;
while(count > 0 && (read = source.Read(buffer, offset, count)) > 0) {
    socket.BeginSend(buffer, offset , read, SocketFlags.None, null, null);

    // Here we don't need to wait BeginSend() completes. 

    offset += read;
    count -= read;
}
Run Code Online (Sandbox Code Playgroud)

哪一个更好?很难说,如果你一次性分配所有内存,那么你很少需要通过增加块来读取块offset(只有我能想到的情况是性能优化,因为输入流上的块大小或者你想要 - 并行 - 启动在读取新数据时对接收到的数据进行一些处理).相比之下,分配一个足够容纳所有数据的缓冲区至少有两大缺点:

  • 必须提前知道文件大小(并不总是如此);
  • 如果文件足够大,那么你将耗尽内存.

一般情况下(IMO)如果第一种方法(重用相同的缓冲区)在大多数情况下都相当不错,那么在大多数网络场景中,单次读取(和非阻塞发送)可能带来的性能提升可以忽略不计,而且缺点很严重.总结一下:

                               1                2
Unknown file size              yes              no
Can run out of memory          yes              no
Parallel processing friendly   no               yes
Performance optimized          no               yes

当然,您也可以"混合"两种方法:一个带有多个较小读取的循环缓冲区,对于每次读取,您都会使偏移指针开始新读取并且并行处理前一个读取.有了这个,你可以从这两种方法中获益,但调整起来有点棘手(因为并发访问和可能重叠的读/写).