C# 整数的变长编码
在C#中对无符号整数值进行变长编码的最佳方法是什么C# 整数的变长编码,c#,variables,uint,C#,Variables,Uint,在C#中对无符号整数值进行变长编码的最佳方法是什么 “实际目的是将可变长度编码整数(字节)附加到文件头。” 例如:“内容长度”-Http头 这可以通过以下逻辑中的一些更改来实现 我已经写了一些代码,可以做到这一点。如果小值比大值更常见,你可以使用。我使用的一种方法,使较小的值使用更少的字节,就是编码7位数据+1位开销字节 该编码仅适用于从零开始的正值,但也可以在必要时进行修改以处理负值 编码的工作方式如下所示: 获取值的最低7位并将其存储在一个字节中,这就是您要输出的内容 将值向右移动7位
“实际目的是将可变长度编码整数(字节)附加到文件头。” 例如:“内容长度”-Http头 这可以通过以下逻辑中的一些更改来实现
我已经写了一些代码,可以做到这一点。如果小值比大值更常见,你可以使用。我使用的一种方法,使较小的值使用更少的字节,就是编码7位数据+1位开销字节 该编码仅适用于从零开始的正值,但也可以在必要时进行修改以处理负值 编码的工作方式如下所示:
- 获取值的最低7位并将其存储在一个字节中,这就是您要输出的内容
- 将值向右移动7位,去掉刚才抓取的7位
- 如果该值为非零(即,从它移开7位后),则在输出前设置要输出的字节的高位
- 输出字节
- 如果该值为非零(即导致设置高位的相同检查),则返回并从头开始重复步骤
- 从位0开始
- 从文件中读取一个字节
- 存储高位是否已设置,并将其屏蔽
- 或者在字节的其余部分中输入最终值,即您所在的位位置
- 如果设置了高位,则将位位置增加7,然后重复步骤,跳过第一步(不要重置位位置)
void Main()
{
using (FileStream stream = new FileStream(@"c:\temp\test.dat", FileMode.Create))
using (BinaryWriter writer = new BinaryWriter(stream))
writer.EncodeInt32(123456789);
using (FileStream stream = new FileStream(@"c:\temp\test.dat", FileMode.Open))
using (BinaryReader reader = new BinaryReader(stream))
reader.DecodeInt32().Dump();
}
// Define other methods and classes here
public static class Extensions
{
/// <summary>
/// Encodes the specified <see cref="Int32"/> value with a variable number of
/// bytes, and writes the encoded bytes to the specified writer.
/// </summary>
/// <param name="writer">
/// The <see cref="BinaryWriter"/> to write the encoded value to.
/// </param>
/// <param name="value">
/// The <see cref="Int32"/> value to encode and write to the <paramref name="writer"/>.
/// </param>
/// <exception cref="ArgumentNullException">
/// <para><paramref name="writer"/> is <c>null</c>.</para>
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <para><paramref name="value"/> is less than 0.</para>
/// </exception>
/// <remarks>
/// See <see cref="DecodeInt32"/> for how to decode the value back from
/// a <see cref="BinaryReader"/>.
/// </remarks>
public static void EncodeInt32(this BinaryWriter writer, int value)
{
if (writer == null)
throw new ArgumentNullException("writer");
if (value < 0)
throw new ArgumentOutOfRangeException("value", value, "value must be 0 or greater");
do
{
byte lower7bits = (byte)(value & 0x7f);
value >>= 7;
if (value > 0)
lower7bits |= 128;
writer.Write(lower7bits);
} while (value > 0);
}
/// <summary>
/// Decodes a <see cref="Int32"/> value from a variable number of
/// bytes, originally encoded with <see cref="EncodeInt32"/> from the specified reader.
/// </summary>
/// <param name="reader">
/// The <see cref="BinaryReader"/> to read the encoded value from.
/// </param>
/// <returns>
/// The decoded <see cref="Int32"/> value.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <para><paramref name="reader"/> is <c>null</c>.</para>
/// </exception>
public static int DecodeInt32(this BinaryReader reader)
{
if (reader == null)
throw new ArgumentNullException("reader");
bool more = true;
int value = 0;
int shift = 0;
while (more)
{
byte lower7bits = reader.ReadByte();
more = (lower7bits & 128) != 0;
value |= (lower7bits & 0x7f) << shift;
shift += 7;
}
return value;
}
}
void Main()
{
使用(FileStream stream=newfilestream(@“c:\temp\test.dat”,FileMode.Create))
使用(BinaryWriter=新的BinaryWriter(流))
writer.EncodeInt32(123456789);
使用(FileStream stream=newfilestream(@“c:\temp\test.dat”,FileMode.Open))
使用(BinaryReader=新的BinaryReader(流))
reader.DecodeInt32().Dump();
}
//在此处定义其他方法和类
公共静态类扩展
{
///
///使用可变数量的
///字节,并将编码的字节写入指定的写入器。
///
///
///要将编码值写入的。
///
///
///要编码和写入的值。
///
///
///是空的。
///
///
///小于0。
///
///
///有关如何从中解码回值的信息,请参见
///a。
///
公共静态void EncodeInt32(此二进制编写器,int值)
{
if(writer==null)
抛出新的异常(“编写器”);
如果(值<0)
抛出新ArgumentOutOfRangeException(“value”,value,“value必须为0或更大”);
做
{
字节低7位=(字节)(值&0x7f);
值>>=7;
如果(值>0)
低7位|=128;
writer.Write(低7位);
}而(值>0);
}
///
///从可变数量的
///字节,最初使用来自指定读取器的。
///
///
///要从中读取编码值的。
///
///
///解码后的值。
///
///
///是空的。
///
公共静态int DecodeInt32(此二进制读取器)
{
如果(读卡器==null)
抛出新的异常(“读取器”);
布尔莫尔=真;
int值=0;
int-shift=0;
而(更多)
{
byte lower7bits=reader.ReadByte();
更多=(低7位和128位)!=0;
值|=(低7位&0x7f)
?您应该首先为您的值制作一个直方图。如果分布是随机的(即,直方图中的每一个单元的计数都接近另一个),那么您将无法对该数字进行比二进制表示更有效的编码
如果您的直方图不平衡(即,如果某些值比其他值更多),那么选择对这些值使用较少位的编码可能有意义,而对其他不太可能的值使用更多位
例如,如果需要编码的数字小于15位的可能性是大于15位的2倍,则可以使用第16位来说明这一点,并且只存储/发送16位(如果为零,则下一个字节将形成一个16位数字,可以容纳在32位数字中)。
如果是1,那么接下来的25位将形成一个32位数字。
你在这里失去了一点,但因为它不太可能,最终,对于很多数字,你赢得了更多的位
显然,这是一个微不足道的例子,而将其扩展到两个以上的例子是哈夫曼算法,该算法根据数字出现的概率影响一个接近最优的“码字”
还有一种算术编码算法也能做到这一点(p
void Main()
{
using (FileStream stream = new FileStream(@"c:\temp\test.dat", FileMode.Create))
using (BinaryWriter writer = new BinaryWriter(stream))
writer.EncodeInt32(123456789);
using (FileStream stream = new FileStream(@"c:\temp\test.dat", FileMode.Open))
using (BinaryReader reader = new BinaryReader(stream))
reader.DecodeInt32().Dump();
}
// Define other methods and classes here
public static class Extensions
{
/// <summary>
/// Encodes the specified <see cref="Int32"/> value with a variable number of
/// bytes, and writes the encoded bytes to the specified writer.
/// </summary>
/// <param name="writer">
/// The <see cref="BinaryWriter"/> to write the encoded value to.
/// </param>
/// <param name="value">
/// The <see cref="Int32"/> value to encode and write to the <paramref name="writer"/>.
/// </param>
/// <exception cref="ArgumentNullException">
/// <para><paramref name="writer"/> is <c>null</c>.</para>
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <para><paramref name="value"/> is less than 0.</para>
/// </exception>
/// <remarks>
/// See <see cref="DecodeInt32"/> for how to decode the value back from
/// a <see cref="BinaryReader"/>.
/// </remarks>
public static void EncodeInt32(this BinaryWriter writer, int value)
{
if (writer == null)
throw new ArgumentNullException("writer");
if (value < 0)
throw new ArgumentOutOfRangeException("value", value, "value must be 0 or greater");
do
{
byte lower7bits = (byte)(value & 0x7f);
value >>= 7;
if (value > 0)
lower7bits |= 128;
writer.Write(lower7bits);
} while (value > 0);
}
/// <summary>
/// Decodes a <see cref="Int32"/> value from a variable number of
/// bytes, originally encoded with <see cref="EncodeInt32"/> from the specified reader.
/// </summary>
/// <param name="reader">
/// The <see cref="BinaryReader"/> to read the encoded value from.
/// </param>
/// <returns>
/// The decoded <see cref="Int32"/> value.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <para><paramref name="reader"/> is <c>null</c>.</para>
/// </exception>
public static int DecodeInt32(this BinaryReader reader)
{
if (reader == null)
throw new ArgumentNullException("reader");
bool more = true;
int value = 0;
int shift = 0;
while (more)
{
byte lower7bits = reader.ReadByte();
more = (lower7bits & 128) != 0;
value |= (lower7bits & 0x7f) << shift;
shift += 7;
}
return value;
}
}
public struct VariableLength
{
// Variable Length byte array to int
public VariableLength(byte[] bytes)
{
int index = 0;
int value = 0;
byte b;
do
{
value = (value << 7) | ((b = bytes[index]) & 0x7F);
index++;
} while ((b & 0x80) != 0);
Length = index;
Value = value;
Bytes = new byte[Length];
Array.Copy(bytes, 0, Bytes, 0, Length);
}
// Variable Length int to byte array
public VariableLength(int value)
{
Value = value;
byte[] bytes = new byte[4];
int index = 0;
int buffer = value & 0x7F;
while ((value >>= 7) > 0)
{
buffer <<= 8;
buffer |= 0x80;
buffer += (value & 0x7F);
}
while (true)
{
bytes[index] = (byte)buffer;
index++;
if ((buffer & 0x80) > 0)
buffer >>= 8;
else
break;
}
Length = index;
Bytes = new byte[index];
Array.Copy(bytes, 0, Bytes, 0, Length);
}
// Number of bytes used to store the variable length value
public int Length { get; private set; }
// Variable Length Value
public int Value { get; private set; }
// Bytes representing the integer value
public byte[] Bytes { get; private set; }
}
public void Example()
{
//Convert an integer into a variable length byte
int varLenVal = 480;
VariableLength v = new VariableLength(varLenVal);
byte[] bytes = v.Bytes;
//Convert a variable length byte array into an integer
byte[] varLenByte = new byte[2]{131, 96};
VariableLength v = new VariableLength(varLenByte);
int result = v.Length;
}
public static int Read7BitEncodedInt(this BinaryReader br) {
// Read out an Int32 7 bits at a time. The high bit
// of the byte when on means to continue reading more bytes.
int count = 0;
int shift = 0;
byte b;
do {
// Check for a corrupted stream. Read a max of 5 bytes.
// In a future version, add a DataFormatException.
if (shift == 5 * 7) // 5 bytes max per Int32, shift += 7
throw new FormatException("Format_Bad7BitInt32");
// ReadByte handles end of stream cases for us.
b = br.ReadByte();
count |= (b & 0x7F) << shift;
shift += 7;
} while ((b & 0x80) != 0);
return count;
}
public static void Write7BitEncodedInt(this BinaryWriter br, int value) {
// Write out an int 7 bits at a time. The high bit of the byte,
// when on, tells reader to continue reading more bytes.
uint v = (uint)value; // support negative numbers
while (v >= 0x80) {
br.Write((byte)(v | 0x80));
v >>= 7;
}
br.Write((byte)v);
}