代码之家  ›  专栏  ›  技术社区  ›  Valentin V

不使用序列化将字符串数组持久化到流的可能方法?

  •  3
  • Valentin V  · 技术社区  · 16 年前

    在不使用序列化的情况下,将字符串数组保存到流中有哪些可能的方法?

    我对弦特别感兴趣,因为它们的长度可能会有所不同。我还应该能够从流中恢复数组。 而且,更重要的是,我希望能够在不向内存中读取整个数组的情况下只读取数组的切片,因为我的数组可能很大。

    另外,我知道有数据库存在,我不应该重新发明轮子等等,但我有理由选择手工解决方案。

    谢谢您。

    1 回复  |  直到 16 年前
        1
  •  3
  •   Marc Gravell    16 年前

    嗯,将数据保存到流中 序列化;真正的诀窍是:什么类型。例如,我假设你说的是 XmlSerializer BinaryFormatter 这要求您对整个事物进行反序列化,但这并不总是必要的。

    通过使用长度前缀编写每个字符串,您应该能够很容易地查找过去不需要的项目。另一种选择是(单独)写一个偏移索引,但这有时是多余的。

    作为一个 基本的 例子, s 这是 "jkl" , 没有 它读取整个流或反序列化不需要的字符串;注意,它可以通过(例如)使用可变长度编码来优化 int (长度),这也将修正当前的假设,即读写器之间的结尾是相同的:

    static void Main()
    {
        byte[] raw;
        using (MemoryStream ms = new MemoryStream())
        {
            // serialize all
            List<string> data = new List<string> {
               "abc", "def", "ghi", "jkl", "mno", "pqr" };
            foreach (string s in data)
            {
                byte[] buffer = Encoding.UTF8.GetBytes(s);
                byte[] lenBuffer = BitConverter.GetBytes(buffer.Length);
                ms.Write(lenBuffer, 0, lenBuffer.Length);
                ms.Write(buffer, 0, buffer.Length);
            }
            raw = ms.ToArray();
        }
        using (MemoryStream ms = new MemoryStream(raw))
        {
            int offset = 3, len;
            byte[] buffer = new byte[128];
            while (offset-- > 0)
            {
                Read(ms, ref buffer, 4);
                len = BitConverter.ToInt32(buffer, 0);
                ms.Seek(len, SeekOrigin.Current); // assume seekable, but
                                                  // easy to read past if not
            }
            Read(ms, ref buffer, 4);
            len = BitConverter.ToInt32(buffer, 0);
            Read(ms, ref buffer, len);
            string s = Encoding.UTF8.GetString(buffer, 0, len);
        }
    }
    static void Read(Stream stream, ref byte[] buffer, int count)
    {
        if (buffer.Length < count) buffer = new byte[count];
        int offset = 0;
        while (count > 0)
        {
            int bytes = stream.Read(buffer, offset, count);
            if (bytes <= 0) throw new EndOfStreamException();
            offset += bytes;
            count -= bytes;
        }
    }