Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/258.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#-如何以尽可能小的大小将字节值保存到文件中?_C#_Arrays_Serialization - Fatal编程技术网

C#-如何以尽可能小的大小将字节值保存到文件中?

C#-如何以尽可能小的大小将字节值保存到文件中?,c#,arrays,serialization,C#,Arrays,Serialization,我需要以尽可能小的文件大小序列化以下数据 我有一组模式,每个模式都是一个固定长度的字节数组(byte[]) 在本例中,让我们使用5的模式长度,因此字节数组将为: var pattern = new byte[] {1, 2, 3, 4, 5}; 假设我们在一个集合中有3个相同的模式: var collection = new byte[][] { pattern, pattern, pattern }; 目前,我正在将集合保存在ASCII编码的文件中。使用上述集合,保存的文件如下所示: 01

我需要以尽可能小的文件大小序列化以下数据

我有一组模式,每个模式都是一个固定长度的字节数组(
byte[]

在本例中,让我们使用5的模式长度,因此字节数组将为:

var pattern = new byte[] {1, 2, 3, 4, 5};
假设我们在一个集合中有3个相同的模式:

var collection = new byte[][] { pattern, pattern, pattern };
目前,我正在将集合保存在ASCII编码的文件中。使用上述集合,保存的文件如下所示:

010203040501020304050102030405
数组中的每个字节由2位数字(00)表示,因此我可以处理从0到25的字节值,它可以如下所示:

010203040501020304050102030405
[01 | 02 | 03 | 04 | 05][01 | 02 | 03 | 04 | 05][01 | 02 | 03 | 04 | 05]

当我反序列化文件时,我将每个2个字符的块解析为一个字节,并将每5个字节放入一个字节数组

据我所知,ASCII编码文件中的每个字符都是一个字节——可能提供256个不同的值,但我所需要的是,每个2个字符的块都可能是0到25之间的十进制值

当我保存一个有50000个模式的文件时,每个模式的长度为12,我最终得到一个1.7MB的文件,这个文件太大了

我可以在C#中使用什么编码使文件大小更小


请提供如何在文件中写入和读取此数据的示例代码。

我在将二进制数据编码为条形码时做了类似的操作(请参阅)。考虑下面的代码,这些代码会将样本序列化到文件中并立即反序列化:

static void Main(string[] args)
{
    var data = new List<byte[]>() {
        new byte[] { 01, 05, 15, 04, 11, 00, 01, 01, 05, 15, 04, 11, 00, 01 },
        new byte[] { 09, 04, 02, 00, 08, 12, 01, 07, 04, 02, 00, 08, 12, 01 },
        new byte[] { 01, 05, 06, 04, 02, 00, 01, 01, 05, 06, 04, 02, 00, 01 }
    };

    // has to be known when loading the file
    var reasonableBase = data.SelectMany(i => i).Max() + 1;

    using (var target = File.OpenWrite("data.bin"))
    {
        using (var writer = new BinaryWriter(target))
        {
            // write the number of lines (16 bit, lines limited to 65536)
            writer.Write((ushort)data.Count);

            // write the base (8 bit, base limited to 255)
            writer.Write((byte)reasonableBase);

            foreach (var sample in data)
            {
                // converts the byte array into a large number of the known base (bypasses all the bit-mess)
                var serializedData = ByteArrayToNumberBased(sample, reasonableBase).ToByteArray();

                // write the length of the sample (8 bit, limited to 255)
                writer.Write((byte)serializedData.Length);
                writer.Write(serializedData);
            }
        }
    }

    var deserializedData = new List<byte[]>();

    using (var source = File.OpenRead("data.bin"))
    {
        using (var reader = new BinaryReader(source))
        {
            var lines = reader.ReadUInt16();
            var sourceBase = reader.ReadByte();

            for (int i = 0; i < lines; i++)
            {
                var length = reader.ReadByte();
                var value = new BigInteger(reader.ReadBytes(length));

                // chunk the bytes back of the big number we loaded
                // works because we know the base
                deserializedData.Add(NumberToByteArrayBased(value, sourceBase));
            }
        }
    }
}

private static BigInteger ByteArrayToNumberBased(byte[] data, int numBase)
{
    var result = BigInteger.Zero;

    for (int i = 0; i < data.Length; i++)
    {
        result += data[i] * BigInteger.Pow(numBase, i);
    }

    return result;
}

private static byte[] NumberToByteArrayBased(BigInteger data, int numBase)
{
    var list = new List<Byte>();

    do
    {
        list.Add((byte)(data % numBase));
    }
    while ((data = (data / numBase)) > 0);

    return list.ToArray();
}
static void Main(字符串[]args)
{
变量数据=新列表(){
新字节[]{01,05,15,04,11,00,01,01,05,15,04,11,00,01},
新字节[]{09,04,02,00,08,12,01,07,04,02,00,08,12,01},
新字节[]{01,05,06,04,02,00,01,01,05,06,04,02,00,01}
};
//加载文件时必须知道
var reasonalbase=data.SelectMany(i=>i).Max()+1;
使用(var target=File.OpenWrite(“data.bin”))
{
使用(var writer=newbinarywriter(目标))
{
//写入行数(16位,行数限制为65536)
writer.Write((ushort)data.Count);
//写入基数(8位,基数限制为255)
writer.Write((字节)合理基数);
foreach(数据中的var样本)
{
//将字节数组转换为大量已知基(绕过所有位混乱)
var serializedData=ByteArrayToNumberBased(示例,ReasonicalBase).ToByteArray();
//写入样本的长度(8位,限制为255)
writer.Write((字节)serializedData.Length);
writer.Write(序列化数据);
}
}
}
var deserializedData=新列表();
使用(var source=File.OpenRead(“data.bin”))
{
使用(变量读取器=新二进制读取器(源))
{
var lines=reader.ReadUInt16();
var sourceBase=reader.ReadByte();
对于(int i=0;i0);
return list.ToArray();
}

与您的格式相比,示例数据将序列化为27字节,而不是90字节。使用@xanatos的每个符号4.7位,完美的结果将是
14*3*4.7/8=24675字节
,所以这并不坏(公平地说:示例序列化为30字节,基数设置为26).

下面是一个示例,说明如何使用
GZipStream
BinaryFormatter
从压缩文件中读取和写入数据

它对于小型阵列不是非常有效,但对于大型阵列则更加有效。但是,请注意,这依赖于数据是可压缩的-如果不是,那么这将没有任何用处

using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;

namespace Demo
{
    static class Program
    {
        static void Main()
        {
            var pattern    = new byte[] { 1, 2, 3, 4, 5 };
            var collection = new [] { pattern, pattern, pattern };

            string filename = @"e:\tmp\test.bin";
            zipToFile(filename, collection);

            var deserialised = unzipFromFile(filename);

            Console.WriteLine(string.Join("\n", deserialised.Select(row => string.Join(", ", row))));
        }

        static void zipToFile(string file, byte[][] data)
        {
            using (var output = new FileStream(file, FileMode.Create))
            using (var gzip   = new GZipStream(output, CompressionLevel.Optimal))
            {
                new BinaryFormatter().Serialize(gzip, data);
            }
        }

        static byte[][] unzipFromFile(string file)
        {
            using (var input = new FileStream(file, FileMode.Open))
            using (var gzip  = new GZipStream(input, CompressionMode.Decompress))
            {
                return (byte[][]) new BinaryFormatter().Deserialize(gzip);
            }
        }
    }
}

有时简单是最好的折衷办法

矩形阵列可以看作是一系列线性阵列

字节文件是字节的线性数组

下面是一段非常简单的代码,用于转换字节的矩形数组并将字节写入文件:

// All patterns must be the same length so they can be split when reading
File.WriteAllBytes(Path.GetTempFileName(), collection.SelectMany(p => p).ToArray()); 
System.Linq.Enumerable.SelectMany(pattern=>pattern)
获取序列并将其展平为序列。(它和ToArray()并不是最有效的,但对于50000*4个元素,它可能很好。)


考虑到这一点,如果需要压缩,Zip将是一种可行的方法

如果您的文件不必是ASCII,您可以使用和来压缩数据。文件必须是文本编辑器可读的吗?只需保存字节而不是数字,就可以保存一半的数据?我也无意冒犯,但这听起来很像家庭作业。0-25->A。。Z.或使用每5位表示一个值的位流。使用进行压缩/解压缩的流可能更容易。通过二进制写入,最多可以压缩5位/数字(log2(26)=4.7)。。。但是写基于位的信息很痛苦谢谢你的回复,我得花点时间看一下。谢谢,我会试试看的