【问题标题】:Decode large Base64 strings解码大型 Base64 字符串
【发布时间】:2015-01-23 08:05:44
【问题描述】:

我有一个来自 WebService 的输入字符串,格式为大约 70 MB 大的 base64 编码字符串。

我想将它解码成一个文件,并尝试了显而易见的方法:使用Convert.FromBase64String()

然而,这会产生一个OutOfMemoryException。经过一番阅读,我发现Convert方法与Base64有关

内存泄漏(无疑是由于字符串的不可变特性和框架方法内部的一些糟糕设计) source

System.Security.Cryptography 命名空间中有一个方便的“流式”替换:FromBase64Transform

所以,我决定试一试,但我需要在方法中输入一个 bytes 的数组,而我没有 - 我有一个字符串。

我怎样才能将我拥有的string 转换为bytes 而不会在那个 转换中再次遇到另一个OutOfMemoryException

【问题讨论】:

  • 大对象堆是出了名的知之甚少。今天没有什么理由不在 64 位操作系统上运行 Web 服务。标准错误是忘记删除强制抖动,项目+属性,编译选项卡。

标签: c# base64 out-of-memory


【解决方案1】:

虽然您可能可以将字符串转换为内存中的字节数组而无需担心内存使用情况,但您可以通过以下方式流式传输转换:

var input = "abcdefghijklmnop";
byte[] output;
using (var ms = new MemoryStream())
using (var cs = new CryptoStream(ms, new FromBase64Transform(), CryptoStreamMode.Write))
using (var tr = new StreamWriter(cs))
{
    tr.Write(input);
    tr.Flush();
    output = ms.ToArray();
}

如果您将MemoryStream 替换为合适的FileStream,您可以直接流式传输到文件而不是数组:

var input = new string('a', 400000000);
byte[] output;
using (var ms = new FileStream(Guid.NewGuid().ToString() + ".bin", FileMode.Create))
using (var cs = new CryptoStream(ms, new FromBase64Transform(), CryptoStreamMode.Write))
using (var tr = new StreamWriter(cs))
{
    tr.Write(input);
    tr.Flush();
}

【讨论】:

    【解决方案2】:

    您应该使用Encoding.ASCII.GetBytes() 或类似方法将您的字符串转换回用于传输base64 编码数据的原始ASCII。

    我很好奇您最初是如何从WebService 收到字符串的。您是否可以跳过转换为 .NET 字符串而直接将接收到的字节传递给转换?这样会更有效率。

    【讨论】:

    • 响应是一个 JSON 响应,使用 NewtonSoft.Json 反序列化 - 它返回一个正确的对象。但我想我必须为这种类型的响应创建一些例外,所以我可以直接流式传输响应......
    • 那肯定会更好。不过,公平地说:使用 base64 的主要原因是处理无法流式传输二进制文件的情况,例如由于格式问题、API 限制等。如果您拥有的是 JSON,则可能会更麻烦比添加流媒体支持更值得(但如果您认为值得,您可以传输二进制文件并节省 25% 的带宽 :))。
    • 不幸的是,WebService 不在我的控制之下。我必须利用我从中得到的东西来工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-12
    • 2011-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多