从输入流创建字节数组的首选方法是什么?
下面是我目前使用。net 3.5的解决方案。
Stream s;
byte[] b;
using (BinaryReader br = new BinaryReader(s))
{
b = br.ReadBytes((int)s.Length);
}
读写流的块仍然是一个更好的主意吗?
从输入流创建字节数组的首选方法是什么?
下面是我目前使用。net 3.5的解决方案。
Stream s;
byte[] b;
using (BinaryReader br = new BinaryReader(s))
{
b = br.ReadBytes((int)s.Length);
}
读写流的块仍然是一个更好的主意吗?
当前回答
如果流支持Length属性,则可以直接创建字节数组。其优点是MemoryStream。ToArray创建两次数组。另外,缓冲区中可能还有一些未使用的额外字节。此解决方案分配所需的精确数组。如果流不支持Length属性,它将抛出NotSupportedException异常。
同样值得注意的是,数组不能大于int.MaxValue。
public static async Task<byte[]> ToArrayAsync(this Stream stream)
{
var array = new byte[stream.Length];
await stream.ReadAsync(array, 0, (int)stream.Length);
return array;
}
根据流是否支持搜索在两个版本之间切换的完整代码。它包括检查位置和不可靠的长度。这可能会略微降低速度。在我的测试中,ToArrayAsyncDirect比ToArrayAsyncGeneral快3倍。
public static class StreamExtensions
{
public static readonly byte[] TempArray = new byte[4];
/// <summary>
/// Converts stream to byte array.
/// </summary>
/// <param name="stream">Stream</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>Stream data as array</returns>
/// <returns>Binary data from stream in an array</returns>
public static async Task<byte[]> ToArrayAsync(this Stream stream, CancellationToken cancellationToken)
{
if (!stream.CanRead)
{
throw new AccessViolationException("Stream cannot be read");
}
if (stream.CanSeek)
{
return await ToArrayAsyncDirect(stream, cancellationToken);
}
else
{
return await ToArrayAsyncGeneral(stream, cancellationToken);
}
}
/// <summary>
/// Converts stream to byte array through MemoryStream. This doubles allocations compared to ToArrayAsyncDirect.
/// </summary>
/// <param name="stream">Stream</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns></returns>
private static async Task<byte[]> ToArrayAsyncGeneral(Stream stream, CancellationToken cancellationToken)
{
using MemoryStream memoryStream = new MemoryStream();
await stream.CopyToAsync(memoryStream, cancellationToken);
return memoryStream.ToArray();
}
/// <summary>
/// Converts stream to byte array without unnecessary allocations.
/// </summary>
/// <param name="stream">Stream</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>Stream data as array</returns>
/// <exception cref="ArgumentException">Thrown if stream is not providing correct Length</exception>
private static async Task<byte[]> ToArrayAsyncDirect(Stream stream, CancellationToken cancellationToken)
{
if (stream.Position > 0)
{
throw new ArgumentException("Stream is not at the start!");
}
var array = new byte[stream.Length];
int bytesRead = await stream.ReadAsync(array, 0, (int)stream.Length, cancellationToken);
if (bytesRead != array.Length ||
await stream.ReadAsync(TempArray, 0, TempArray.Length, cancellationToken) > 0)
{
throw new ArgumentException("Stream does not have reliable Length!");
}
return array;
}
}
其他回答
您可以使用这个扩展方法。
public static class StreamExtensions
{
public static byte[] ToByteArray(this Stream stream)
{
var bytes = new List<byte>();
int b;
// -1 is a special value that mark the end of the stream
while ((b = stream.ReadByte()) != -1)
bytes.Add((byte)b);
return bytes.ToArray();
}
}
只是想指出,如果你有一个MemoryStream,你已经有了MemoryStream。toarray()。
同样,如果你正在处理未知的流或不同的子类型,你可以接收一个MemoryStream,你可以在这些情况下对上述方法进行中继,而对其他情况仍然使用接受的答案,如下所示:
public static byte[] StreamToByteArray(Stream stream)
{
if (stream is MemoryStream)
{
return ((MemoryStream)stream).ToArray();
}
else
{
// Jon Skeet's accepted answer
return ReadFully(stream);
}
}
这是我正在使用的功能,测试和工作良好。 请记住“input”不应该是空的,而应该是“input”。Position '应该在读取之前重置为'0',否则它将打破读取循环,并且不会读取任何东西来转换为数组。
public static byte[] StreamToByteArray(Stream input)
{
if (input == null)
return null;
byte[] buffer = new byte[16 * 1024];
input.Position = 0;
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
byte[] temp = ms.ToArray();
return temp;
}
}
只是我的几毛钱……我经常使用的做法是将这些方法组织成一个自定义助手
public static class StreamHelpers
{
public static byte[] ReadFully(this Stream input)
{
using (MemoryStream ms = new MemoryStream())
{
input.CopyTo(ms);
return ms.ToArray();
}
}
}
将命名空间添加到配置文件中,并在任何地方使用它
如果流支持Length属性,则可以直接创建字节数组。其优点是MemoryStream。ToArray创建两次数组。另外,缓冲区中可能还有一些未使用的额外字节。此解决方案分配所需的精确数组。如果流不支持Length属性,它将抛出NotSupportedException异常。
同样值得注意的是,数组不能大于int.MaxValue。
public static async Task<byte[]> ToArrayAsync(this Stream stream)
{
var array = new byte[stream.Length];
await stream.ReadAsync(array, 0, (int)stream.Length);
return array;
}
根据流是否支持搜索在两个版本之间切换的完整代码。它包括检查位置和不可靠的长度。这可能会略微降低速度。在我的测试中,ToArrayAsyncDirect比ToArrayAsyncGeneral快3倍。
public static class StreamExtensions
{
public static readonly byte[] TempArray = new byte[4];
/// <summary>
/// Converts stream to byte array.
/// </summary>
/// <param name="stream">Stream</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>Stream data as array</returns>
/// <returns>Binary data from stream in an array</returns>
public static async Task<byte[]> ToArrayAsync(this Stream stream, CancellationToken cancellationToken)
{
if (!stream.CanRead)
{
throw new AccessViolationException("Stream cannot be read");
}
if (stream.CanSeek)
{
return await ToArrayAsyncDirect(stream, cancellationToken);
}
else
{
return await ToArrayAsyncGeneral(stream, cancellationToken);
}
}
/// <summary>
/// Converts stream to byte array through MemoryStream. This doubles allocations compared to ToArrayAsyncDirect.
/// </summary>
/// <param name="stream">Stream</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns></returns>
private static async Task<byte[]> ToArrayAsyncGeneral(Stream stream, CancellationToken cancellationToken)
{
using MemoryStream memoryStream = new MemoryStream();
await stream.CopyToAsync(memoryStream, cancellationToken);
return memoryStream.ToArray();
}
/// <summary>
/// Converts stream to byte array without unnecessary allocations.
/// </summary>
/// <param name="stream">Stream</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>Stream data as array</returns>
/// <exception cref="ArgumentException">Thrown if stream is not providing correct Length</exception>
private static async Task<byte[]> ToArrayAsyncDirect(Stream stream, CancellationToken cancellationToken)
{
if (stream.Position > 0)
{
throw new ArgumentException("Stream is not at the start!");
}
var array = new byte[stream.Length];
int bytesRead = await stream.ReadAsync(array, 0, (int)stream.Length, cancellationToken);
if (bytesRead != array.Length ||
await stream.ReadAsync(TempArray, 0, TempArray.Length, cancellationToken) > 0)
{
throw new ArgumentException("Stream does not have reliable Length!");
}
return array;
}
}