C# 高效读取流内容并限制读取量
C# efficient reading of stream content with a limit on amount read
我有一个案例,网络 API 调用 returns 一个非常大的字符串响应。我按如下方式拨打电话:
var multipartContent = new MultipartFormDataContent();
multipartContent.Add(new ByteArrayContent(blobStream.CopyToBytes()),
"upload", Path.GetFileName(fileName));
var response = await _httpClient.PostAsync("api/v1/textResponse", multipartContent);
int responeLength = response.Content.Headers.ContentLength.HasValue ?
(int)response.Content.Headers.ContentLength.Value : -1;
response.EnsureSuccessStatusCode();
我只需要处理响应中的前 1Mb 数据,因此如果响应小于 1Mb,我将全部读取,但如果大于 1Mb,我将很难停止读取。
我正在寻找最有效的阅读方式。我试过这段代码:
// section above...
response.EnsureSuccessStatusCode();
string contentText = null;
if (responeLength < maxAllowedLimit) // 1Mb
{
// less then limit - read all as string.
contentText = await response.Content.ReadAsStringAsync();
}
else {
var contentStream = await response.Content.ReadAsStreamAsync();
using (var stream = new MemoryStream())
{
byte[] buffer = new byte[5120]; // read in chunks of 5KB
int bytesRead;
while((bytesRead = contentStream.Read(buffer, 0, buffer.Length)) > 0)
{
stream.Write(buffer, 0, bytesRead);
}
contentText = stream.ConvertToString();
}
}
这是最有效的方法吗?我怎样才能限制读取量(其他)。我试过这段代码,它总是 returns 一个空字符串。还有:
ReadAsStringAsync()
ReadAsByteArrayAsync()
ReadAsStreamAsync()
LoadIntoBufferAsync(int size)
这些方法是否更有效?
提前感谢您的指点!
我怀疑最有效(但仍然正确)的方法可能是这样的。由于您对读取的 字节 的数量有限制,而不是 字符的数量 ,因此这变得更加复杂,因此我们不能使用 StreamReader
。请注意,我们必须小心不要在代码点的中间停止读取 - 在许多情况下,单个字符使用多个字节表示,中途停止将是一个错误。
const int bufferSize = 1024;
var bytes = new byte[bufferSize];
var chars = new char[Encoding.UTF8.GetMaxCharCount(bufferSize)];
var decoder = Encoding.UTF8.GetDecoder();
// We don't know how long the result will be in chars, but one byte per char is a
// reasonable first approximation. This will expand as necessary.
var result = new StringBuilder(maxAllowedLimit);
int totalReadBytes = 0;
using (var stream = await response.Content.ReadAsStreamAsync())
{
while (totalReadBytes <= maxAllowedLimit)
{
int readBytes = await stream.ReadAsync(
bytes,
0,
Math.Min(maxAllowedLimit - totalReadBytes, bytes.Length));
// We reached the end of the stream
if (readBytes == 0)
break;
totalReadBytes += readBytes;
int readChars = decoder.GetChars(bytes, 0, readBytes, chars, 0);
result.Append(chars, 0, readChars);
}
}
请注意,您可能想要使用 HttpCompletionOption.ResponseHeadersRead
,否则 HttpClient
无论如何都会去下载整个正文。
如果您对字符的数量限制感到满意,那么生活会更轻松:
string result;
using (var reader = new StreamReader(await response.Content.ReadAsStreamAsync()))
{
char[] chars = new char[maxAllowedLimit];
int read = reader.ReadBlock(chars, 0, chars.Length);
result = new string(chars, 0, read);
}
我有一个案例,网络 API 调用 returns 一个非常大的字符串响应。我按如下方式拨打电话:
var multipartContent = new MultipartFormDataContent();
multipartContent.Add(new ByteArrayContent(blobStream.CopyToBytes()),
"upload", Path.GetFileName(fileName));
var response = await _httpClient.PostAsync("api/v1/textResponse", multipartContent);
int responeLength = response.Content.Headers.ContentLength.HasValue ?
(int)response.Content.Headers.ContentLength.Value : -1;
response.EnsureSuccessStatusCode();
我只需要处理响应中的前 1Mb 数据,因此如果响应小于 1Mb,我将全部读取,但如果大于 1Mb,我将很难停止读取。
我正在寻找最有效的阅读方式。我试过这段代码:
// section above...
response.EnsureSuccessStatusCode();
string contentText = null;
if (responeLength < maxAllowedLimit) // 1Mb
{
// less then limit - read all as string.
contentText = await response.Content.ReadAsStringAsync();
}
else {
var contentStream = await response.Content.ReadAsStreamAsync();
using (var stream = new MemoryStream())
{
byte[] buffer = new byte[5120]; // read in chunks of 5KB
int bytesRead;
while((bytesRead = contentStream.Read(buffer, 0, buffer.Length)) > 0)
{
stream.Write(buffer, 0, bytesRead);
}
contentText = stream.ConvertToString();
}
}
这是最有效的方法吗?我怎样才能限制读取量(其他)。我试过这段代码,它总是 returns 一个空字符串。还有:
ReadAsStringAsync()
ReadAsByteArrayAsync()
ReadAsStreamAsync()
LoadIntoBufferAsync(int size)
这些方法是否更有效?
提前感谢您的指点!
我怀疑最有效(但仍然正确)的方法可能是这样的。由于您对读取的 字节 的数量有限制,而不是 字符的数量 ,因此这变得更加复杂,因此我们不能使用 StreamReader
。请注意,我们必须小心不要在代码点的中间停止读取 - 在许多情况下,单个字符使用多个字节表示,中途停止将是一个错误。
const int bufferSize = 1024;
var bytes = new byte[bufferSize];
var chars = new char[Encoding.UTF8.GetMaxCharCount(bufferSize)];
var decoder = Encoding.UTF8.GetDecoder();
// We don't know how long the result will be in chars, but one byte per char is a
// reasonable first approximation. This will expand as necessary.
var result = new StringBuilder(maxAllowedLimit);
int totalReadBytes = 0;
using (var stream = await response.Content.ReadAsStreamAsync())
{
while (totalReadBytes <= maxAllowedLimit)
{
int readBytes = await stream.ReadAsync(
bytes,
0,
Math.Min(maxAllowedLimit - totalReadBytes, bytes.Length));
// We reached the end of the stream
if (readBytes == 0)
break;
totalReadBytes += readBytes;
int readChars = decoder.GetChars(bytes, 0, readBytes, chars, 0);
result.Append(chars, 0, readChars);
}
}
请注意,您可能想要使用 HttpCompletionOption.ResponseHeadersRead
,否则 HttpClient
无论如何都会去下载整个正文。
如果您对字符的数量限制感到满意,那么生活会更轻松:
string result;
using (var reader = new StreamReader(await response.Content.ReadAsStreamAsync()))
{
char[] chars = new char[maxAllowedLimit];
int read = reader.ReadBlock(chars, 0, chars.Length);
result = new string(chars, 0, read);
}