c# - 将 ReadOnlyCollection<byte> 写入流

标签 c# filestream immutability binaryfiles readonly-collection

我使用包含多个魔术字节序列的二进制格式。我想将它们作为不可变的静态成员保存在静态类中。

public static class HuffmanConsts
{
    // output format: Header, serialized tree (prefix), DataDelimiter, coded data (logical blocks are 8 byte large, Little Endian)
    public const string Extension = ".huff";
    public static readonly IReadOnlyList<byte> Header = Array.AsReadOnly(new byte[] {0x7B, 0x68, 0x75, 0x7C, 0x6D, 0x7D, 0x66, 0x66}); // string {hu|m}ff
    public static readonly IReadOnlyList<byte> DataDelimiter = Array.AsReadOnly(BitConverter.GetBytes(0L)); // eight binary zeroes, regardless of endianness
}

ReadOnlyCollection<byte> (从 Array.AsReadOnly() 返回)防止外部代码更改值,不像 byte[] .

但是现在,我无法输出Header通过stream.Write() ,因为它需要 byte[] :

stream.Write(HuffmanConsts.Header, 0, HuffmanConsts.Header.Count)

有没有一种优雅的方式来写Header ?或者我是否必须编写一个循环并将字节一个一个地馈送到流中?

最佳答案

只是让输出数组不可变

你可以考虑这样的事情:

public static class HuffmanConsts {
   // output format: Header, serialized tree (prefix), DataDelimiter,
   // coded data (logical blocks are 8 byte large, Little Endian)
   public const string Extension = ".huff";

   private static readonly IReadOnlyList<byte> _header =
      // string {hu|m}ff
      Array.AsReadOnly(new byte[] {0x7B, 0x68, 0x75, 0x7C, 0x6D, 0x7D, 0x66, 0x66});
   private static readonly IReadOnlyList<byte> _dataDelimiter =
      // eight binary zeroes, regardless of endianness
      Array.AsReadOnly(BitConverter.GetBytes(0L)); 

   public static byte[] Header { get { return _header.ToArray(); } }
   public static byte[] DataDelimiter { get { return _dataDelimiter.ToArray(); } }
}

处理 ToArray 的任何性能影响

但是,每次访问这些属性时都会产生 ToArray() 的开销。为了减轻潜在的性能损失(注意:测试是为了查看是否真的存在!),您可以使用 System.Buffer.BlockCopy :

private static readonly byte[] _header =
   // string {hu|m}ff
   new byte[] {0x7B, 0x68, 0x75, 0x7C, 0x6D, 0x7D, 0x66, 0x66};
private static int BYTE_SIZE = 1;
private static byte[] GetHeaderClone() {
   byte[] clone = new byte[_header.Length];
   Buffer.BlockCopy(_header, 0, clone, 0, _header.Length * BYTE_SIZE);
   return clone;
}

更好的解决方案:封装写入流

您还可以创建扩展方法,让您的消费者不再纠结于自己编写这些流组件的细节,例如,WriteHeader 方法可能如下所示:

public static class StreamExtensions {
   // include BlockCopy code from above
   public static void WriteHuffmanHeader(this Stream stream) {
      var header = GetHeaderClone();
      stream.Write(header, 0, header.Length);
   }
}

这不会使数组不可变,但私有(private)化不是问题。

一个可能更好的解决方案:封装一个霍夫曼流对象

您还可以选择实现自己的 HuffmanStream,它会为您处理 header 和其他方面的细节!我实际上认为这是理想的,因为它将 Huffman 流的所有关注点封装到一段可测试的代码中,不会在您需要使用的每个地方都重复。

public class HuffmanStream : Stream {
   private Stream _stream = new MemoryStream();
   private static byte[] _header = ... ;
   public HuffmanStream( ... ) {
      ...
      _stream.Write(_header, 0, _header.Length)
      // the stream already has the header written at instantiation time
   }
}

注意:将 byte[] 实例传递给 Stream.Write() 时,它可能会在方法返回后被修改,因为方法可以直接访问数组.行为良好的 Stream 实现不会那样做,但为了防止自定义流的安全,您必须Stream 实例视为敌对的,因此永远不要向他们传递对不应更改的数组的引用。例如,任何时候你想将你的 _header 字节数组传递给 possiblyHostileStream.Write(),你需要传递 _header.Clone()反而。我的 HuffmanStream 不需要这个,因为它使用了可以信任的 MemoryStream

关于c# - 将 ReadOnlyCollection<byte> 写入流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34727828/

相关文章:

c# - 在 Linux 下是否有一种简单的方法来实现类似于 C++ 中的 GC.GetTotalMemory 的函数?

C#6 重载决议 Func<T1> & Func<T2>

c# - 流阅读器无法将文本从文件文本获取到文本框

c++ - 从文件中删除字符

具有可变列表的 Julia 不可变结构

c# - 防止直接实例化的工厂类

c# - DBMetal 为 sqlite_sequence 生成无效类

c# - 重复/同时读取/写入文本文件

algorithm - Clojure 中的不可变队列

java - 如何使 2D ArrayList 不可变?