我需要帮助将一个非常大的二进制文件(ZIP 文件)转换为 Base64String 并再次转换回来。这些文件太大了,无法一次性加载到内存中(会抛出 OutOfMemoryExceptions 异常),否则这将是一个简单的任务。我不想逐个处理 ZIP 文件的内容,而是要处理整个 ZIP 文件。
问题:
我可以将整个 ZIP 文件(测试大小目前变化从 1 MB 到 800 MB 不等)转换为 Base64String,但当我将其转换回来时,它就被损坏了。新的 ZIP 文件大小正确,Windows 和 WinRAR / 7-Zip 等软件也能识别它为 ZIP 文件,并且我甚至可以查看 ZIP 文件中的内容以及其正确的大小/属性,但是当我尝试从 ZIP 文件中提取时,我会收到:“ Error: 0x80004005 ”的错误代码。
我不确定损坏发生在哪里或为什么会发生。我已经进行了一些调查,并注意到以下事项:
如果您有一个大文本文件,可以逐步将其转换为 Base64String,而没有任何问题。如果对整个文件调用 Convert.ToBase64String
得到的结果是:"abcdefghijklmnopqrstuvwx",那么将其分成两部分并分别调用会得到:"abcdefghijkl"和"mnopqrstuvwx"。
不幸的是,如果文件是二进制的,则结果会有所不同。虽然整个文件可能会得到:"abcdefghijklmnopqrstuvwx",但尝试在两个部分中处理它将产生类似于:"oiweh87yakgb" 和 "kyckshfguywp" 的东西。
有没有一种方式可以逐步对二进制文件进行 base64 编码而避免此类损坏?
我的代码:
private void ConvertLargeFile()
{
FileStream inputStream = new FileStream("C:\\Users\\test\\Desktop\\my.zip", FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[MultipleOfThree];
int bytesRead = inputStream.Read(buffer, 0, buffer.Length);
while(bytesRead > 0)
{
byte[] secondaryBuffer = new byte[buffer.Length];
int secondaryBufferBytesRead = bytesRead;
Array.Copy(buffer, secondaryBuffer, buffer.Length);
bool isFinalChunk = false;
Array.Clear(buffer, 0, buffer.Length);
bytesRead = inputStream.Read(buffer, 0, buffer.Length);
if(bytesRead == 0)
{
isFinalChunk = true;
buffer = new byte[secondaryBufferBytesRead];
Array.Copy(secondaryBuffer, buffer, buffer.length);
}
String base64String = Convert.ToBase64String(isFinalChunk ? buffer : secondaryBuffer);
File.AppendAllText("C:\\Users\\test\\Desktop\\Base64Zip", base64String);
}
inputStream.Dispose();
}
解码部分与之前相同。我使用上面的base64String
变量的大小(它取决于我测试时原始缓冲区的大小)作为解码的缓冲区大小。然后,我调用Convert.FromBase64String()
而不是Convert.ToBase64String()
,并将结果写入不同的文件名/路径。
编辑:
为了减少代码(我将其重构为一个新项目,与其他处理分开以消除与问题无关的代码),我匆忙地引入了一个错误。对于除最后一次迭代(通过isFinalChunk
标识)以外的所有迭代,应在secondaryBuffer
上执行base64转换,而在最后一次迭代时应使用buffer
。我已经更正了上面的代码。
编辑#2:
感谢大家的评论/反馈。在更正了错误之后(请参见上面的编辑),我重新测试了我的代码,现在它确实可以工作了。我打算测试和实施@rene的解决方案,因为它似乎是最好的,但我认为我也应该让每个人知道我的发现。
isFinalChunk
吗?看起来你正在对已清除的缓冲区调用ToBase64String
,除非它是最后一个块。 - BlorgbeardsecondaryBuffer
,其中包含所需的数据。 - CaptainCobol