首页 > 解决方案 > 大字节数组 - 在字节数组中存储长度有什么好处?

问题描述

问:在数组本身中存储大数组的长度有什么好处吗?

解释:

假设我们使用 System.IO.Compression 命名空间的 GZipStream 类来压缩一些大型二进制序列化对象。输出将是一些压缩字节数组的 Base64 字符串。在稍后的某个时间点,Base64 字符串被转换回字节数组,并且需要解压缩数据。

在压缩数据时,我们创建一个新的字节数组,其大小为压缩字节数组 + 4。在前 4 个字节中,我们存储压缩字节数组的长度/大小,然后将长度和数据块复制到新数组. 这个新数组被转换为 Base64 字符串。

在解压缩时,我们将 Base64 字符串转换为字节数组。现在我们可以使用 BitConverter 类提取实际压缩数据的长度,该类将从前 4 个字节中提取 Int32。然后,我们分配一个字节数组,其长度是我们从前 4 个字节中获得的长度,并让 Stream 将解压缩的字节写入字节数组。

我无法想象这样的事情实际上有什么好处。它增加了代码的复杂性,需要执行更多的操作。可读性也降低了。单独的 BlockCopy 操作应该消耗如此多的资源,这根本没有好处,对吧?

压缩示例代码:

byte[] buffer = new byte[0xffff] // Some large binary serialized object
// Compress in-memory.
using (var mem = new MemoryStream())
{
    // The actual compression takes place here.
    using (var zipStream = new GZipStream(mem, CompressionMode.Compress, true)) {
        zipStream.Write(buffer, 0, buffer.Length);
    }

    // Store compressed byte data here.
    var compressedData = new byte[mem.Length];
    mem.Position = 0;                
    mem.Read(compressedData, 0, compressedData.Length);

    /* Increase the size by 4 to accommadate for an Int32 that
    ** will store the total length of the compressed data. */
    var zipBuffer = new byte[compressedData.Length + 4];
    // Store length of compressedData array in the first 4 bytes.
    Buffer.BlockCopy(compressedData, 0, zipBuffer, 4, compressedData.Length);
    // Store the compressedData array after the first 4 bytes which store the length.
    Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, zipBuffer, 0, 4);
    return Convert.ToBase64String(zipBuffer);
} 

解压示例代码:

byte[] zipBuffer = Convert.FromBase64String("some base64 string");
using (var inStream = new MemoryStream())
{
    // The length of the array that was stored in the first 4 bytes.
    int dataLength = BitConverter.ToInt32(zipBuffer, 0);
    // Allocate array with specific size.
    byte[] buffer = new byte[dataLength];

    // Writer data to buffer array.
    inStream.Write(zipBuffer, 4, zipBuffer.Length - 4);                
    inStream.Position = 0;

    // Decompress data.
    using (var zipStream = new GZipStream(inStream, CompressionMode.Decompress)) {
        zipStream.Read(buffer, 0, buffer.Length);
    }

    ... code
    ... code 
    ... code
}

标签: c#arraysperformancecompressionlarge-data

解决方案


您将问题标记为 C#,这意味着 .NET,因此问题无关紧要:

框架已经用数组存储了长度。这就是数组类对索引器进行完整性检查的方式。它如何防止托管代码中的溢出攻击。仅此一项帮助就值得任何轻微的低效率(请注意,JiT 实际上能够修剪大多数检查。例如,对于循环,它只会在每个循环中查看一次运行变量)。

您必须一直深入到非托管代码并处理裸指针才能摆脱它。但你为什么要?差异如此之小,它属于速度咆哮。如果它很重要,您可能会得到一个实时编程案例。从 .NET 开始是个坏主意。


推荐阅读