无法压缩的数据序列

6
我希望通过一个算法生成X MB的“不可压缩”数据序列。我希望这样做是为了创建一个通过VPN连接测量网络速度的程序(避免VPN内置压缩)。
有人可以帮我吗?谢谢!
附:我需要一个算法,我已经使用了一个被压缩到无法再压缩的文件,但现在我需要从头开始编程生成数据序列。

2
一个随机的字节序列是不可压缩的。因此,获取一个好的随机源并提取所需的数据大小。 - Eugen Rieck
1
您正在针对特定的压缩算法进行开发吗?压缩算法通常有一个有限的帧大小,用于压缩数据。例如,参考gzip实现的最大帧大小为32KB,因此您可以重复相同的32KB随机数据来生成任意大的不可压缩流。 - broofa
8个回答

8

白噪声数据是真正的随机数据,因此不可压缩。

因此,您应该找到一个生成它(或近似值)的算法。

在Linux中尝试以下方法:

# dd if=/dev/urandom bs=1024 count=10000 2>/dev/null | bzip2 -9 -c -v > /dev/null
(stdin): 0.996:1, 8.035 bits/byte, -0.44% saved, 10240000 in, 10285383 out.

虽然您可以尝试任何类型的随机数生成...


2
仅供澄清。上述内容表明,您可以生成一块不可压缩的数据;压缩它实际上会使其变得更大,这已经在输入和输出中得到证明... - Kris

7
使用随机数生成器创建统计上难以压缩的数据是一种简单的方法。如果需要重复使用,请固定种子。任何一个合理好用的随机数生成器都可以。具有讽刺意味的是,如果您知道随机数生成器,结果是非常可压缩的:它只包含种子信息。然而,它将击败任何真正的压缩方法。

4
其他答案已经指出,随机噪声是不可压缩的,并且好的加密函数的输出尽可能接近随机噪声(除非您知道解密密钥)。因此,一个好的方法可能是只使用随机数生成器或加密算法来生成您的不可压缩数据。
真正不可压缩(按“不可压缩”的某些形式定义)的比特串存在,但即使识别它们也是计算上不可判定的,更不用说生成它们了。
值得指出的是,“随机数据”仅在平均情况下没有任何压缩算法能够实现优于1:1的压缩比率。然而,对于任何特定的随机生成字符串,可能存在一种特定的压缩算法可以实现良好的压缩比率。毕竟,任何可压缩的字符串都应该是随机生成器的可能输出,包括所有零等愚蠢的东西,尽管可能性很小。
因此,虽然从随机数生成器或加密算法中获取“可压缩”数据的可能性可能非常小,但在使用数据之前我希望进行实际测试。如果您可以访问VPN连接中使用的压缩算法,则最好只需随机生成数据直到获得无法压缩的内容。否则,只需通过几个常见的压缩工具运行它并检查大小是否不会减小即可足够。

3
你有几个选择: 1.使用一个好的伪随机数生成器 2.使用像AES这样的加密函数(实现可以在任何地方找到)
算法
1.想出你想要的任何密钥。全零也可以。 2.创建一个空块 3.使用密钥加密该块 4.输出该块 5.如果需要更多数据,请转到3
如果正确执行,生成的数据流将与随机噪声在数学上无法区分。

额外的想法:为了测试您选择的算法:
  • 让它运行并生成大约100MB左右。
  • 尝试压缩它zip,rar等...
- Jan Hertsens
这是我的答案的想法。硬件加速的AES(aes-ni)非常快,但如果目标只是不可压缩性,我们当然可以做得更好。 - u0b34a0f6ae

2
下面的程序(C/POSIX)可以快速生成不可压缩数据,速度应该在每秒数十亿字节的范围内。我相信可以使用这个基本思路来使它甚至更快(也许使用Djb的ChaCha核心和SIMD?)。
/* public domain, 2013 */

#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>

#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
static void salsa_scrambler(uint32_t out[16], uint32_t x[16])
{
    int i;
    /* This is a quickly mutilated Salsa20 of only 1 round */
    x[ 4] ^= R(x[ 0] + x[12],  7);
    x[ 8] ^= R(x[ 4] + x[ 0],  9);
    x[12] ^= R(x[ 8] + x[ 4], 13);
    x[ 0] ^= R(x[12] + x[ 8], 18);
    x[ 9] ^= R(x[ 5] + x[ 1],  7);
    x[13] ^= R(x[ 9] + x[ 5],  9);
    x[ 1] ^= R(x[13] + x[ 9], 13);
    x[ 5] ^= R(x[ 1] + x[13], 18);
    x[14] ^= R(x[10] + x[ 6],  7);
    x[ 2] ^= R(x[14] + x[10],  9);
    x[ 6] ^= R(x[ 2] + x[14], 13);
    x[10] ^= R(x[ 6] + x[ 2], 18);
    x[ 3] ^= R(x[15] + x[11],  7);
    x[ 7] ^= R(x[ 3] + x[15],  9);
    x[11] ^= R(x[ 7] + x[ 3], 13);
    x[15] ^= R(x[11] + x[ 7], 18);
    for (i = 0; i < 16; ++i)
        out[i] = x[i];
}

#define CHUNK 2048

int main(void)
{
    uint32_t bufA[CHUNK];
    uint32_t bufB[CHUNK];
    uint32_t *input = bufA, *output = bufB;
    int i;

    /* Initialize seed */
    srand(time(NULL));
    for (i = 0; i < CHUNK; i++)
        input[i] = rand();

    while (1) {
        for (i = 0; i < CHUNK/16; i++) {
            salsa_scrambler(output + 16*i, input + 16*i);
        }
        write(1, output, sizeof(bufA));

        {
            uint32_t *tmp = output;
            output = input;
            input = tmp;
        }
    }
    return 0;
}

0
一个非常简单的解决方案是生成一个随机字符串,然后压缩它。 已经压缩过的文件是不可压缩的。

踩票者:这种方法已经在一个项目中使用过了,有什么问题吗? - advncd
压缩一段字符串并不意味着它不能再被压缩。有些压缩方法会使用多个算法来相继进行压缩。 - Ykok

0

对于喜欢复制粘贴的人,这里有一些用C#代码生成(几乎)不可压缩内容文件的方法。代码的核心是MD5哈希算法,但任何具有密码学强度(最终结果具有良好的随机分布)的哈希算法都可以胜任(如SHA1、SHA256等)。

它只使用文件编号字节(32位小端有符号整数在我的机器上)作为哈希函数的初始输入,并重新哈希和连接输出,直到达到所需的文件大小。因此,文件内容是确定性的(相同的数字始终生成相同的输出),并且是随机分布的“垃圾”,用于测试压缩算法。

    using System;
    using System.IO;
    using System.Linq;
    using System.Security.Cryptography;

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

        GenerateUncompressableTestFiles(
            outputDirectory  : Path.GetFullPath( "." ),
            fileNameTemplate : "test-file-{0}.dat", 
            fileCount        : 10,
            fileSizeAsBytes  : 16 * 1024
        );

        byte[] bytes = GetIncompressibleBuffer( 16 * 1024 );

    }//Main

    static void GenerateUncompressableTestFiles( string outputDirectory, string  fileNameTemplate, int fileCount, int fileSizeAsBytes ) {

       using ( var md5 = MD5.Create() ) {

          for ( int number = 1; number <= fileCount; number++ ) {

              using ( var content = new MemoryStream() ) {

                    var inputBytes = BitConverter.GetBytes( number );

                    while ( content.Length <= fileSizeAsBytes ) {

                        var hashBytes = md5.ComputeHash( inputBytes );
                        content.Write( hashBytes );
                        inputBytes = hashBytes;

                        if ( content.Length >= fileSizeAsBytes ) {
                            var file = Path.Combine( outputDirectory, String.Format( fileNameTemplate, number ) );
                            File.WriteAllBytes( file, content.ToArray().Take( fileSizeAsBytes ).ToArray() );
                        }

                    }//while

               }//using

            }//for

       }//using

    }//GenerateUncompressableTestFiles

    public static byte[] GetIncompressibleBuffer( int size, int seed = 0 ) { 

       using ( var md5 = MD5.Create() ) {

            using ( var content = new MemoryStream() ) {

                var inputBytes = BitConverter.GetBytes( seed );

                while ( content.Length <= size ) {

                    var hashBytes = md5.ComputeHash( inputBytes );
                    content.Write( hashBytes );
                    inputBytes = hashBytes;

                    if ( content.Length >= size ) {
                        return content.ToArray().Take( size ).ToArray();
                    }

                }//while

            }//using

        }//using

        return Array.Empty<byte>();

    }//GetIncompressibleBuffer 


    }//class

-1

我刚刚创建了一个(非常简单且未经过优化的)C#控制台应用程序,可以创建不可压缩的文件。 它会扫描一个包含文本文件(扩展名为.txt)的文件夹,并为每个文本文件创建一个具有相同名称和大小的二进制文件(扩展名为.bin)。 希望这能对某些人有所帮助。 以下是C#代码:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var files = Directory.EnumerateFiles(@"d:\MyPath\To\TextFile\", "*.txt");
            var random = new Random();
            foreach (var fileName in files)
            {
                var fileInfo = new FileInfo(fileName);
                var newFileName = Path.GetDirectoryName(fileName) + @"\" + Path.GetFileNameWithoutExtension(fileName) + ".bin";
                using (var f = File.Create(newFileName))
                {
                    long bytesWritten = 0;
                    while (bytesWritten < fileInfo.Length)
                    {
                        f.WriteByte((byte)random.Next());
                        bytesWritten++;
                    }
                    f.Close();
                }
            }
        }
    }
}

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