-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathstream_writer.go
131 lines (111 loc) · 2.66 KB
/
stream_writer.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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (c) 2017 Andrey Gayvoronsky <[email protected]>
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package ooxml
import (
"archive/zip"
"bytes"
"encoding/xml"
"io"
"io/ioutil"
"os"
"path"
)
//StreamFileWriterFinalizer is callback that will be called to do final processing before closing stream
type StreamFileWriterFinalizer func() error
//StreamFileWriter is stream writer for *zip.File
type StreamFileWriter struct {
*xml.Encoder
target interface{}
writer *zip.Writer
finalizer StreamFileWriterFinalizer
}
var _ io.Closer = (*StreamFileWriter)(nil)
//NewStreamFileWriter returns a StreamFileWriter for fileName
func NewStreamFileWriter(f string, memory bool, finalizer StreamFileWriterFinalizer) (*StreamFileWriter, error) {
var writer *zip.Writer
var target interface{}
if memory {
//stream to memory
buf := bytes.NewBuffer(nil)
writer = zip.NewWriter(buf)
target = buf
} else {
//stream to disk
tmpFile, err := ioutil.TempFile("", path.Base(f))
if err != nil {
return nil, err
}
writer = zip.NewWriter(tmpFile)
target = tmpFile
}
zipFile, err := writer.Create(f)
if err != nil {
return nil, err
}
_, err = zipFile.Write([]byte(xml.Header))
if err != nil {
return nil, err
}
enc := xml.NewEncoder(zipFile)
return &StreamFileWriter{
enc,
target,
writer,
finalizer,
}, nil
}
//Close previously allocated resources for writing
func (s *StreamFileWriter) Close() error {
if s.writer != nil {
//call finalizer, if required
if s.finalizer != nil {
if err := s.finalizer(); err != nil {
return err
}
}
//flush zipper
if err := s.Flush(); err != nil {
return err
}
//close writer
var writer io.Closer
writer, s.writer = s.writer, nil
return writer.Close()
}
return nil
}
//Save current state of stream to *zip.Writer
func (s *StreamFileWriter) Save(to *zip.Writer) error {
if err := s.Close(); err != nil {
return err
}
if buf, ok := s.target.(*bytes.Buffer); ok {
//stored in memory
readerAt := bytes.NewReader(buf.Bytes())
if zipReader, err := zip.NewReader(readerAt, int64(readerAt.Len())); err != nil {
return err
} else {
zipFile := zipReader.File[0]
if err := CopyZipFile(zipFile, to); err != nil {
return err
}
}
} else if file, ok := s.target.(*os.File); ok {
//stored at disk
if zipReader, err := zip.OpenReader(file.Name()); err != nil {
return err
} else {
zipFile := zipReader.File[0]
if err := CopyZipFile(zipFile, to); err != nil {
return err
}
if err = zipReader.Close(); err != nil {
return err
}
os.Remove(file.Name())
}
}
s.target = nil
return nil
}