【问题标题】:Why does StreamReader.ReadToEnd work but not Stream.Read?为什么 StreamReader.ReadToEnd 有效但 Stream.Read 无效?
【发布时间】:2020-02-19 18:22:02
【问题描述】:

我正在尝试将 ASP.NET Core 控制器中的请求正文作为 byte[] 数组。这是我最初写的:

var declaredLength = (int)request.ContentLength;
byte[] fileBuffer = new byte[declaredLength];

request.Body.Read(fileBuffer, 0, declaredLength);

此代码有效,但仅适用于小请求(约 20KB)。对于较大的请求,它会填满数组中的前 20,000 个左右字节,然后数组的其余部分为空。

我在置顶答案here中使用了一些代码,并且在重写我的代码后能够成功读取整个请求体:

var declaredLength = (int)request.ContentLength;
byte[] fileBuffer = new byte[declaredLength];

// need to enable, otherwise Seek() fails
request.EnableRewind();

// using StreamReader apparently resolves the issue
using (var reader = new StreamReader(request.Body, Encoding.UTF8, true, 1024, true))
{
    reader.ReadToEnd();
}

request.Body.Seek(0, SeekOrigin.Begin);
request.Body.Read(fileBuffer, 0, declaredLength);

为什么StreamReader.ReadToEnd() 能够成功读取整个请求体,而Stream.Read() 却不能?两次读取请求流感觉就像是 hack。有没有更好的方法来解决这个问题? (我只需要将流读入字节数组一次)

【问题讨论】:

标签: c# asp.net-core .net-core


【解决方案1】:

请记住,在收到所有请求之前,您正在尝试读取 request.Body

Stream.Read 的行为如下:

  1. 如果已到达流的末尾,则返回0
  2. 如果没有尚未读取的可用字节,则阻塞直到至少有 1 个字节可用
  3. 如果有 1 个或多个新字节可用,请立即返回它们。不要屏蔽。

如您所见,如果还没有收到整个正文,request.Body.Read(...) 将只返回已收到的正文部分。

StreamReader.ReadToEnd() 调用Stream.Read in a loop,直到找到流的结尾。

您可能也应该在循环中调用Stream.Read,直到您读取所有字节:

byte[] fileBuffer = new byte[declaredLength];
int numBytesRead = 0;
while (numBytesRead < declaredLength)
{
    int readBytes = request.Body.Read(fileBuffer, numBytesRead, declaredLength - numBytesRead);
    if (readBytes == 0)
    {
        // We reached the end of the stream before we were expecting it
        // Might want to throw an exception here?
    }
    numBytesRead += readBytes;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-12
    • 2020-05-14
    • 2020-10-07
    • 2023-03-30
    • 2013-05-13
    • 2011-09-06
    相关资源
    最近更新 更多