GZIP解压C#OutOfMemory
我从ftp下载了许多大型gzip文件(大约10MB-200MB)进行解压缩 所以我试着用谷歌搜索并找到一些gzip解压的解决方案GZIP解压C#OutOfMemory,c#,gzip,out-of-memory,compression,gzipstream,C#,Gzip,Out Of Memory,Compression,Gzipstream,我从ftp下载了许多大型gzip文件(大约10MB-200MB)进行解压缩 所以我试着用谷歌搜索并找到一些gzip解压的解决方案 static byte[] Decompress(byte[] gzip) { using (GZipStream stream = new GZipStream(new MemoryStream(gzip), CompressionMode.Decompress)) { const int si
static byte[] Decompress(byte[] gzip)
{
using (GZipStream stream = new GZipStream(new MemoryStream(gzip), CompressionMode.Decompress))
{
const int size = 4096;
byte[] buffer = new byte[size];
using (MemoryStream memory = new MemoryStream())
{
int count = 0;
do
{
count = stream.Read(buffer, 0, size);
if (count > 0)
{
memory.Write(buffer, 0, count);
}
}
while (count > 0);
return memory.ToArray();
}
}
}
它适用于任何低于50mb的文件,但一旦输入超过50mb,就会出现系统内存不足异常。异常前的最后一个位置和内存长度为134217728。我不认为这与我的物理内存有关,我知道我不能拥有超过2GB的对象,因为我使用32位
我还需要在解压缩文件后处理数据。我不确定内存流是否是这里的最佳方法,但我真的不喜欢先写入文件,然后再读取文件
我的问题
- 为什么我得到System.OutMemoryException
- 解压gzip文件并随后进行文本处理的最佳解决方案是什么
编写一个下载文件的脚本,然后使用gzip或7zip等工具对其进行解压缩,然后对其进行处理。根据处理类型、文件数量和总大小,您必须在某个时候保存它们,以避免此类内存问题。解压后保存它们并立即处理1MB。您可以尝试以下测试,以了解在获得OutOfMemoryException之前,您可以向MemoryStream写入多少内容:
const int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
int fileSize = 1000 * 1024 * 1024;
int total = 0;
try
{
using (MemoryStream memory = new MemoryStream())
{
while (total < fileSize)
{
memory.Write(buffer, 0, bufferSize);
total += bufferSize;
}
}
MessageBox.Show("No errors");
}
catch (OutOfMemoryException)
{
MessageBox.Show("OutOfMemory around size : " + (total / (1024m * 1024.0m)) + "MB" );
}
const int bufferSize=4096;
字节[]缓冲区=新字节[bufferSize];
int fileSize=1000*1024*1024;
int-total=0;
尝试
{
使用(MemoryStream memory=new MemoryStream())
{
while(总数<文件大小)
{
写入(缓冲区,0,缓冲区大小);
总+=缓冲区大小;
}
}
MessageBox.Show(“无错误”);
}
捕获(OutOfMemoryException)
{
MessageBox.Show(“大约大小的OutOfMemory:+(总计/(1024m*1024.0m))+“MB”);
}
您可能需要先解压缩到一个临时物理文件,然后分小块重新读取它,然后边走边处理
旁白:有趣的是,在WindowsXP PC上,当代码针对.NET2.0时,上面的代码给出了“大约256MB大小的OutOfMemory”,而在.NET4上给出了“大约512MB大小的OutOfMemory” MemoryStream的内存分配策略对大量数据不友好 因为MemoryStream的契约是将连续数组作为底层存储,所以它必须经常重新分配数组以适应大数据流(通常为log2(大小为\u的\u流))。这种再分配的副作用是
- 重新分配时的长拷贝延迟
- 新的阵列必须适合可用的地址空间,因为以前的分配已经严重碎片化
- 新阵列将位于LOH堆上,该堆有其独特之处(无压缩,在GC2上收集)
- 最便宜的方法是将MemoryStream预增长到您需要的大小(最好稍微大一点)。您可以预先计算读取不存储任何内容的伪流所需的大小(浪费CPU资源,但您可以读取它)。还考虑返回流而不是字节数组(或返回内存字节数组的长度与内存流)。
- 如果需要整个流或字节数组,另一种处理方法是使用临时文件流而不是MemoryStream来存储大量数据李>
- 更复杂的方法是实现将底层数据分块成更小(即64K)块的流,以避免在LOH上分配和在流需要增长时复制数据
但在当前情况下,您可以使用内存映射文件来绕过任何地址大小限制。如果您使用的是.NET 4.0,它将为Windows函数提供本机包装。您正在将流的全部内容加载到内存中,并将其作为字节数组返回。除了内存不足异常,您还希望发生什么?您不应该像这样将其全部加载到内存中--您最终打算如何处理该数组?将其写入文件?不管你想要什么,它都应该是基于流的,而不是基于数组的。。该异常发生在memory.write上,并卡在134217728中。。我不熟悉内存管理,所以请耐心听我说。稍后我会将所有处理过的文件保存到数据库中,gzip文件中的文件是csv fileSure,但如果在解压时对其进行处理,您的设计会更好。这样,您就不必分配大量内存来处理它。(例如,通过将gzip流直接放入
Strea