/
zipreader.go
107 lines (95 loc) · 2.64 KB
/
zipreader.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package shp
import (
"archive/zip"
"bytes"
"fmt"
"io"
"strings"
)
// ZipReader provides an interface for reading Shapefiles that are compressed in a ZIP archive.
type ZipReader struct {
sr SequentialReader
z *zip.Reader
}
// openFromZIP is convenience function for opening the file called name that is
// compressed in z for reading.
func openFromZIP(z *zip.Reader, name string) (io.ReadCloser, error) {
for _, f := range z.File {
if f.Name == name {
return f.Open()
}
}
return nil, fmt.Errorf("No such file in archive: %s", name)
}
// ReadZipFrom read zip file from io.Reader, zip file must contain only one shape file
func ReadZipFrom(r io.Reader) (*ZipReader, error) {
zipBytes, err := io.ReadAll(r)
if err != nil {
return nil, err
}
reader, err := zip.NewReader(bytes.NewReader(zipBytes), int64(len(zipBytes)))
if err != nil {
return nil, err
}
zr := &ZipReader{
z: reader,
}
shapeFiles := shapesInZip(reader)
if len(shapeFiles) == 0 {
return nil, fmt.Errorf("archive does not contain a .shp file")
}
if len(shapeFiles) > 1 {
return nil, fmt.Errorf("archive does contain multiple .shp files")
}
shp, err := openFromZIP(zr.z, shapeFiles[0].Name)
if err != nil {
return nil, err
}
/* Note: not used
withoutExt := strings.TrimSuffix(shapeFiles[0].Name, ".shp")
// dbf is optional, so no error checking here
dbf, _ := openFromZIP(zr.z, withoutExt+".dbf")*/
zr.sr = SequentialReaderFromExt(shp /*, dbf*/)
return zr, nil
}
func shapesInZip(z *zip.Reader) []*zip.File {
var shapeFiles []*zip.File
for _, f := range z.File {
if strings.HasSuffix(f.Name, ".shp") {
shapeFiles = append(shapeFiles, f)
}
}
return shapeFiles
}
// Close closes the ZipReader and frees the allocated resources.
func (zr *ZipReader) Close() error {
err := zr.sr.Close()
if err != nil {
return err
}
return nil
}
// Next reads the next shape in the shapefile and the next row in the DBF. Call
// Shape() and Attribute() to access the values.
func (zr *ZipReader) Next() bool {
return zr.sr.Next()
}
// Shape returns the shape that was last read as well as the current index.
func (zr *ZipReader) Shape() (int, Shape) {
return zr.sr.Shape()
}
/* Note: not used
// Attribute returns the n-th field of the last row that was read. If there
// were any errors before, the empty string is returned.
func (zr *ZipReader) Attribute(n int) string {
return zr.sr.Attribute(n)
}
// Fields returns a slice of Fields that are present in the
// DBF table.
func (zr *ZipReader) Fields() []Field {
return zr.sr.Fields()
}*/
// Err returns the last non-EOF error that was encountered by this ZipReader.
func (zr *ZipReader) Err() error {
return zr.sr.Err()
}