gpx-utils/pkg/openname/io.go

70 lines
1.6 KiB
Go
Raw Normal View History

package openname
import (
"archive/zip"
"encoding/gob"
"fmt"
"os"
"strings"
"github.com/ray1729/gpx-utils/pkg/placenames"
)
// ProcessFile reads the compressed OS Open Names data set and calls the handler for each record.
func ProcessFile(filename string, handler func(*Record) error) error {
r, err := zip.OpenReader(filename)
if err != nil {
return fmt.Errorf("error opening %s for reading: %v", filename, err)
}
defer r.Close()
for _, f := range r.File {
if !(strings.HasPrefix(f.Name, "DATA/") && strings.HasSuffix(f.Name, ".csv")) {
continue
}
rc, err := f.Open()
if err != nil {
return fmt.Errorf("error opening %s: %v", filename, err)
}
s, err := NewScanner(rc)
if err != nil {
rc.Close()
return fmt.Errorf("error reading %s: %v", f.Name, err)
}
for s.Scan() {
r := s.Record()
if r.Type == "populatedPlace" && r.MbrXMax != r.MbrXMin && r.MbrYMax != r.MbrYMin {
if err := handler(r); err != nil {
return err
}
}
}
if err = s.Err(); err != nil {
rc.Close()
return fmt.Errorf("error parsing %s: %v", f.Name, err)
}
rc.Close()
}
return nil
}
// Save processes the OS OpenNames zip file and outputs bounded places in gob format.
func Save(inFile string, outFile string) error {
wc, err := os.OpenFile(outFile, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644)
if err != nil {
return err
}
defer wc.Close()
enc := gob.NewEncoder(wc)
err = ProcessFile(inFile, func(r *Record) error {
b := placenames.NamedBoundary{
Name: r.Name,
Xmin: r.MbrXMin,
Ymin: r.MbrYMin,
Xmax: r.MbrXMax,
Ymax: r.MbrYMax}
return enc.Encode(b)
})
return err
}