C# 如何直接从流中读取二进制数组?
这里的“直接”是指没有临时C# 如何直接从流中读取二进制数组?,c#,arrays,C#,Arrays,这里的“直接”是指没有临时字节[]数组 问题是,例如,我在磁盘上有一个int或double数组,所以目前我创建了两个数组--字节数组和int数组(在int的情况下)。前者仅用于阅读,后者是实际输出 由于流只能读取字节数组,因此我将其读取到第一个数组,然后将所有数据复制到第二个数组。它是有效的,但它真的伤害了我(我不是在这里谈论性能) 那么,如何在没有临时数组的情况下读取数组呢?使用C#不安全的上下文对我来说很好 到目前为止,我尝试了两种方法:我看是否有可能创建一个重用分配内存的数组,第二种方法看
字节[]
数组
问题是,例如,我在磁盘上有一个int
或double
数组,所以目前我创建了两个数组--字节
数组和int
数组(在int
的情况下)。前者仅用于阅读,后者是实际输出
由于流
只能读取字节
数组,因此我将其读取到第一个数组,然后将所有数据复制到第二个数组。它是有效的,但它真的伤害了我(我不是在这里谈论性能)
那么,如何在没有临时数组的情况下读取数组呢?使用C#不安全的
上下文对我来说很好
到目前为止,我尝试了两种方法:我看是否有可能创建一个重用分配内存的数组,第二种方法看起来更有希望——我可以得到指向结果/秒数组的指针,在不安全的上下文中,我可以将它转换为字节*
指针。考虑到我的需要,它是100%安全和有效的,但是byte*
指针在C#world中不是byte[]
数组,我找不到将指针投射到数组的方法
代码:
据我所知,无法将数据直接从流复制到类型化数组。但是,您可以分块处理数据,将内存开销限制在固定的范围内。记忆将被复制两次,但据我所知,这是不可避免的 例如:
public static void ReadArrayDataChunked(BinaryReader binaryReader, Array target, Type type, int bufferSize = 4096)
{
var buffer = new byte[bufferSize];
var tSize = Marshal.SizeOf(type) ;
var remainingBytes = target.Length * tSize;
var targetPosition = 0;
while (remainingBytes > 0)
{
var toRead = Math.Min(remainingBytes, buffer.Length);
var bytesRead = binaryReader.Read(buffer, 0, toRead);
Buffer.BlockCopy(buffer, 0, target, targetPosition, bytesRead);
targetPosition += bytesRead;
remainingBytes -= bytesRead;
}
}
请注意,由于块复制,这仅适用于基本类型,但这有助于提高复制性能。您需要逐项读取其他类型。No。使用read()方法读取所需的字节数,并将其放入字节[]。您不需要读取整个流直到结束。在阅读之前,您可以检查流的位置和长度,以确保流中有足够的数据。您的问题不清楚。仅用您请求的字节填充可重用缓冲区。所以不涉及临时数组。如果您有很多并发操作,并且担心即使是这些缓冲区也会损害性能,那么您可以使用一个跨流重用相同的缓冲区。您当然不需要字节指针。如果您不想复制数组,可以使用
Span
@astrowalker,您可能应该发布代码而不是描述it@astrowalker所有语言、所有运行时、所有操作系统都是这样工作的。当您在C中使用字节*
时,您也会这样工作。有人分配了那个数组。由于每次都使用相同的缓冲区,因此即使是单个流也不会产生浪费或额外的GC。MemoryPool在需要跨数千条流保存内存时使用,例如当您拥有高流量web服务时。那么,真正的问题是什么?为什么要看字节*
?如果您想避免复制,请使用Stream.Read(Span)
BinaryReader
可用于从流的一部分读取整数和字节是的,谢谢,看起来我最终遵循了这条路径,因为我没有看到将我的“外部”需求(如双数组)与流API需求(字节数组)连接起来的粘合剂。如果您有一个double[]
并且想要一个byte[]
或者反之亦然,您可以直接执行块复制,无需流来执行。我的数据(double)在磁盘上,因此我首先需要流来读取它们。
public static void ReadArrayDataChunked(BinaryReader binaryReader, Array target, Type type, int bufferSize = 4096)
{
var buffer = new byte[bufferSize];
var tSize = Marshal.SizeOf(type) ;
var remainingBytes = target.Length * tSize;
var targetPosition = 0;
while (remainingBytes > 0)
{
var toRead = Math.Min(remainingBytes, buffer.Length);
var bytesRead = binaryReader.Read(buffer, 0, toRead);
Buffer.BlockCopy(buffer, 0, target, targetPosition, bytesRead);
targetPosition += bytesRead;
remainingBytes -= bytesRead;
}
}