2011-01-11 11 views
6

Per la vita di me non posso deserializzare il file protobuf da Open Street Maps.Protobuf-net Deserialize Open Street Maps

Sto tentando di deserializzare il seguente estratto: http://download.geofabrik.de/osm/north-america/us-northeast.osm.pbf per ottenere i nodi e sto usando http://code.google.com/p/protobuf-net/ come libreria. Ho provato a deserializzare un sacco di oggetti diversi, ma tutti vengono nulli.

I file proto possono essere trovate qui: http://trac.openstreetmap.org/browser/applications/utils/export/osm2pgsql/protobuf

Qualche suggerimento?

+0

Sono l'autore di protobuf-net; In questo momento sono in "lavoro", ma cercherò di vederlo più tardi oggi, per vedere qual è il problema –

+0

So chi sei Marc, ho scaricato il tuo software. Mi piace il lavoro tra parentesi haha. Grazie per il tuo aiuto (e il framework)! – jonperl

risposta

8

Diritto; il problema è che questo non è solo protobuf - si tratta di un formato di file ibrido (defined here che include protobuf tra diversi formati internamente Incorpora anche la compressione (anche se questo sembra essere opzionale)

I'.. Ho fatto a pezzi quello che posso dalle specifiche, e qui ho un lettore C# che usa protobuf-net per gestire i blocchi - legge felicemente quel file fino alla fine - posso dirti che ci sono 4515 blocchi (BlockHeader) Quando arriva il Blob Sono un po 'confuso su come le specifiche demark OSMHeader e OSMData - Sono aperto a suggerimenti qui! Ho anche utilizzato ZLIB.NET per gestire la compressione di zlib che viene utilizzata. di prendendo la mia testa intorno a questo, mi sono accontentato di elaborare i dati ZLIB e di convalidarlo contro la dimensione richiesta, per verificare che sia almeno sano di mente. .

Se si riesce a capire (o chiedere l'autore) il modo in cui stanno separando OSMHeader e OSMData te lo felicemente manovella qualcos'altro in spero che non ti dispiaccia che ho fermato qui - ma è stato un poche ore; p

using System; 
using System.IO; 
using OpenStreetMap; // where my .proto-generated entities are living 
using ProtoBuf; // protobuf-net 
using zlib; // ZLIB.NET  

class OpenStreetMapParser 
{ 

    static void Main() 
    { 
     using (var file = File.OpenRead("us-northeast.osm.pbf")) 
     { 
      // from http://wiki.openstreetmap.org/wiki/ProtocolBufBinary: 
      //A file contains a header followed by a sequence of fileblocks. The design is intended to allow future random-access to the contents of the file and skipping past not-understood or unwanted data. 
      //The format is a repeating sequence of: 
      //int4: length of the BlockHeader message in network byte order 
      //serialized BlockHeader message 
      //serialized Blob message (size is given in the header) 

      int length, blockCount = 0; 
      while (Serializer.TryReadLengthPrefix(file, PrefixStyle.Fixed32, out length)) 
      { 
       // I'm just being lazy and re-using something "close enough" here 
       // note that v2 has a big-endian option, but Fixed32 assumes little-endian - we 
       // actually need the other way around (network byte order): 
       uint len = (uint)length; 
       len = ((len & 0xFF) << 24) | ((len & 0xFF00) << 8) | ((len & 0xFF0000) >> 8) | ((len & 0xFF000000) >> 24); 
       length = (int)len; 

       BlockHeader header; 
       // again, v2 has capped-streams built in, but I'm deliberately 
       // limiting myself to v1 features 
       using (var tmp = new LimitedStream(file, length)) 
       { 
        header = Serializer.Deserialize<BlockHeader>(tmp); 
       } 
       Blob blob; 
       using (var tmp = new LimitedStream(file, header.datasize)) 
       { 
        blob = Serializer.Deserialize<Blob>(tmp); 
       } 
       if(blob.zlib_data == null) throw new NotSupportedException("I'm only handling zlib here!"); 

       using(var ms = new MemoryStream(blob.zlib_data)) 
       using(var zlib = new ZLibStream(ms)) 
       { // at this point I'm very unclear how the OSMHeader and OSMData are packed - it isn't clear 
        // read this to the end, to check we can parse the zlib 
        int payloadLen = 0; 
        while (zlib.ReadByte() >= 0) payloadLen++; 
        if (payloadLen != blob.raw_size) throw new FormatException("Screwed that up..."); 
       } 
       blockCount++; 
       Console.WriteLine("Read block " + blockCount.ToString()); 


      } 
      Console.WriteLine("all done"); 
      Console.ReadLine(); 
     } 
    } 
} 
abstract class InputStream : Stream 
{ 
    protected abstract int ReadNextBlock(byte[] buffer, int offset, int count); 
    public sealed override int Read(byte[] buffer, int offset, int count) 
    { 
     int bytesRead, totalRead = 0; 
     while (count > 0 && (bytesRead = ReadNextBlock(buffer, offset, count)) > 0) 
     { 
      count -= bytesRead; 
      offset += bytesRead; 
      totalRead += bytesRead; 
      pos += bytesRead; 
     } 
     return totalRead; 
    } 
    long pos; 
    public override void Write(byte[] buffer, int offset, int count) 
    { 
     throw new NotImplementedException(); 
    } 
    public override void SetLength(long value) 
    { 
     throw new NotImplementedException(); 
    } 
    public override long Position 
    { 
     get 
     { 
      return pos; 
     } 
     set 
     { 
      if (pos != value) throw new NotImplementedException(); 
     } 
    } 
    public override long Length 
    { 
     get { throw new NotImplementedException(); } 
    } 
    public override void Flush() 
    { 
     throw new NotImplementedException(); 
    } 
    public override bool CanWrite 
    { 
     get { return false; } 
    } 
    public override bool CanRead 
    { 
     get { return true; } 
    } 
    public override bool CanSeek 
    { 
     get { return false; } 
    } 
    public override long Seek(long offset, SeekOrigin origin) 
    { 
     throw new NotImplementedException(); 
    } 
} 
class ZLibStream : InputStream 
{ // uses ZLIB.NET: http://www.componentace.com/download/download.php?editionid=25 
    private ZInputStream reader; // seriously, why isn't this a stream? 
    public ZLibStream(Stream stream) 
    { 
     reader = new ZInputStream(stream); 
    } 
    public override void Close() 
    { 
     reader.Close(); 
     base.Close(); 
    } 
    protected override int ReadNextBlock(byte[] buffer, int offset, int count) 
    { 
     // OMG! reader.Read is the base-stream, reader.read is decompressed! yeuch 
     return reader.read(buffer, offset, count); 
    } 

} 
// deliberately doesn't dispose the base-stream  
class LimitedStream : InputStream 
{ 
    private Stream stream; 
    private long remaining; 
    public LimitedStream(Stream stream, long length) 
    { 
     if (length < 0) throw new ArgumentOutOfRangeException("length"); 
     if (stream == null) throw new ArgumentNullException("stream"); 
     if (!stream.CanRead) throw new ArgumentException("stream"); 
     this.stream = stream; 
     this.remaining = length; 
    } 
    protected override int ReadNextBlock(byte[] buffer, int offset, int count) 
    { 
     if(count > remaining) count = (int)remaining; 
     int bytesRead = stream.Read(buffer, offset, count); 
     if (bytesRead > 0) remaining -= bytesRead; 
     return bytesRead; 
    } 
} 
+0

Questo è assolutamente meraviglioso. Grazie per l'inizio vado a vedere cosa posso ottenere! (Tu sei l'uomo). – jonperl

+0

Ho intenzione di provare a lavorare all'indietro da https://github.com/scrosby/OSM-binary/tree/master/src.java/crosby/binary – jonperl

0

Hai provato a ottenere un'area più piccola? come us-pacific.osm.pbf

Eventualmente sarebbe utile pubblicare i messaggi di errore.

+0

Viene ancora visualizzato null.Ho provato var f = Serializer.Deserialize (file); – jonperl

1

Dopo l'installazione di contorno da Mark ho capito l'ultima parte, cercando in http://git.openstreetmap.nl/index.cgi/pbf2osm.git/tree/src/main.c?h=35116112eb0066c7729a963b292faa608ddc8ad7

Ecco il codice finale.

using System; 
using System.Diagnostics; 
using System.IO; 
using crosby.binary; 
using OSMPBF; 
using PerlLLC.Tools; 
using ProtoBuf; 
using zlib; 

namespace OpenStreetMapOperations 
{ 
    class OpenStreetMapParser 
    { 
     static void Main() 
     { 
      using (var file = File.OpenRead(StaticTools.AssemblyDirectory + @"\us-pacific.osm.pbf")) 
      { 
       // from http://wiki.openstreetmap.org/wiki/ProtocolBufBinary: 
       //A file contains a header followed by a sequence of fileblocks. The design is intended to allow future random-access to the contents of the file and skipping past not-understood or unwanted data. 
       //The format is a repeating sequence of: 
       //int4: length of the BlockHeader message in network byte order 
       //serialized BlockHeader message 
       //serialized Blob message (size is given in the header) 

       int length, blockCount = 0; 
       while (Serializer.TryReadLengthPrefix(file, PrefixStyle.Fixed32, out length)) 
       { 
        // I'm just being lazy and re-using something "close enough" here 
        // note that v2 has a big-endian option, but Fixed32 assumes little-endian - we 
        // actually need the other way around (network byte order): 
        length = IntLittleEndianToBigEndian((uint)length); 

        BlockHeader header; 
        // again, v2 has capped-streams built in, but I'm deliberately 
        // limiting myself to v1 features 
        using (var tmp = new LimitedStream(file, length)) 
        { 
         header = Serializer.Deserialize<BlockHeader>(tmp); 
        } 
        Blob blob; 
        using (var tmp = new LimitedStream(file, header.datasize)) 
        { 
         blob = Serializer.Deserialize<Blob>(tmp); 
        } 
        if (blob.zlib_data == null) throw new NotSupportedException("I'm only handling zlib here!"); 

        HeaderBlock headerBlock; 
        PrimitiveBlock primitiveBlock; 

        using (var ms = new MemoryStream(blob.zlib_data)) 
        using (var zlib = new ZLibStream(ms)) 
        { 
         if (header.type == "OSMHeader") 
          headerBlock = Serializer.Deserialize<HeaderBlock>(zlib); 

         if (header.type == "OSMData") 
          primitiveBlock = Serializer.Deserialize<PrimitiveBlock>(zlib); 
        } 
        blockCount++; 
        Trace.WriteLine("Read block " + blockCount.ToString()); 


       } 
       Trace.WriteLine("all done"); 
      } 
     } 

     // 4-byte number 
     static int IntLittleEndianToBigEndian(uint i) 
     { 
      return (int)(((i & 0xff) << 24) + ((i & 0xff00) << 8) + ((i & 0xff0000) >> 8) + ((i >> 24) & 0xff)); 
     } 
    } 

    abstract class InputStream : Stream 
    { 
     protected abstract int ReadNextBlock(byte[] buffer, int offset, int count); 
     public sealed override int Read(byte[] buffer, int offset, int count) 
     { 
      int bytesRead, totalRead = 0; 
      while (count > 0 && (bytesRead = ReadNextBlock(buffer, offset, count)) > 0) 
      { 
       count -= bytesRead; 
       offset += bytesRead; 
       totalRead += bytesRead; 
       pos += bytesRead; 
      } 
      return totalRead; 
     } 
     long pos; 
     public override void Write(byte[] buffer, int offset, int count) 
     { 
      throw new NotImplementedException(); 
     } 
     public override void SetLength(long value) 
     { 
      throw new NotImplementedException(); 
     } 
     public override long Position 
     { 
      get 
      { 
       return pos; 
      } 
      set 
      { 
       if (pos != value) throw new NotImplementedException(); 
      } 
     } 
     public override long Length 
     { 
      get { throw new NotImplementedException(); } 
     } 
     public override void Flush() 
     { 
      throw new NotImplementedException(); 
     } 
     public override bool CanWrite 
     { 
      get { return false; } 
     } 
     public override bool CanRead 
     { 
      get { return true; } 
     } 
     public override bool CanSeek 
     { 
      get { return false; } 
     } 
     public override long Seek(long offset, SeekOrigin origin) 
     { 
      throw new NotImplementedException(); 
     } 
    } 
    class ZLibStream : InputStream 
    { // uses ZLIB.NET: http://www.componentace.com/download/download.php?editionid=25 
     private ZInputStream reader; // seriously, why isn't this a stream? 
     public ZLibStream(Stream stream) 
     { 
      reader = new ZInputStream(stream); 
     } 
     public override void Close() 
     { 
      reader.Close(); 
      base.Close(); 
     } 
     protected override int ReadNextBlock(byte[] buffer, int offset, int count) 
     { 
      // OMG! reader.Read is the base-stream, reader.read is decompressed! yeuch 
      return reader.read(buffer, offset, count); 
     } 

    } 
    // deliberately doesn't dispose the base-stream  
    class LimitedStream : InputStream 
    { 
     private Stream stream; 
     private long remaining; 
     public LimitedStream(Stream stream, long length) 
     { 
      if (length < 0) throw new ArgumentOutOfRangeException("length"); 
      if (stream == null) throw new ArgumentNullException("stream"); 
      if (!stream.CanRead) throw new ArgumentException("stream"); 
      this.stream = stream; 
      this.remaining = length; 
     } 
     protected override int ReadNextBlock(byte[] buffer, int offset, int count) 
     { 
      if (count > remaining) count = (int)remaining; 
      int bytesRead = stream.Read(buffer, offset, count); 
      if (bytesRead > 0) remaining -= bytesRead; 
      return bytesRead; 
     } 
    } 
} 
+0

Hai avuto problemi a leggere i nodi durante la de-serializzazione? Questo codice viene eseguito senza errori, tuttavia quando si cercano i dati in primitiveBlock non ottengo nulla. – ninehundredt

+0

Siamo spiacenti, non ho mai ricevuto una notifica. L'hai capito? Ricordo di essere in grado di accedere ai dati. Sebbene non usiamo più questo codice. – jonperl

+0

Ho finalmente ottenuto il funzionamento del codice dopo aver esaminato un altro progetto, ma abbiamo deciso di adottare un'altra soluzione dopo avere incontrato più problemi con le mappe stradali aperte. – ninehundredt

1

Sì, è venuto da ProtoGen in Fileformat.cs (sulla base di file di OSM Fileformat.proto .. codice qui sotto.)

package OSM_PROTO; 
    message Blob { 
    optional bytes raw = 1; 
    optional int32 raw_size = 2; 
    optional bytes zlib_data = 3; 
    optional bytes lzma_data = 4; 
    optional bytes bzip2_data = 5; 
    } 

    message BlockHeader { 
    required string type = 1; 
    optional bytes indexdata = 2; 
    required int32 datasize = 3; 
    } 

Ecco la dichiarazione di BlockHeader nel file generato:

public sealed partial class BlockHeader : pb::GeneratedMessage<BlockHeader, BlockHeader.Builder> {...} 

-> utilizzando pb = global :: Google.ProtocolBuffers;

(ProtocolBuffers.dll) è venuto con questo pacchetto:

http://code.google.com/p/protobuf-csharp-port/downloads/detail?name=protobuf-csharp-port-2.4.1.473-full-binaries.zip&can=2&q=