【问题标题】:System.OutofMemoryException Error when Convert.ToBase64String()Convert.ToBase64String() 时发生 System.OutofMemoryException 错误
【发布时间】:2018-07-26 21:41:31
【问题描述】:

我正在尝试使用以下方法将 zip 文件转换为文本文件 (xml)。它适用于较小的文件,但似乎不适用于大于 50 mb 的文件。

class Program
{
    public static void Main(string[] args)
    {
        try
        {

            string importFilePath = @"D:\CorpTax\Tasks\966442\CS Publish error\CSUPD20180604L.zip";

            int maxLengthInMb = 20;
            byte[] payLoad = File.ReadAllBytes(importFilePath);
            int payLoadInMb = (payLoad.Length / 1024) / 1024;
            bool splitIntoMultipleFiles = (payLoadInMb / maxLengthInMb) > 1;
            int payLoadLength = splitIntoMultipleFiles ? maxLengthInMb * 1024 * 1024 : payLoad.Length;

            if (splitIntoMultipleFiles)
            {
                foreach (byte[] splitPayLoad in payLoad.Slices(payLoadLength))
                {
                    ToXml(payLoad);
                }
            }              
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
    }

    public static string ToXml(byte[] payLoad)
    {
        using (XmlStringWriter xmlStringWriter = new XmlStringWriter())
        {
            xmlStringWriter.WriteStartDocument();
            xmlStringWriter.Writer.WriteStartElement("Payload");

            xmlStringWriter.Writer.WriteRaw(Convert.ToBase64String(payLoad));
            xmlStringWriter.Writer.WriteEndElement();
            xmlStringWriter.WriteEndDocument();
            return xmlStringWriter.ToString();
        }
    }
}

我有一个 120 MB 大小的 .zip 文件,我得到了 System.OutOfMemoryException 调用 Convert.ToBase64String() 时。

所以我继续将字节数组拆分为 20 mb 大小的块,希望它不会失败。但是我看到它一直有效,直到它通过循环 3 次,即能够转换 60mb 的数据,并且在第 4 次迭代中我得到了同样的异常。有时我也会在 return xmlStringWriter.ToString()

行遇到异常

为了拆分字节[],我使用了以下扩展类

public static class ArrayExtensions
{
    public static T[] CopySlice<T>(this T[] source, int index, int length, bool padToLength = false)
    {
        int n = length;
        T[] slice = null;

        if (source.Length < index + length)
        {
            n = source.Length - index;
            if (padToLength)
            {
                slice = new T[length];
            }
        }

        if (slice == null) slice = new T[n];
        Array.Copy(source, index, slice, 0, n);
        return slice;
    }
    public static IEnumerable<T[]> Slices<T>(this T[] source, int count, bool padToLength = false)
    {
        for (var i = 0; i < source.Length; i += count)
        {
            yield return source.CopySlice(i, count, padToLength);
        }
    }
}

我从以下链接获得了上面的代码 Splitting a byte[] into multiple byte[] arrays in C#

有趣的是,当我在控制台应用程序中运行程序时,程序运行良好,但是当我将此代码放入 Windows 应用程序时,它会抛出 System.OutOfMemoryException

【问题讨论】:

  • 您应该使用Stream 而不是byte[]
  • Project > Properties > Build 选项卡,取消勾选“Prefer 32-bit”复选框。你不喜欢它。
  • 请注意,尝试计算切片的 Base64 不会给出相同的结果。甚至没有接近:dotnetfiddle.net/IUtlzH
  • 一般来说,尝试一次操作内存中如此大量的数据是个坏主意。字符串构建器、xml 构建器等不是为这种情况设计的。我的建议是找到或实现一个 streaming 构建器,它可以直接转储到磁盘,而不是在内存中构建如此庞大的结构。
  • 这也是一种反模式。此时不将 zip 文件放在 xml 中似乎更好。

标签: c# .net


【解决方案1】:

最好你想做这样的事情

            byte[] Packet = new byte[4096];
            string b64str = "";
            using (FileStream fs = new FileStream(file, FileMode.Open))
            {
                int i = Packet.Length;
                while (i == Packet.Length)
                {
                    i = fs.Read(Packet, 0, Packet.Length);
                    b64str = Convert.ToBase64String(Packet, 0, i);
                }
            }

您应该使用该 b64str 创建您的 xml 数据。 此外,一次性在堆栈上分配 20mb 空间通常是不明智的。

【讨论】:

  • @user6520378 np。也研究这个。这是在 c# 中读取文件的最常用方法,大多数人会读取流的一部分并对其进行处理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-04
  • 2013-11-11
  • 2020-06-21
  • 1970-01-01
相关资源
最近更新 更多