-
Notifications
You must be signed in to change notification settings - Fork 0
/
第 12.01.01、archive_tar 包
206 lines (151 loc) · 5.58 KB
/
第 12.01.01、archive_tar 包
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
总览
tar 包实现了读写 tar 存档
它目标在于囊括大部分变种,包括 那些被 GNU 和 BSD tar 产生的存档
参考:
http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5
http://www.gnu.org/software/tar/manual/html_node/Standard.html
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html
EG.
// 创建一个缓存来写入我们的存档
buf := new(bytes.Buffer)
// 创建一个新的 tar 存档
tw := tar.NewWriter(buf)
// 将一些文件写入存档中
var files = []struct {
Name, Body string
}{
{"readme.txt", "This archive contains some text files."},
{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
{"todo.txt", "Get animal handling license."},
}
for _, file := range files {
hdr := &tar.Header{
Name: file.Name,
Mode: 0600,
Size: int64(len(file.Body)),
}
if err := tw.WriteHeader(hdr); err != nil {
log.Fatalln(err)
}
if _, err := tw.Write([]byte(file.Body)); err != nil {
log.Fatalln(err)
}
}
// 保证在调用 Close 时检查错误
if err := tw.Close(); err != nil {
log.Fatalln(err)
}
// 打开 tar 存档读来读取
r := bytes.NewReader(buf.Bytes())
tr := tar.NewReader(r)
// 逐一读取存档中的文件
for {
hdr, err := tr.Next()
if err == io.EOF {
// end of tar archive
break
}
if err != nil {
log.Fatalln(err)
}
fmt.Printf("Contents of %s:\n", hdr.Name)
if _, err := io.Copy(os.Stdout, tr); err != nil {
log.Fatalln(err)
}
fmt.Println()
}
常量
头数据类型 flag
const (
TypeReg = '0' // 普通文件
TypeRegA = '\x00' // 普通文件
TypeLink = '1' // 硬链接
TypeSymlink = '2' // 符号链接
TypeChar = '3' // 字符设备节点
TypeBlock = '4' // 块设备节点
TypeDir = '5' // 目录
TypeFifo = '6' // 先进先出节点
TypeCont = '7' // 保留
TypeXHeader = 'x' // 扩展头数据
TypeXGlobalHeader = 'g' // 全局扩展头数据
TypeGNULongName = 'L' // 下个文件具有长文件名
TypeGNULongLink = 'K' // 下个符号链接指向的文件具有长文件名
TypeGNUSparse = 'S' // 稀疏文件
)
变量
var (
ErrWriteTooLong = errors.New("archive/tar: write too long")
ErrFieldTooLong = errors.New("archive/tar: header field too long")
ErrWriteAfterClose = errors.New("archive/tar: write after close")
)
var (
ErrHeader = errors.New("archive/tar: invalid tar header")
)
Header struct 类型
一个 Header 表示了在一个 tar 存档中的单独的头数据
一些字段可能并不会被填充
type Header struct {
Name string // 头数据文件条目的名称
Mode int64 // 权限和 mode bit
Uid int // 拥有者的 uid
Gid int // 拥有者的 gid
Size int64 // 字节为单位的长度
ModTime time.Time // 修改时间
Typeflag byte // 头数据条目的类型
Linkname string // 链接的目标名
Uname string // 拥有者的名称
Gname string // 拥有者的组名称
Devmajor int64 // 字符设备或者块设备的主编号
Devminor int64 // 字符设备或者块设备的次编号
AccessTime time.Time // 读取时间
ChangeTime time.Time // 状态改变时间
Xattrs map[string]string
}
FileInfoHeader(fi os.FileInfo, link string) (*Header, error)
从 fi 中创建一个部分填充的 Header
若 fi 描述了一个符号链接,本函数将把链接记录链接目标
若 fi 描述了了一个目录,则一个斜线将附加在名称后面
因为 os.FileInfo 的 Name 方法仅会返回它所描述的文件的 base name,
可能需要修改返回头数据的 Name 字段来提供文件的完整路径
(h *Header) FileInfo() os.FileInfo
为 Header 返回一个 os.FileInfo
Reader struct 类型
一个 Reader 提供了顺序读取 tar 存档的内容的方法
一个 tar 存档包含一系列文件
Next 方法将读取头移动至下一个存档(包含第一个),
接着它就可以当作一个 io.Reader 来读取文件数据
type Reader struct {
// 包含过滤或未导出的字段
}
NewReader(r io.Reader) *Reader
新建一个 Reader,从 r 中读取
(tr *Reader) Next() (*Header, error)
移动读取头至 tar 存档的下一个条目
在输入的末端,io.EOF 被返回
(tr *Reader) Read(b []byte) (int, error)
从 tar 存档的当前条目中读取
当遇到条目尾部时,返回 0, io.EOF,直到下次调用 Next 一地哦那个至下个条目
在特殊的类型上调用 Read,无论 Header.Size 是怎么定义的,会直接返回 0, io.EOF,
这些类型包括,
TypeLink, TypeSymlink, TypeChar, TypeBlock, TypeDir, TypeFifo
Writer struct 类型
一个 Writer 提供了序列写入一个 POSIX.1 格式的 tar 存档
一个 tar 存档包含一系列文件
调用 WriteHeader 来开始一个新文件,然后调用 Write 来提供该文件的数据,
总共最多可以写入 hdr.Size 字节
Writer struct {
// 包含过滤或未导出的字段
}
NewWriter(w io.Writer) *Writer
创建一个新的 Writer,写入 w
(tw *Writer) Close() error
关闭一个 tar 存档,刷写任何未写入的数据至底层 writer
(tw *Writer) Flush() error
完成当前文件的写入(可选)
(tw *Writer) Write(b []byte) (n int, err error)
写入 tar 存档当前条目
若在 WriteHeader 之后,写入的数据量大于 hdr.Size 字节,则返回错误 ErrWriteTooLong
(tw *Writer) WriteHeader(hdr *Header) error
写入 hdr,并准备接受文件内容
若并非第一个头数据,则 WriteHeader 调用 Flush
在 Close 之后调用本方法,将返回 ErrWriteAfterClose