将zip文件编码为Base64

5

我想将zip文件解码为base64字符串。文件可能达到100 MB,会抛出OutOfMemory异常并重新启动Visual Studio。我的编码代码如下:

public static string EncodeToBase64(string zipPath)
{
    using (FileStream fs = new FileStream(zipPath, FileMode.Open, FileAccess.Read))
    {
       byte[] filebytes = new byte[fs.Length];
       fs.Read(filebytes, 0, Convert.ToInt32(fs.Length));
       return Convert.ToBase64String(filebytes);
    }
}

我该怎么解决这个问题?

1
100 MB不应该是问题。你的RAM满了吗?另外,你需要在代码中使用base64字符串还是要将其保存/发送到其他地方? - Christoph Fink
如果你一遍又一遍地重复操作,100MB很容易成为一个问题。 - David Heffernan
我有很多内存,但是当编码为base64时,RAM会迅速增加。我用于保存和发送的是base64字符串。 - user3305198
一个32位程序运行一段时间后,有机会分配地址空间(与RAM无关),分配90MB很容易失败。在程序真正耗尽内存之前,就已经没有足够大的空洞来适应这个分配了。否则,在C#中允许程序作为64位进程运行可以轻松解决这个问题。 - Hans Passant
2个回答

3

不要试图一次性完成整个操作。

从文件流中逐字节循环。获取三个字节的倍数并进行编码。一定要使用StringBuilder来构建输出。

这将大大减少内存使用量。


1
<注意:本回答假设您可以分块处理最终的base 64字符串,例如通过将每个块依次写入某种流中进行处理。>

如果您编写一个帮助方法来读取文件并将其分块为最大大小的byte[]块,则此过程将变得简化,例如:

public static IEnumerable<byte[]> ReadFileInBlocks(string filename, int blockSize)
{
    byte[] buffer = new byte[blockSize];

    using (var file = File.OpenRead(filename))
    {
        while (true)
        {
            int n = file.Read(buffer, 0, buffer.Length);

            if (n == buffer.Length)
            {
                yield return buffer;
            }
            else if (n > 0) // Must be the last block in the file (because n != buffer.Length)
            {
                Array.Resize(ref buffer, n);
                yield return buffer;         // Just this last block to return,
                break;                       // and then we're done.
            }
            else // Exactly read to end of file in previous read, so we're already done.
            {
                break;
            }
        }
    }
}

然后,您可以编写一个简单的方法,依次从文件中每个字节块转换为一系列Base64字符串。
public static IEnumerable<string> ToBase64Strings(string filename, int blockSize)
{
    return ReadFileInBlocks(filename, blockSize).Select(Convert.ToBase64String);
}

假设您有一种处理每个转换后的Base-64字符串块的方法,那么请按照以下步骤操作:
foreach (var base64String in ToBase64Strings(myFilename, 1024))
    process(base64String);

或者,您可以跳过中介的ReadFileInBlocks()方法,并将转换为base 64字符串的步骤合并到其中,如下所示:

public IEnumerable<string> ConvertToBase64StringInBlocks(string filename, int blockSize)
{
    byte[] buffer = new byte[blockSize];

    using (var file = File.OpenRead(filename))
    {
        while (true)
        {
            int n = file.Read(buffer, 0, buffer.Length);

            if (n == 0) // Exactly read to end of file in previous read, so we're already done.
            {
                break;
            }
            else
            {
                yield return Convert.ToBase64String(buffer, 0, n);
            }
        }
    }
}

Matthew Watson,我该如何将Base64字符串解码为zip文件? - user3305198

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接