Используйте Protobuf-net для потоковой передачи больших файлов данных как IEnumerable - PullRequest
7 голосов
/ 26 августа 2011

Я пытаюсь использовать Protobuf-net для сохранения и загрузки данных на диск, но застрял.

У меня есть портфель активов, которые мне нужно обработать, и я хочу быть в состоянии сделать это как можно быстрее. Я уже могу читать из CSV, но было бы быстрее использовать двоичный файл, поэтому я смотрю в Protobuf-Net.

Я не могу поместить все ресурсы в память, поэтому я хочу транслировать их, а не загружать их все в память.

Итак, мне нужно представить большой набор записей в виде IEnumerable. Это возможно с Protobuf-Net? Я попробовал пару вещей, но не смог запустить его.

Сериализация, кажется, работает, но я не смог прочитать их снова, я вернул 0 активов. Может ли кто-нибудь указать мне правильное направление, пожалуйста? Посмотрел методы в классе Serializer, но не смог найти ни одного, который бы охватывал этот случай. Этот вариант использования поддерживается Protobuf-net? Кстати, я пользуюсь V2.

Заранее спасибо,

Герт-Ян

Вот пример кода, который я пробовал:

public partial class MainWindow : Window {

    // Generate x Assets
    IEnumerable<Asset> GenerateAssets(int Count) {
        var rnd = new Random();
        for (int i = 1; i < Count; i++) {
            yield return new Asset {
                ID = i,
                EAD = i * 12345,
                LGD = (float)rnd.NextDouble(),
                PD = (float)rnd.NextDouble()
            };
        }
    }

    // write assets to file
    private void Write(string path, IEnumerable<Asset> assets){
        using (var file = File.Create(path)) {
            Serializer.Serialize<IEnumerable<Asset>>(file, assets);
        }
    }

    // read assets from file
    IEnumerable<Asset> Read(string path) {
        using (var file = File.OpenRead(path)) {
            return Serializer.DeserializeItems<Asset>(file, PrefixStyle.None, -1);
        }
    }

    // try it 
    private void Test() {
        Write("Data.bin", GenerateAssets(100)); // this creates a file with binary gibberish that I assume are the assets
        var x = Read("Data.bin");
        MessageBox.Show(x.Count().ToString()); // returns 0 instead of 100
    }

    public MainWindow() {
        InitializeComponent();
    }

    private void button2_Click(object sender, RoutedEventArgs e) {
        Test();
    }
}

[ProtoContract]
class Asset {

    [ProtoMember(1)]
    public int ID { get; set; }

    [ProtoMember(2)]
    public double EAD { get; set; }

    [ProtoMember(3)]
    public float LGD { get; set; }

    [ProtoMember(4)]
    public float PD { get; set; }
}

1 Ответ

7 голосов
/ 27 августа 2011

разобрался.Для десериализации используйте PrefixBase.Base128, который по умолчанию является значением по умолчанию .

Теперь это работает как шарм!

ГДж

        using (var file = File.Create("Data.bin")) {
            Serializer.Serialize<IEnumerable<Asset>>(file, Generate(10));
        }

        using (var file = File.OpenRead("Data.bin")) {
            var ps = Serializer.DeserializeItems<Asset>(file, PrefixStyle.Base128, 1);
            int i = ps.Count(); // got them all back :-)
        }
...