Documentation ¶
Overview ¶
Package flatgeobuf enables reading and writing FlatGeobuf files.
Index ¶
- Constants
- Variables
- func FeatureString(f *flat.Feature, s Schema) string
- func HeaderString(hdr *flat.Header) string
- type FileReader
- func (r *FileReader) Close() error
- func (r *FileReader) Data(p []flat.Feature) (int, error)
- func (r *FileReader) DataRem() ([]flat.Feature, error)
- func (r *FileReader) Header() (*flat.Header, error)
- func (r *FileReader) Index() (*packedrtree.PackedRTree, error)
- func (r *FileReader) IndexSearch(b packedrtree.Box) ([]flat.Feature, error)
- func (r *FileReader) Rewind() error
- type FileWriter
- func (w *FileWriter) Close() error
- func (w *FileWriter) Data(p []flat.Feature) (n int, err error)
- func (w *FileWriter) Header(hdr *flat.Header) (n int, err error)
- func (w *FileWriter) Index(index *packedrtree.PackedRTree) (n int, err error)
- func (w *FileWriter) IndexData(p []flat.Feature) (n int, err error)
- type PropReader
- func (r *PropReader) ReadBinary() ([]byte, error)
- func (r *PropReader) ReadBool() (bool, error)
- func (r *PropReader) ReadByte() (int8, error)
- func (r *PropReader) ReadDouble() (float64, error)
- func (r *PropReader) ReadFloat() (float32, error)
- func (r *PropReader) ReadInt() (int32, error)
- func (r *PropReader) ReadLong() (int64, error)
- func (r *PropReader) ReadSchema(schema Schema) ([]PropValue, error)
- func (r *PropReader) ReadShort() (int16, error)
- func (r *PropReader) ReadString() (string, error)
- func (r *PropReader) ReadUByte() (uint8, error)
- func (r *PropReader) ReadUInt() (uint32, error)
- func (r *PropReader) ReadULong() (uint64, error)
- func (r *PropReader) ReadUShort() (uint16, error)
- type PropValue
- type PropWriter
- func (w *PropWriter) WriteBinary(v []byte) (n int, err error)
- func (w *PropWriter) WriteBool(v bool) (n int, err error)
- func (w *PropWriter) WriteByte(v int8) (n int, err error)
- func (w *PropWriter) WriteDouble(v float64) (n int, err error)
- func (w *PropWriter) WriteFloat(v float32) (n int, err error)
- func (w *PropWriter) WriteInt(v int32) (n int, err error)
- func (w *PropWriter) WriteLong(v int64) (n int, err error)
- func (w *PropWriter) WriteShort(v int16) (n int, err error)
- func (w *PropWriter) WriteString(v string) (n int, err error)
- func (w *PropWriter) WriteUByte(v uint8) (n int, err error)
- func (w *PropWriter) WriteUInt(v uint32) (n int, err error)
- func (w *PropWriter) WriteULong(v uint64) (n int, err error)
- func (w *PropWriter) WriteUShort(v uint16) (n int, err error)
- type Schema
- type SpecVersion
Examples ¶
Constants ¶
const ( // MinSpecMajorVersion is the minimum major version of the // FlatGeobuf specification that this package can read. MinSpecMajorVersion = 0x03 // MaxSpecMajorVersion is the maximum major version of the // FlatGeobuf specification that this package can read. MaxSpecMajorVersion = 0x03 )
Variables ¶
var ( // ErrNoIndex is returned when attempting to do an index read or // search on a FlatGeobuf file that has no index. ErrNoIndex = textErr("no index") // ErrNotSeekable is returned from a FileReader's Rewind method if // its underlying stream does not implement io.Seeker. ErrNotSeekable = textErr("can't rewind: reader is not an io.Seeker") // ErrClosed is returned when attempting to perform an operation on // a FileReader or FileWriter which has been closed. ErrClosed = textErr("closed") )
Functions ¶
func FeatureString ¶
FeatureString returns a string summarizing the Feature. The returned value is a summary and not meant to be exhaustive.
Property column names are taken from the Feature's column schema, if it has one. If not, they are taken from the supplied Schema parameter if it is not nil. The supplied Schema parameter will typically be the *flat.Header from the feature's FlatGeobuf file.
func HeaderString ¶
HeaderString returns a string summarizing the Header fields. The returned value is a summary and not meant to be exhaustive.
Types ¶
type FileReader ¶
type FileReader struct {
// contains filtered or unexported fields
}
FileReader reads an underlying io.Reader stream as a FlatGeobuf file.
The underlying stream may optionally implement io.Seeker to enable streaming index searches via IndexSearch and Rewind.
Example (EmptyFile) ¶
package main import ( "bytes" "compress/bzip2" "encoding/base64" "fmt" "io" "strings" "github.com/gogama/flatgeobuf/flatgeobuf" testdata "github.com/gogama/flatgeobuf/flatgeobuf/testdata/flatgeobuf" ) func testdataReader(data string) io.Reader { var r io.Reader r = strings.NewReader(data) r = base64.NewDecoder(base64.StdEncoding, r) r = bzip2.NewReader(r) b, err := io.ReadAll(r) if err != nil { panic(err) } return bytes.NewReader(b) } func main() { // This simple example reads a trivial, empty, FlatGeobuf file. It // opens the file, reads the FlatGeobuf header, attempts to read the // index (but gets an error because the file has no index), and // reads the data section, which contains no features. r := flatgeobuf.NewFileReader(testdataReader(testdata.EmptyFGB)) defer r.Close() hdr, err := r.Header() if err != nil { panic(err) } fmt.Println(flatgeobuf.HeaderString(hdr)) index, err := r.Index() fmt.Printf("Index = %v, err = %v\n", index, err) data, err := r.DataRem() fmt.Printf("Data = %v, err = %v\n", data, err) }
Output: Header{Name:gps_mobile_tiles,Type:Polygon,Columns:6,Features:Unknown,No Index,CRS:{Org:EPSG,Code:4326,Name:WGS 84,WKT:821 bytes}} Index = <nil>, err = flatgeobuf: no index Data = [], err = <nil>
Example (UnknownFeatureCount) ¶
package main import ( "bytes" "compress/bzip2" "encoding/base64" "fmt" "io" "strings" "github.com/gogama/flatgeobuf/flatgeobuf" testdata "github.com/gogama/flatgeobuf/flatgeobuf/testdata/flatgeobuf" ) func testdataReader(data string) io.Reader { var r io.Reader r = strings.NewReader(data) r = base64.NewDecoder(base64.StdEncoding, r) r = bzip2.NewReader(r) b, err := io.ReadAll(r) if err != nil { panic(err) } return bytes.NewReader(b) } func main() { // This example reads a FlatGeobuf file which has an unknown feature // count, indicated by a zero in the header's feature count field. // The FileReader's DataRem() method provides a one-liner read all // available features at once. It is equivalent to using Data() in // a loop until EOF is reached. r := flatgeobuf.NewFileReader(testdataReader(testdata.UnknownFeatureCountFGB)) defer r.Close() hdr, err := r.Header() if err != nil { panic(err) } fmt.Println(flatgeobuf.HeaderString(hdr)) data, _ := r.DataRem() // Ignoring error to simplify example only! if len(data) > 0 { fmt.Printf("len(Data) -> %d, Data[0] -> %s\n", len(data), flatgeobuf.FeatureString(&data[0], hdr)) } }
Output: Header{Name:gps_mobile_tiles,Type:Polygon,Columns:6,Features:Unknown,No Index,CRS:{Org:EPSG,Code:4326,Name:WGS 84,WKT:821 bytes}} len(Data) -> 1, Data[0] -> Feature{Geometry:{Type:Unknown,Bounds:[-69.911499,18.458768,-69.906006,18.463979]},Properties:{quadkey:0322113021201023,avg_d_kbps:16109,avg_u_kbps:11204,avg_lat_ms:36,tests:98,devices:49}}
func NewFileReader ¶
func NewFileReader(r io.Reader) *FileReader
NewFileReader creates a new FlatGeobuf file reader based on an underlying input stream.
The underlying reader must be positioned at the beginning of the file, i.e. right before the FlatGeobuf magic number.
If the underlying reader implements the io.Seeker interface and the underlying FlatGeobuf file has an index, the index can be searched in a streaming manner using the new FileReader's IndexSearch method.
func (*FileReader) Close ¶
func (r *FileReader) Close() error
Close closes the FileReader. All subsequent calls to any method will return ErrClosed.
If the underlying stream implements io.Closer, this method invokes Close on the underlying stream and returns the result.
func (*FileReader) Data ¶
func (r *FileReader) Data(p []flat.Feature) (int, error)
Data reads up to len(p) feature structures from the FlatGeobuf data section into p. If fewer than len(p) features remain to be read then only the remaining features are read into p. The number of features (not bytes!) actually read is returned.
This method may only be called once Header has been called. If a previous call to Data has not been made since the last successful Header or Rewind call, Data starts reading from the beginning of the data section. Otherwise, it resumes reading from the position that the last Data call left off.
If no features remain to be read, the return value is a count of 0 and the error io.EOF. This method will never return io.EOF if the count returned is positive; but any other I/O error maybe returned with a positive count, for example io.ErrUnexpectedEOF.
func (*FileReader) DataRem ¶
func (r *FileReader) DataRem() ([]flat.Feature, error)
DataRem reads and returns all remaining unread features from the FlatGeobuf data section.
This method may only be called once Header has been called. If a previous call to Data has not been made since the last successful Header or Rewind call, DataRem reads all features from the data section. Otherwise, it reads all features remaining after the last Data call left off.
func (*FileReader) Header ¶
func (r *FileReader) Header() (*flat.Header, error)
Header reads and returns the FlatBuffer table containing the FlatGeobuf file's header table.
This method may only be called once, immediately after creating the FileReader via NewFileReader. Once the reader has advanced past the header, it cannot be read again.
If the header table cannot be read, the return value is a nil pointer and an error. If the header table was successfully read and contains usable values, the return value is a non-nil pointer and a nil error. Lastly, if the header table was successfully read, but the feature count or index node size values it contains are unusable, the return value is a non-nil pointer and an error, in which case this reader will transition to a permanent error state from which only the Close() method will work without further error.
func (*FileReader) Index ¶
func (r *FileReader) Index() (*packedrtree.PackedRTree, error)
Index reads and returns an in-memory implementation of the FlatGeobuf file's index data structure. If the FlatGeobuf file has no index, the error ErrNoIndex is returned.
This method may only be called immediately after a successful call to Header or Rewind.
As an alternative to calling Index, consider IndexSearch, which combines reading the index data structure, searching it, and returning the features for each qualified match in the search results.
Example ¶
package main import ( "bytes" "compress/bzip2" "encoding/base64" "fmt" "io" "sort" "strings" "github.com/gogama/flatgeobuf/flatgeobuf" "github.com/gogama/flatgeobuf/flatgeobuf/flat" testdata "github.com/gogama/flatgeobuf/flatgeobuf/testdata/flatgeobuf" "github.com/gogama/flatgeobuf/packedrtree" ) func testdataReader(data string) io.Reader { var r io.Reader r = strings.NewReader(data) r = base64.NewDecoder(base64.StdEncoding, r) r = bzip2.NewReader(r) b, err := io.ReadAll(r) if err != nil { panic(err) } return bytes.NewReader(b) } func main() { // This example reads from a FlatGeobuf file which contains an // index. It reads the entire index data structure into memory using // the FileReader's Index() method, searches the index to find // candidate features that may intersect a bounding box, then // reads the data section up to the first candidate feature and // prints a string summary of the candidate. r := flatgeobuf.NewFileReader(testdataReader(testdata.CountriesFGB)) defer r.Close() hdr, err := r.Header() if err != nil { panic(err) } fmt.Println(flatgeobuf.HeaderString(hdr)) // Read the index into memory. This is a good option if repeated index // searches are planned. index, _ := r.Index() fmt.Println("Index ->", index) // Search the index for features intersecting a bounding box. results := index.Search(packedrtree.Box{ XMin: -81.73195714597884, YMin: 47.667150959664525, XMax: -81.71291285629297, YMax: 47.67849844412743, }) fmt.Printf("Results -> %+v\n", results) // Read the search results, and print the properties for the first // intersecting result. if len(results) > 0 { sort.Sort(results) data := make([]flat.Feature, results[0].RefIndex+1) n, _ := r.Data(data) // Ignoring error to simplify example only! if n > results[0].RefIndex { fmt.Printf("First Result: %s\n", flatgeobuf.FeatureString(&data[results[0].RefIndex], hdr)) } } }
Output: Header{Name:countries,Envelope:[-180,-85.609038,180,83.64513],Type:MultiPolygon,Columns:2,Features:179,NodeSize:16,CRS:{Org:EPSG,Code:4326,Name:WGS 84,WKT:354 bytes}} Index -> PackedRTree{Bounds:[-180,-85.609038,180,83.64513],NumRefs:179,NodeSize:16} Results -> [{Offset:147776 RefIndex:162} {Offset:160424 RefIndex:165} {Offset:167864 RefIndex:166}] First Result: Feature{Geometry:{Type:MultiPolygon,Bounds:[-180,41.151416,180,81.2504],Parts:13},Properties:{id:RUS,name:Russia}}
func (*FileReader) IndexSearch ¶
func (r *FileReader) IndexSearch(b packedrtree.Box) ([]flat.Feature, error)
IndexSearch searches the FlatGeobuf file's index and returns the FlatBuffer table corresponding to each data section feature whose bounding box intersects the query box. If the FlatGeobuf file has no index, the error ErrNoIndex is returned.
This method may only be called immediately after a successful call to Header or Rewind.
If the underlying stream passed to NewFileReader implements the io.Seeker interface, IndexSearch will perform a streaming search of the index without needing to read the whole index into memory. This allows efficient searches of random access capable streams, including HTTP streams using HTTP range requests. Again if io.Seeker is implemented, repeated streaming searches are enabled by calling Rewind after each call to IndexSearch.
Example (Streaming) ¶
package main import ( "bytes" "compress/bzip2" "encoding/base64" "fmt" "io" "strings" "github.com/gogama/flatgeobuf/flatgeobuf" "github.com/gogama/flatgeobuf/flatgeobuf/flat" testdata "github.com/gogama/flatgeobuf/flatgeobuf/testdata/flatgeobuf" "github.com/gogama/flatgeobuf/packedrtree" ) func testdataReader(data string) io.Reader { var r io.Reader r = strings.NewReader(data) r = base64.NewDecoder(base64.StdEncoding, r) r = bzip2.NewReader(r) b, err := io.ReadAll(r) if err != nil { panic(err) } return bytes.NewReader(b) } func main() { // This example demonstrates a streaming index search of a // FlatGeobuf file which contains an index. The FileReader's // IndexSearch() function reads and searches the index and fetches // all candidate features in a streaming manner, reading only the // minimum necessary data into memory. r := flatgeobuf.NewFileReader(testdataReader(testdata.UScountiesFGB)) defer r.Close() hdr, err := r.Header() if err != nil { panic(err) } fmt.Println(flatgeobuf.HeaderString(hdr)) var data []flat.Feature // First search: Cook County, IL. if data, err = r.IndexSearch(packedrtree.Box{ XMin: -87.63429124101445, YMin: 41.87174069508944, XMax: -87.61485750565028, YMax: 41.88406678494189, }); err != nil || len(data) == 0 { panic(fmt.Sprintf("err= %v, len(data) = %d", err, len(data))) } fmt.Printf("First search, first Result: %s\n", flatgeobuf.FeatureString(&data[0], hdr)) // Rewind. if err = r.Rewind(); err != nil { panic(err) } // Second search: Maricopa County, AZ. if data, err = r.IndexSearch(packedrtree.Box{ XMin: -112.10457517582745, YMin: 33.43241637947986, XMax: -112.03936601127879, YMax: 33.46045877551812, }); err != nil || len(data) == 0 { panic(fmt.Sprintf("err= %v, len(features) = %d", err, len(data))) } fmt.Printf("Second search, first Result: %s\n", flatgeobuf.FeatureString(&data[0], hdr)) }
Output: Header{Name:US__counties,Envelope:[-179.14734,17.884813,179.77847,71.352561],Type:Unknown,Columns:6,Features:3221,NodeSize:16,CRS:{Org:EPSG,Code:4269,Name:NAD83,WKT:1280 bytes}} First search, first Result: Feature{Geometry:{Type:MultiPolygon,Bounds:[-88.263572,41.469555,-87.524044,42.154265],Parts:1},Properties:{STATE_FIPS:17,COUNTY_FIP:031,FIPS:17031,STATE:IL,NAME:Cook,LSAD:County}} Second search, first Result: Feature{Geometry:{Type:MultiPolygon,Bounds:[-113.33438,32.504938,-111.03991,34.04817],Parts:1},Properties:{STATE_FIPS:04,COUNTY_FIP:013,FIPS:04013,STATE:AZ,NAME:Maricopa,LSAD:County}}
func (*FileReader) Rewind ¶
func (r *FileReader) Rewind() error
Rewind seeks the read position of the underlying stream to the position directly after the FlatGeobuf header buffer, enabling repeat calls to IndexSearch, Index, Data, or DataRem. Returns ErrNotSeekable if the underlying stream does not implement io.Seeker.
This method may only be called once Header has been called.
type FileWriter ¶
type FileWriter struct {
// contains filtered or unexported fields
}
FileWriter writes a FlatGeobuf file to an underlying stream.
func NewFileWriter ¶
func NewFileWriter(w io.Writer) *FileWriter
NewFileWriter creates a new FlatGeobuf file writer based on an underlying output stream.
The underlying writer must be positioned at the beginning of the file, i.e. right before the FlatGeobuf magic number.
func (*FileWriter) Close ¶
func (w *FileWriter) Close() error
Close closes the FileWriter. All subsequent calls to any method will return ErrClosed.
If the underlying stream implements io.Closer, this method invokes Close on the underlying stream and returns the result.
func (*FileWriter) Data ¶
func (w *FileWriter) Data(p []flat.Feature) (n int, err error)
Data writes features into the data section. If the feature count field written with Header is non-zero, then the input feature count, plus the count of features already written, may not exceed file feature count. The total number of bytes written is returned.
This method may only be called after Header has been called. If a positive index node size was indicated with Header, then it may only be called after Index has been called. This method may be called repeatedly to stream as many features as desired into the data section, as long as total number of features written does not exceed a positive feature count written with Header.
The input features are FlatBuffer tables. Each feature must be a size-prefixed root table positioned at offset 0 within its buffer. This type of value is returned by FileReader.Data, FileReader.DataRem, and from flat.GetSizePrefixedRootAsFeature.
func (*FileWriter) Header ¶
func (w *FileWriter) Header(hdr *flat.Header) (n int, err error)
Header writes the FlatGeobuf file magic number, followed by the given FlatGeobuf header structure. The total number of bytes written, including magic number and header bytes, is returned.
The input header table must be a size-prefixed root FlatBuffer table positioned at offset 0 within its FlatBuffer. This type of value is returned by FileReader.Header or from flat.GetSizePrefixedRootAsHeader.
This method may only be called once, immediately after creating the FileWriter via NewFileWriter.
func (*FileWriter) Index ¶
func (w *FileWriter) Index(index *packedrtree.PackedRTree) (n int, err error)
Index serializes and writes an in-memory FlatGeobuf index data structure to the index section of a FlatGeobuf file. The index node size and feature count must match the corresponding header fields written with Header. The total number of bytes written is returned.
If used, this method must be called immediately after a successful call to Header, and may only be called once. Alternatively, the IndexData method may be used, or the index may be skipped and Data may be called directly after Header.
func (*FileWriter) IndexData ¶
func (w *FileWriter) IndexData(p []flat.Feature) (n int, err error)
IndexData generates and writes an index for the given feature list, to the index section of a FlatGeobuf file, and then writes the features themselves into the data section. The input feature count must match the feature count header field written with Header. The total number of bytes written, to both index and data sections, is returned.
If used, this method must be called immediately after a successful call to Header, and may only be called once. Alternatively, the Index method may be used if you already have an index data structure ready to serializeIndex, or the index may be skipped and Data may be called directly after Header.
The input features are FlatBuffer tables. Each feature must be a size-prefixed root table positioned at offset 0 within its buffer. This type of value is returned by FileReader.Data, FileReader.DataRem, and from flat.GetSizePrefixedRootAsFeature.
type PropReader ¶
type PropReader struct {
// contains filtered or unexported fields
}
PropReader reads a list of key/value pairs in FlatGeobuf property format from an underlying stream.
Each FlatGeobuf feature table (flat.Feature) contains an optional byte array field named Properties which is encoded in its own custom format, a format-within-a-format, if you will. PropReader knows how to read this special format-within-a-format.
To read all properties at once for a given feature property Schema, use ReadSchema.
Use ReadString for flat.ColumnTypeString and flat.ColumnTypeDateTime. Use ReadBinary for flat.ColumnTypeBinary and flat.ColumnTypeJson.
Example ¶
package main import ( "bytes" "encoding/hex" "fmt" "github.com/gogama/flatgeobuf/flatgeobuf" ) func main() { // Start with a byte buffer containing three trivial properties. // // Normally you would obtain this buffer using the PropertiesBytes() // method of a flat.Feature, but we omit that part for simplicity. propBytes, _ := hex.DecodeString("000003000000666f6f010024082020020001") // Read the three properties. Error handling is omitted for brevity. // // If your column schema can vary, or you just want a simpler // interface to read properties, you may want to use the ReadSchema // method to read all properties at once. pr := flatgeobuf.NewPropReader(bytes.NewReader(propBytes)) col, _ := pr.ReadUShort() // Column number str, _ := pr.ReadString() // Property value fmt.Printf("Column %d is the string value %q\n", col, str) col, _ = pr.ReadUShort() // Column number u, _ := pr.ReadUInt() // Property value fmt.Printf("Column %d is the unsigned integer value 0x%x\n", col, u) col, _ = pr.ReadUShort() // Column number b, _ := pr.ReadBool() // Property value fmt.Printf("Column %d is the boolean value %t\n", col, b) }
Output: Column 0 is the string value "foo" Column 1 is the unsigned integer value 0x20200824 Column 2 is the boolean value true
func NewPropReader ¶
func NewPropReader(r io.Reader) *PropReader
NewPropReader creates a new FlatGeobuf feature property reader reading from an underlying input stream.
func (*PropReader) ReadBinary ¶
func (r *PropReader) ReadBinary() ([]byte, error)
ReadBinary reads an arbitrary-length property value, which can be either flat.ColumnTypeBinary or a flat.ColumnTypeJson.
func (*PropReader) ReadBool ¶
func (r *PropReader) ReadBool() (bool, error)
ReadBool reads the value of a flat.ColumnTypeBool property (a byte value of zero for false, one for true).
func (*PropReader) ReadByte ¶
func (r *PropReader) ReadByte() (int8, error)
ReadByte reads the value of a flat.ColumnTypeByte property (signed byte value).
func (*PropReader) ReadDouble ¶
func (r *PropReader) ReadDouble() (float64, error)
ReadDouble reads the value of a flat.ColumnTypeDouble property (an IEEE 64-bit double precision floating point number).
func (*PropReader) ReadFloat ¶
func (r *PropReader) ReadFloat() (float32, error)
ReadFloat reads the value of a flat.ColumnTypeFloat property (an IEEE 32-bit single precision floating point number).
func (*PropReader) ReadInt ¶
func (r *PropReader) ReadInt() (int32, error)
ReadInt writes the value of a flat.ColumnTypeInt property (a 32-bit signed integer value).
func (*PropReader) ReadLong ¶
func (r *PropReader) ReadLong() (int64, error)
ReadLong reads the value of a flat.ColumnTypeLong property (a 64-bit signed integer value).
func (*PropReader) ReadSchema ¶
func (r *PropReader) ReadSchema(schema Schema) ([]PropValue, error)
ReadSchema all properties specified in the given Schema, returning them as a slice of PropValue structures.
The concrete implementation of the schema will typically be a *flat.Header or a *flat.Feature.
Example ¶
package main import ( "bytes" "encoding/hex" "fmt" "github.com/gogama/flatgeobuf/flatgeobuf" "github.com/gogama/flatgeobuf/flatgeobuf/flat" flatbuffers "github.com/google/flatbuffers/go" ) func simpleHeader() *flat.Header { bldr := flatbuffers.NewBuilder(0) col0Name := bldr.CreateString("A string") col1Name := bldr.CreateString("An unsigned int") col2Name := bldr.CreateString("A bool") flat.ColumnStart(bldr) flat.ColumnAddName(bldr, col0Name) flat.ColumnAddType(bldr, flat.ColumnTypeString) col0 := flat.ColumnEnd(bldr) flat.ColumnStart(bldr) flat.ColumnAddName(bldr, col1Name) flat.ColumnAddType(bldr, flat.ColumnTypeUInt) col1 := flat.ColumnEnd(bldr) flat.ColumnStart(bldr) flat.ColumnAddName(bldr, col2Name) flat.ColumnAddType(bldr, flat.ColumnTypeBool) col2 := flat.ColumnEnd(bldr) flat.HeaderStartColumnsVector(bldr, 3) bldr.PrependUOffsetT(col2) bldr.PrependUOffsetT(col1) bldr.PrependUOffsetT(col0) cols := bldr.EndVector(3) flat.HeaderStart(bldr) flat.HeaderAddColumns(bldr, cols) hdr := flat.HeaderEnd(bldr) flat.FinishSizePrefixedHeaderBuffer(bldr, hdr) return flat.GetSizePrefixedRootAsHeader(bldr.FinishedBytes(), 0) } func main() { // Get an example FlatGeobuf file header. Both *flat.Header and // *flat.Feature implement Schema and can be used with ReadSchema. hdr := simpleHeader() // Start with a byte buffer containing three trivial properties // which follows the schema from the above header. // // Normally you would obtain this buffer using the PropertiesBytes() // method of a flat.Feature, but we omit that part for simplicity. propBytes, _ := hex.DecodeString("000003000000666f6f010024082020020001") // Read the properties. pr := flatgeobuf.NewPropReader(bytes.NewReader(propBytes)) vals, _ := pr.ReadSchema(hdr) // Print the properties. fmt.Println(vals[0]) fmt.Println(vals[1]) fmt.Println(vals[2]) }
Output: PropValue{Name:"A string",Type:String,Value:"foo",ColIndex:0} PropValue{Name:"An unsigned int",Type:UInt,Value:0x20200824,ColIndex:1} PropValue{Name:"A bool",Type:Bool,Value:true,ColIndex:2}
func (*PropReader) ReadShort ¶
func (r *PropReader) ReadShort() (int16, error)
ReadShort reads the value of a flat.ColumnTypeShort property (a 16-bit signed integer value).
func (*PropReader) ReadString ¶
func (r *PropReader) ReadString() (string, error)
ReadString reads the value of a string property of type flat.ColumnTypeString.
ReadString can also be used to read a value of type flat.ColumnTypeDateTime, since FlatGeobuf encodes date/time values as strings serialized in the ISO-8601 format.
func (*PropReader) ReadUByte ¶
func (r *PropReader) ReadUByte() (uint8, error)
ReadUByte reads the value of a flat.ColumnTypeUByte property (unsigned byte value).
func (*PropReader) ReadUInt ¶
func (r *PropReader) ReadUInt() (uint32, error)
ReadUInt reads the value of a flat.ColumnTypeUInt property (a 32-bit unsigned integer value).
func (*PropReader) ReadULong ¶
func (r *PropReader) ReadULong() (uint64, error)
ReadULong reads the value of a flat.ColumnTypeULong property (a 64-bit unsigned integer value).
func (*PropReader) ReadUShort ¶
func (r *PropReader) ReadUShort() (uint16, error)
ReadUShort reads the value of a flat.ColumnTypeUShort property (a 16-bit unsigned integer value).
type PropValue ¶
type PropValue struct { // Col is the FlatGeobuf column table describing the property's // column, or key. Col flat.Column // Value is the deserialized property value. Value any // ColIndex is the zero-based index of the property within the // feature's column schema. ColIndex uint16 // Type is the FlatGeobuf column type. This value is repeated in the // Type field for ease of consumption, and is also available through // Col. Type flat.ColumnType }
PropValue pairs together a FlatGeobuf feature property "key" (a flat.Column reference) with the property value and the type of its value.
type PropWriter ¶
type PropWriter struct {
// contains filtered or unexported fields
}
PropWriter writes a list of key/value pairs in FlatGeobuf property format to an underlying stream.
Each FlatGeobuf feature table (flat.Feature) contains an optional byte array field named Properties which is encoded in its own custom format, a format-within-a-format, if you will. PropWriter knows how to write this special format-within-a-format.
A typical usage pattern is to write the properties for a feature to a byte buffer using a PropWriter, convert the buffer containing the properties into a FlatBuffer byte vector (with flatbuffers.Builder), and finally supply the vector offset when building the feature using flat.FeatureAddProperties.
Use WriteString for flat.ColumnTypeString and flat.ColumnTypeDateTime. Use WriteBinary for flat.ColumnTypeBinary and flat.ColumnTypeJson.
Example ¶
package main import ( "bytes" "encoding/hex" "fmt" "github.com/gogama/flatgeobuf/flatgeobuf" "github.com/gogama/flatgeobuf/flatgeobuf/flat" flatbuffers "github.com/google/flatbuffers/go" ) func main() { var buf bytes.Buffer pw := flatgeobuf.NewPropWriter(&buf) // Serialize the properties to a byte buffer in the FlatGeobuf // properties format. pw.WriteUShort(0) // Column 0 pw.WriteString("foo") pw.WriteUShort(1) // Column 1 pw.WriteUInt(0x20200824) pw.WriteUShort(2) // Column 2 pw.WriteBool(true) props := buf.Bytes() // Attach the properties to a FlatGeobuf feature. (Feature type and // geometry, which are required for a meaningful feature, are // omitted from this example to keep it lean.) bldr := flatbuffers.NewBuilder(0) propsOffset := bldr.CreateByteVector(props) flat.FeatureStart(bldr) flat.FeatureAddProperties(bldr, propsOffset) ftrOffset := flat.FeatureEnd(bldr) flat.FinishSizePrefixedFeatureBuffer(bldr, ftrOffset) fmt.Printf("props: %s, propsOffset: %d, ftrOffset: %d", hex.EncodeToString(props), propsOffset, ftrOffset) }
Output: props: 000003000000666f6f010024082020020001, propsOffset: 24, ftrOffset: 32
func NewPropWriter ¶
func NewPropWriter(w io.Writer) *PropWriter
NewPropWriter creates a new FlatGeobuf feature property writer based on an underlying output stream.
func (*PropWriter) WriteBinary ¶
func (w *PropWriter) WriteBinary(v []byte) (n int, err error)
WriteBinary writes an arbitrary-length property value, which can be either flat.ColumnTypeBinary or a flat.ColumnTypeJson.
func (*PropWriter) WriteBool ¶
func (w *PropWriter) WriteBool(v bool) (n int, err error)
WriteBool writes the value of a flat.ColumnTypeBool property (a byte value of zero for false, one for true).
func (*PropWriter) WriteByte ¶
func (w *PropWriter) WriteByte(v int8) (n int, err error)
WriteByte writes the value of a flat.ColumnTypeByte property (signed byte value).
func (*PropWriter) WriteDouble ¶
func (w *PropWriter) WriteDouble(v float64) (n int, err error)
WriteDouble writes the value of a flat.ColumnTypeDouble property (an IEEE 64-bit double precision floating point number).
func (*PropWriter) WriteFloat ¶
func (w *PropWriter) WriteFloat(v float32) (n int, err error)
WriteFloat writes the value of a flat.ColumnTypeFloat property (an IEEE 32-bit single precision floating point number).
func (*PropWriter) WriteInt ¶
func (w *PropWriter) WriteInt(v int32) (n int, err error)
WriteInt writes the value of a flat.ColumnTypeInt property (a 32-bit signed integer value).
func (*PropWriter) WriteLong ¶
func (w *PropWriter) WriteLong(v int64) (n int, err error)
WriteLong writes the value of a flat.ColumnTypeLong property (a 64-bit signed integer value).
func (*PropWriter) WriteShort ¶
func (w *PropWriter) WriteShort(v int16) (n int, err error)
WriteShort writes the value of a flat.ColumnTypeShort property (a 16-bit signed integer value).
func (*PropWriter) WriteString ¶
func (w *PropWriter) WriteString(v string) (n int, err error)
WriteString writes the value of a string property of type flat.ColumnTypeString.
WriteString can also be used to write a value of type flat.ColumnTypeDateTime provided the value is serialized to a string in the ISO-8601 format.
func (*PropWriter) WriteUByte ¶
func (w *PropWriter) WriteUByte(v uint8) (n int, err error)
WriteUByte writes the value of a flat.ColumnTypeUByte property (unsigned byte value).
func (*PropWriter) WriteUInt ¶
func (w *PropWriter) WriteUInt(v uint32) (n int, err error)
WriteUInt writes the value of a flat.ColumnTypeUInt property (a 32-bit unsigned integer value).
func (*PropWriter) WriteULong ¶
func (w *PropWriter) WriteULong(v uint64) (n int, err error)
WriteULong writes the value of a flat.ColumnTypeULong property (a 64-bit unsigned integer value).
func (*PropWriter) WriteUShort ¶
func (w *PropWriter) WriteUShort(v uint16) (n int, err error)
WriteUShort writes the value of a flat.ColumnTypeUShort property (a 16-bit unsigned integer value).
type Schema ¶
type Schema interface { // ColumnsLength returns the number of columns, i.e. properties, in // the schema. ColumnsLength() int // Columns obtains the metadata for the column, i.e. property, at a // specific index. // // The index j may range from 0 to ColumnsLength()-1. The pointer // obj must not be nil. On return, obj points to the property // metadata (flat.Column) for property j and the return value is // true. A return value of false indicates that no property metadata // was found for the property at index j. Columns(obj *flat.Column, j int) bool }
Schema is a schema for FlatGeobuf's feature property format. It documents the number of available properties (ColumnsLength) for a feature and the property definition (flat.Column) for each property.
Both the header structure (flat.Header) of a FlatGeobuf file and an individual feature within the data section (flat.Feature) implement Schema. When provided on the header table, the Schema applies to all features in the data section, except those features that have their own dedicated schema. When provided on an individual feature, the Schema applies only to that feature.
Use PropReader.ReadSchema to read all properties from a FlatGeobuf properties buffer that is serialized according to a particular schema.
type SpecVersion ¶
type SpecVersion struct { // Major is the major version of the FlatGeobuf specification. Major uint8 // Patch is the patch version of the FlatGeobuf specification. Patch uint8 }
SpecVersion is a version of the FlatGeobuf specification.
func Magic ¶
func Magic(r io.Reader) (SpecVersion, error)
Magic reads the FlatGeobuf magic number from a stream and, if it is valid, returns the FlatGeobuf specification version. This function can be used to test whether any file seems to be in the FlatGeobuf format. However, it does not read beyond the magic number.
Calling this function will result in 8 bytes being read from the stream reader (unless there were fewer than 8 bytes available, in which all available bytes in the stream are consumed).
Example ¶
package main import ( "bytes" "compress/bzip2" "encoding/base64" "fmt" "io" "strings" "github.com/gogama/flatgeobuf/flatgeobuf" testdata "github.com/gogama/flatgeobuf/flatgeobuf/testdata/flatgeobuf" ) func testdataReader(data string) io.Reader { var r io.Reader r = strings.NewReader(data) r = base64.NewDecoder(base64.StdEncoding, r) r = bzip2.NewReader(r) b, err := io.ReadAll(r) if err != nil { panic(err) } return bytes.NewReader(b) } func main() { var r = testdataReader(testdata.Poly00FGB) version, err := flatgeobuf.Magic(r) fmt.Printf("%+v, %v\n", version, err) }
Output: {Major:3 Patch:0}, <nil>