2013-06-12 4 views
4

Нам нужны BSON эквивалент кИспользование потоков для создания массива BSON байт (для формата файла) с помощью Json.NET

{ 
    "Header": { 
     "SubHeader1": { 
      "Name": "Bond", 
      "License": 7 
     }, 
     "SubHeader2": { 
      "IsActive": true 
     } 
    }, 
    "Payload": /* This will be a 40GB byte stream! */ 
} 

Но что мы получаем:

enter image description here

As вы можете видеть, что полезная нагрузка появляется FIRST, а затем остальная часть заголовка!

Мы используем писателя BSON Json.NET (Bson.BsonWriter.WriteValue(byte[] value)), но он принимает только byte[], а не Stream. Так как наши полезные нагрузки будут 10s ГБ, мы должны использовать потоки, поэтому мы попытались обойти (код ниже), но это дает нам неправильный результат, показанный выше

public void Expt() 
{ 
    // Just some structure classes, defined below 
    var fileStruct = new FileStructure(); 

    using (Stream outputSt = new FileStream("TestBinary.bson", FileMode.Create)) 
    { 
     var serializer = new JsonSerializer(); 
     var bw = new BsonWriter(outputSt); 

     // Start 
     bw.WriteStartObject(); 

     // Write header    
     bw.WritePropertyName("Header"); 
     serializer.Serialize(bw, fileStruct.Header); 

     // Write payload 
     bw.WritePropertyName("Payload"); 
     bw.Flush(); // <== flush !     
     // In reality we 40GB into the stream, dummy example for now 
     byte[] dummyPayload = Encoding.UTF8.GetBytes("This will be a 40GB byte stream!"); 
     outputSt.Write(dummyPayload, 0, dummyPayload.Length); 

     // End 
     bw.WriteEndObject(); 
    }  
} 

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

Вопрос: Есть ли другой способ сделать это? Мы бы предпочли не отвалить от источника Json.NET (и исследовать его внутренние трубопроводы) или повторно изобрести колесо как-то ...


Детали: Опорные структуры классов (если вы хотите Репрографическим это)

public class FileStructure 
{ 
    public TopHeader Header { get; set; } 
    public byte[] Payload { get; set; } 

    public FileStructure() 
    { 
     Header = new TopHeader 
      { 
       SubHeader1 = new SubHeader1 {Name = "Bond", License = 007}, 
       SubHeader2 = new SubHeader2 {IsActive = true} 
      }; 
    } 
} 

public class TopHeader 
{ 
    public SubHeader1 SubHeader1 { get; set; } 
    public SubHeader2 SubHeader2 { get; set; } 
} 

public class SubHeader1 
{ 
    public string Name { get; set; } 
    public int License { get; set; } 
} 

public class SubHeader2 
{ 
    public bool IsActive { get; set; } 
} 
+0

'BsonWriter' записывает данные только в конце объектов (см.' BsonWriter.WriteEnd'). Похоже, вам придется копировать в свой проект и модифицировать довольно много классов ('BsonWriter',' BsonBinaryWriter', целую иерархию BsonToken и т. Д.), Чтобы реализовать потоки записи, поскольку они не предназначены для расширяемой. Эта функция выглядит весьма полезной, поэтому я предлагаю изменить код библиотеки и сделать запрос на перенос. Между прочим, будут некоторые ограничения; одним из требований является то, что потоку необходимо поддерживать его длину. – Athari

+0

Каким будет ваше обходное решение в отношении спецификации BSON, требующей 32-разрядного целого числа со знаком для описания длины потока (что ограничило бы размер вашей полезной нагрузки до 2 ГБ)? – DuckMaestro

+1

@DuckMaestro: взлом/расширение спецификации. Мы рассмотрели возможность взлома первого uint32 в uint64 (4 байта => 8 байтов) ИЛИ назначение особому значению uint32 length = 0 как «игнорировать первые 4 байта и читать следующие 8 байтов/uint64». К счастью, нам не пришлось идти по этому маршруту, так как мы приняли альтернативное решение (см. Ниже). BSON хорош, но все еще есть возможность расти для общности. – DeepSpace101

ответ

1

Итак, мы добрались до какой-то золотую середину здесь, потому что у нас нет времени (на данный момент), чтобы исправить иначе большую библиотеку Json.NET. Так как нам повезло иметь поток только в конце, мы теперь используем BSON для заголовка (достаточно мал для byte[]), а затем передать его на стандартный поток писателя т.е. представления является:

{ 
    "SubHeader1": { 
     "Name": "Bond", 
     "License": 7 
    }, 
    "SubHeader2": { 
     "IsActive": true 
    } 
} /* End of valid BSON */ 
// <= Our Stream is written here, raw byte stream, no BSON 

Было бы более эстетично иметь единую компоновку BSON, но в отсутствие ее это тоже отлично. Наверное, немного быстрее! Если кто-то еще найдет лучший ответ в будущем, мы слушаем.

+0

Чтобы добавить, мы в конечном итоге избавились от BSON и заменили его заголовком стиля ProtoBuf. Используя реализацию Marc Gavell, вы можете использовать что-то вроде 'Serializer.DeserializeWithLengthPrefix (readSteam, PrefixStyle.Base128);' ... только FYI – DeepSpace101

 Смежные вопросы

  • Нет связанных вопросов^_^