【问题标题】:Read large file into byte array and encode it to ToBase64String将大文件读入字节数组并将其编码为 ToBase64String
【发布时间】:2018-09-10 14:27:18
【问题描述】:

我已经实现了 POC 将整个文件内容读入 Byte[] 数组。我现在成功读取了大小低于 100MB 的文件,当我加载大小超过 100MB 的文件时,它会抛出

Convert.ToBase64String(mybytearray) 无法获取 局部变量或参数,因为没有足够的内存 可用。

以下是我尝试将内容从文件读取到字节数组的代码

var sFile = fileName;
var mybytearray = File.ReadAllBytes(sFile);

var binaryModel = new BinaryModel
{
    fileName = binaryFile.FileName,
    binaryData = Convert.ToBase64String(mybytearray),
    filePath = string.Empty
};

我的模型类如下

public class BinaryModel
{
    public string fileName { get; set; }
    public string binaryData { get; set; }
    public string filePath { get; set; }
}

我收到“Convert.ToBase64String(mybytearray) 无法获取局部变量或参数的值,因为没有足够的可用内存。” Convert.ToBase64String(mybytearray) 处出现此错误。

我需要注意什么以防止出现此错误吗?

注意:我不想在我的文件内容中添加换行符

【问题讨论】:

  • 在通常情况下,加载和编码 100mb 根本不会引起任何问题,还有其他事情发生 - 我认为您需要添加更多细节,包括完整的堆栈跟踪和异常消息,有你发布的那个没有谷歌点击。
  • 默认情况下,对象的最大大小为 2GB,这可能就像 @AlexK 所说的那样。问题不在于 100MB 数组的声明
  • 我认为这将是非常不可行的。你最大的文件有多大?例如,如果您有一个 500 MB 的文件,您正在谈论的字符串长度约为 699,050,660 个字符。因为每个字符是 2 个字节,所以你说 1.3 GB 的内存只是为了保存这个字符串。
  • @AlexK。 - 这不是文件的数组,我猜问题在于将二进制流转换为 Base64 编码的字符串。该比率基本上是“数组”长度的 8/6 或大约 1.3 增加,但请记住,由于这些现在是数组中的 chars,我们将数据要求加倍。所以一个 500 MB 的文件变成了一个 1.3 GB 的字符串数组。一个 200 MB 的文件将是一个大约 530 MB 的字符串。
  • @Vijay - 您是否可以将其作为流执行,读取并将其写入文件或其他内容,或者您​​是否需要将该字符串保存在内存中(作为@987654324 的一部分@)。我认为没有任何方法可以让您将整个字符串保存在内存中。正如您从建议的答案中看到的那样,每个答案都显示将此数据直接写回文件。

标签: c# base64 filereader


【解决方案1】:

为了节省内存,您可以将字节流转换为 3 包。每三个字节在 Base64 中产生 4 个字节。您不需要一次将整个文件存储在内存中。

这是伪代码:

Repeat
1. Try to read max 3 bytes from stream
2. Convert to base64, write to output stream

以及简单的实现:

using (var inStream = File.OpenRead("E:\\Temp\\File.xml"))
using (var outStream = File.CreateText("E:\\Temp\\File.base64"))
{
    var buffer = new byte[3];
    int read;
    while ((read = inStream.Read(buffer, 0, 3)) > 0)
    {
        var base64 = Convert.ToBase64String(buffer, 0, read);
        outStream.Write(base64);
    }
}

提示:每乘以 3 都是有效的。更高 - 更多内存,更好的性能,更低 - 更少的内存,更差的性能。

其他信息:

文件流就是一个例子。结果流使用[HttpContext].Response.OutputStream 并直接写入它。在一个块中处理数百兆字节会杀死你和你的服务器。

考虑总内存需求。 100MB 的字符串,导致 133MB 的字节数组,因为你写了模型我希望这 133MB 的副本作为回应。请记住,这只是一个简单的请求。一些这样的请求可能会耗尽你的记忆。

【讨论】:

    【解决方案2】:

    我会使用两个文件流——一个用于读取大文件,一个用于将结果写回。

    因此,您可以分块转换为 base 64 ... 然后将生成的字符串转换为字节 ... 并写入。

        private static void ConvertLargeFileToBase64()
        {
            var buffer = new byte[16 * 1024];
            using (var fsIn = new FileStream("D:\\in.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                using (var fsOut = new FileStream("D:\\out.txt", FileMode.CreateNew, FileAccess.Write))
                {
                    int read;
                    while ((read = fsIn.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        // convert to base 64 and convert to bytes for writing back to file
                        var b64 = Encoding.ASCII.GetBytes(Convert.ToBase64String(buffer));
    
                        // write to the output filestream
                        fsOut.Write(b64, 0, read);
                    }
    
                    fsOut.Close();
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 2018-12-23
      • 1970-01-01
      • 2022-10-19
      • 1970-01-01
      • 2015-08-01
      • 2013-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多