可以将二维字节数组制成一个巨大的连续字节数组吗?
Posted
技术标签:
【中文标题】可以将二维字节数组制成一个巨大的连续字节数组吗?【英文标题】:Can as 2D byte array be made one huge continuous byte array? 【发布时间】:2011-04-08 18:24:23 【问题描述】:我在内存中有一个非常大的二维字节数组,
byte MyBA = new byte[int.MaxValue][10];
有什么方法(可能是不安全的)可以让 C# 误以为这是一个巨大的连续字节数组?我想这样做,以便可以将其传递给 MemoryStream
,然后传递给 BinaryReader
。
MyReader = new BinaryReader(MemoryStream(*MyBA)) //Syntax obviously made-up here
【问题讨论】:
我理解你的问题,但你为什么要分配这么大的数组??我毫不怀疑,即使您成功解决了这个技术问题,您的架构也是错误的,您尝试开发的程序最终也无法正常工作。 Gilad,我需要分配一个大数组才能在内存中处理它。速度对我来说是关键问题。另外,我有很多线程都同时处理相同的数据。我理解您的担忧,但是架构已经可以处理高达任意限制的数据,即字节数组的最大大小。如果我可以删除此限制(或愚弄 c#),那么我看不出它不应该继续工作的理由。 假设 int 是 32 位,每个 10 位,那你的数组不是 40 GB 吗? 【参考方案1】:我不相信 .NET 提供此功能,但实现您自己的 System.IO.Stream
实现应该相当容易,它可以无缝切换支持数组。以下是(未经测试的)基础知识:
public class MultiArrayMemoryStream: System.IO.Stream
byte[][] _arrays;
long _position;
int _arrayNumber;
int _posInArray;
public MultiArrayMemoryStream(byte[][] arrays)
_arrays = arrays;
_position = 0;
_arrayNumber = 0;
_posInArray = 0;
public override int Read(byte[] buffer, int offset, int count)
int read = 0;
while(read<count)
if(_arrayNumber>=_arrays.Length)
return read;
if(count-read <= _arrays[_arrayNumber].Length - _posInArray)
Buffer.BlockCopy(_arrays[_arrayNumber], _posInArray, buffer, offset+read, count-read);
_posInArray+=count-read;
_position+=count-read;
read=count;
else
Buffer.BlockCopy(_arrays[_arrayNumber], _posInArray, buffer, offset+read, _arrays[_arrayNumber].Length - _posInArray);
read+=_arrays[_arrayNumber].Length - _posInArray;
_position+=_arrays[_arrayNumber].Length - _posInArray;
_arrayNumber++;
_posInArray=0;
return count;
public override long Length
get
long res = 0;
for(int i=0;i<_arrays.Length;i++)
res+=_arrays[i].Length;
return res;
public override long Position
get return _position;
set throw new NotSupportedException();
public override bool CanRead
get return true;
public override bool CanSeek
get return false;
public override bool CanWrite
get return false;
public override void Flush()
public override void Seek(long offset, SeekOrigin origin)
throw new NotSupportedException();
public override void SetLength(long value)
throw new NotSupportedException();
public override void Write(byte[] buffer, int offset, int count)
throw new NotSupportedException();
另一种解决 2^31 字节大小限制的方法是 UnmanagedMemoryStream
,它在非托管内存缓冲区(可能与操作系统支持的一样大)之上实现 System.IO.Stream
。像这样的东西可能会起作用(未经测试):
var fileStream = new FileStream("data",
FileMode.Open,
FileAccess.Read,
FileShare.Read,
16 * 1024,
FileOptions.SequentialScan);
long length = fileStream.Length;
IntPtr buffer = Marshal.AllocHGlobal(new IntPtr(length));
var memoryStream = new UnmanagedMemoryStream((byte*) buffer.ToPointer(), length, length, FileAccess.ReadWrite);
fileStream.CopyTo(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
// work with the UnmanagedMemoryStream
Marshal.FreeHGlobal(buffer);
【讨论】:
Rasmus - 我没听说过 - 我会查一下 - 谢谢 Rasmus - 看起来很有趣。 您能否指导我在示例中如何最好地将字节流从磁盘加载到 UnmanagedMemoryStream 中? 谢谢拉斯马斯 - 我正在处理你在这里给我的东西 Rasmus - 我做不到。几乎没有使用 SafeBuffer 的文档或示例,我得到“无法创建 ... SafeBuffer 的实例”。【参考方案2】:同意。无论如何,你有数组大小本身的限制。
如果你真的需要在流中操作巨大的数组,编写你的自定义内存流类。
【讨论】:
是的 _ 我已经考虑过了——但是当我尝试跨越字节数组边界读取写入自定义流类时,这给了我一个单独的问题——我对此还有另一个问题。【参考方案3】:我认为您可以使用以下方法使用线性结构而不是二维结构。
您可以使用 byte[int.MaxValue*10] 而不是 byte[int.MaxValue][10]。您可以将 [4,5] 处的项目寻址为 int.MaxValue*(4-1)+(5-1)。 (一般公式是(i-1)*列数+(j-1)。
当然你可以使用其他约定。
【讨论】:
他使用2D结构的原因是他超出了单字节数组的大小限制。【参考方案4】:如果我正确理解了您的问题,那么您有一个庞大的文件,您想将其读入内存然后进行处理。但是你不能这样做,因为文件中的数据量超过了任何一维数组。
您提到速度很重要,并且您有多个线程并行运行以尽可能快地处理数据。如果您无论如何都必须为每个线程划分数据,为什么不将线程数基于覆盖所有内容所需的byte[int.MaxValue]
缓冲区数?
【讨论】:
对不起,应该说清楚。我的每个线程都运行在整个数据上。 我明白了。所以你正在做一些事情,比如对数据应用多个过滤器,而不是使用线程来更快地处理一组数据?只是想看看是否有另一种方法可以用来解决这个内存限制。【参考方案5】:您可以创建一个memoryStream,然后使用Write方法逐行传递数组
编辑: MemoryStream 的限制当然是您的应用程序存在的内存量。也许有一个限制,但如果您需要更多内存,那么您应该考虑修改您的整体架构。例如。您可以分块处理数据,也可以对文件执行交换机制。
【讨论】:
是的 - 我这样做。但我相信 MemoryStream 仍然有一个最大限制,你可以写入多少 - 这与字节数组的最大大小相同......【参考方案6】:如果您使用的是 Framework 4.0,您可以选择使用 MemoryMappedFile。内存映射文件可以由物理文件或 Windows 交换文件支持。内存映射文件就像内存中的流一样,在需要时透明地与后备存储交换数据。
如果您不使用 Framework 4.0,您仍然可以使用此选项,但您需要自己编写或找到现有的包装器。我希望The Code Project 上有很多。
【讨论】:
谢谢克里斯。我尝试了该选项,但 MemoryMappedFiles 非常慢。 @ManInMoon,这很不幸。性能下降可能是因为从用户空间到内核空间的转换,因为 MemoryMappedFiles 是内核对象。 @ManInMoon,数据的来源是什么?它是从文件中读入内存的吗?以上是关于可以将二维字节数组制成一个巨大的连续字节数组吗?的主要内容,如果未能解决你的问题,请参考以下文章