Как хранить и сериализовать список, чтобы избежать длинных строк - PullRequest
4 голосов
/ 02 октября 2019

У меня проблемы с хранением информации. Проблема заключается в том, что при сохранении списков я получаю очень длинные строки, даже если информация выглядит короткой.

Допустим, у меня есть 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, но даже если в списке только один идентификатор и одно значение для людей, полученная в результате сериализованная строка содержит 4000-5000 символов.

Для хранения небольшого количестваданных я использую ту же систему, но только с одним списком:

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

Но таким образом, даже если есть 100 домов, строка короткая, но запутывает многие числа. И позже у меня могут возникнуть проблемы с сохранением / загрузкой, если я добавлю больше домов.

Можно ли как-то управлять этими данными и сохранять их в гораздо более короткой строке?

Спасибо.

Ответы [ 3 ]

3 голосов
/ 02 октября 2019

Вы можете даже просто сохранить его как список строк в каждой строке вида

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 часов с количеством людей > 9 и < 100)

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

≈ 588 characters | bytes
2 голосов
/ 02 октября 2019

BinaryFormatter не известен как эффективный сериализатор;на самом деле, вы действительно, действительно не должны его использовать;честно говоря никогдаЕсть много известных проблем с ним.

Если вам не хватает места, то, вероятно, 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;
    }
}
1 голос
/ 02 октября 2019

Вот моя попытка с 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}");
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...