如何存储和序列化列表以避免长字符串

时间:2019-10-01 22:30:03

标签: c# unity3d

我在存储信息时遇到一些问题。问题来了,因为在保存列表时,即使信息看起来很短,我也会得到很长的字符串。

让我们说我有100所房屋,我想节省每所房屋中有多少人。我用这个:

Houses.cs

[System.Serializable]
public class Houses
{
    public int ID { get; set; }    
    public int PEOPLE { get; set; }

    public Houses(int _ID, int _PEOPLE)
    {
        ID = _ID;
        PEOPLE = _PEOPLE ;   
    }
}

然后在另一个脚本中我拥有

public List<Houses> HousesList = new List<Houses>();
void Awake()
{
    HousesList.Add(new Houses(0,0));
    //repeat until 100 (or more) I use a loop to initialize it
}

然后添加我说的人:

HousesList[3].PEOPLE+=5;

然后保存,我使用BinaryFormatter / MemoryStream的方式,但是即使列表中只有一个ID和一个人的值,结果序列化的字符串也包含4,000-5,000个字符。

要存储少量数据,我使用同一系统,但仅使用一个列表:

Houses.Add(new Houses(0,2,0,0,1)); // house 1, house 2... house 5

但是这样,即使有100个房屋,字符串也很短,但是却与这么多数字混淆。之后,如果我添加更多房屋,我可能会在保存/加载方面遇到问题。

有什么方法可以管理此类数据并将其保存在更短的字符串中?

谢谢。

3 个答案:

答案 0 :(得分:3)

您甚至可以简单地将其保存为表格的每一行的行列表

id people

所以您有一个文件,例如

0 3
1 4
2 5
...

,稍后您可以通过

进行解析
var lines = fileContent.Split('/n');

然后在每一行

var parts = line.Split(' ');
int id = int.TryParse(parts[0]) ? id : -1;
int people = int.TryParse(parts[1]) ? people : -1;

例如,在代码中

[Serializable]
public class House
{
    public int Id;
    public int People;

    public House(int id, int people)
    {
        Id = id;
        People = people;   
    }
}

List<House> Houses = new List<House>();

public void Save()
{
    var stringBuilder = new StringBuilder();

    foreach(var house in Houses)
    {
        stringBuilder.Append(house.Id).Append(' ').Append(house.People).Append('/n');
    }

    // Now use the file IO method of your choice e.g.
    File.WriteAllText(filePath, stringBuilder.ToString(), Encoding.UTF8);   
}

public void Load()
{
    // clear current list
    Houses.Clear();

    // Use the file IO of choice e.g.
    string readText = File.ReadAllText(path);

    var lines = readText.Split('/n', StringSplitOptions.RemoveEmptyEntries);

    foreach (var line in lines)
    {
        var parts = line.Split(' ');

        // skip wrong formatted line
        if(parts.Length != 2) continue;

        int id = int.TryParse(parts[0]) ? id : -1;
        int people = int.TryParse(parts[1]) ? people : -1;

        if(id < 0 || people < 0) continue;    

        Houses.Add(new House(id, people));
    }
}

现在您的房屋编号和人数都在这里。

字符串的长度取决于您的课程价值,但是会是类似的(对于100的huese,人数为> 9< 100

house IDs + seperator + people  + /n
10+89*2   + 100       + 100 * 2 + 100

≈ 588 characters | bytes

答案 1 :(得分:2)

BinaryFormatter因其高效的串行器而闻名。实际上,您真的真的不应该使用它;坦率地说。有很多已知的问题。

如果您很想念太空,protobuf可能是一个不错的选择;为此,protobuf约为596字节;在这种情况下,我使用的是protobuf-net:

596 bytes
100 items
95, 95
96, 96
97, 97
98, 98
99, 99

包含代码:

using ProtoBuf;
using System.Collections.Generic;
using System.IO;
using System.Linq;

static class P
{
    static void Main()
    {
        var houses = new List<Houses>();
        for (int i = 0; i < 100; i++)
            houses.Add(new Houses(i, i));
        using(var ms = new MemoryStream())
        {
            Serializer.Serialize(ms, houses);
            System.Console.WriteLine($"{ms.Length} bytes");
            ms.Position = 0;
            var clone = Serializer.Deserialize<List<Houses>>(ms);
            System.Console.WriteLine($"{clone.Count} items");
            foreach(var item in clone.Skip(95))
            {
                System.Console.WriteLine($"{item.Id}, {item.People}");
            }
        }
    }
}
[ProtoContract(SkipConstructor = true)]
public class Houses
{
    [ProtoMember(1)]
    public int Id { get; set; }
    [ProtoMember(2)]
    public int People { get; set; }
    public Houses(int id, int people)
    {
        Id = id;
        People = people;
    }
}

答案 2 :(得分:1)

这是我尝试使用Json.Net + GZipStream

Json length: characters=2181, bytes=2181
gzipped.Length=437
class Program
{
  public class Houses
  {
    public int Id { get; } // Btw. No need for setters
    public int People { get; } 

    public Houses(int id, int people)
    {
      Id = id;
      People = people;
    }
  }

  static void Main(string[] args)
  {
    var houses = new List<Houses>();
    for (int i = 0; i < 100; i++)
      houses.Add(new Houses(i, i));

    var json = Newtonsoft.Json.JsonConvert.SerializeObject(houses);
    byte[] inputBytes = Encoding.UTF8.GetBytes(json);

    Console.WriteLine($"Json length: characters={json.Length}, bytes={inputBytes.Length}");

    byte[] gzipped;
    using (var outputStream = new MemoryStream())
    {
      using (var gZipStream = new GZipStream(outputStream, CompressionMode.Compress))
      {
        gZipStream.Write(inputBytes, 0, inputBytes.Length);
      }
      gzipped = outputStream.ToArray();

    }
    Console.WriteLine($"gzipped.Length={gzipped.Length}");
  }
}