Comment string
}
+type ReadCloser struct {
+ f *os.File
+ Reader
+}
+
type File struct {
FileHeader
zipr io.ReaderAt
return f.Flags&0x8 != 0
}
-// OpenReader will open the Zip file specified by name and return a Reader.
-func OpenReader(name string) (*Reader, os.Error) {
+// OpenReader will open the Zip file specified by name and return a ReaderCloser.
+func OpenReader(name string) (*ReadCloser, os.Error) {
f, err := os.Open(name)
if err != nil {
return nil, err
}
fi, err := f.Stat()
if err != nil {
+ f.Close()
+ return nil, err
+ }
+ r := new(ReadCloser)
+ if err := r.init(f, fi.Size); err != nil {
+ f.Close()
return nil, err
}
- return NewReader(f, fi.Size)
+ return r, nil
}
// NewReader returns a new Reader reading from r, which is assumed to
// have the given size in bytes.
func NewReader(r io.ReaderAt, size int64) (*Reader, os.Error) {
- end, err := readDirectoryEnd(r, size)
- if err != nil {
+ zr := new(Reader)
+ if err := zr.init(r, size); err != nil {
return nil, err
}
- z := &Reader{
- r: r,
- File: make([]*File, end.directoryRecords),
- Comment: end.comment,
+ return zr, nil
+}
+
+func (z *Reader) init(r io.ReaderAt, size int64) os.Error {
+ end, err := readDirectoryEnd(r, size)
+ if err != nil {
+ return err
}
+ z.r = r
+ z.File = make([]*File, end.directoryRecords)
+ z.Comment = end.comment
rs := io.NewSectionReader(r, 0, size)
if _, err = rs.Seek(int64(end.directoryOffset), os.SEEK_SET); err != nil {
- return nil, err
+ return err
}
buf := bufio.NewReader(rs)
for i := range z.File {
z.File[i] = &File{zipr: r, zipsize: size}
if err := readDirectoryHeader(z.File[i], buf); err != nil {
- return nil, err
+ return err
}
}
- return z, nil
+ return nil
+}
+
+// Close closes the Zip file, rendering it unusable for I/O.
+func (rc *ReadCloser) Close() os.Error {
+ return rc.f.Close()
}
// Open returns a ReadCloser that provides access to the File's contents.