如何压缩golang 压缩编译编译出的可执行文件大小

/articles/2331
如何选择web框架:
首先Golang语言开发web项目不一定非要框架,本身已经提供了Web开发需要的一切必要技术。当然如果想要ruby里面Rail那种高层次全栈式的MVC框架, Golang里面暂时没有,但是不是所有人都喜欢这种复杂的框架。Golang里面一些应用层面的技术需要自己去组装,比如session,cache,
log等等. 可选择的web框架有martini, goji等,都是轻量级的。
Golang的web项目中的keepalive
关于keepalive, 是比较复杂的, 注意以下几点:
http1.1 默认支持keepalive, 但是不同浏览器对keepalive都有个超时时间, 比如firefox:默认超时时间115秒,
不同浏览器不一样;
Nginx默认超时时间75秒;
golang默认超时时间是无限的, 要控制golang中的keepalive可以设置读写超时, 举例如下:
server := &http.Server{
framework,
ReadTimeout:
32 * time.Second,
WriteTimeout:
32 * time.Second,
MaxHeaderBytes: 1 && 20,
server.ListenAndServe()
</go-sql-driver/mysql使用主意事项:
这是使用率极高的一个库, 在用它进行事务处理的情况下, 要注意一个问题, 由于它内部使用了连接池, 使用事务的时候如果没有Rollback或者Commit, 这个取出的连接就不会放回到池子里面, 导致的后果就是连接数过多, 所以使用事务的时候要注意正确地使用。
</garyburd/redigo/redis使用注意事项:
这也是一个使用率极高的库, 同样需要注意,它是支持连接池的, 所以最好使用连接池, 正确的用法是这样的:
func initRedis(host string) *redis.Pool {
return &redis.Pool{
MaxIdle: 64,
IdleTimeout: 60 * time.Second,
TestOnBorrow: func(c redis.Conn, t time.Time) error {
_, err := c.Do(&PING&)
return err
Dial: func() (redis.Conn, error) {
c, err := redis.Dial(&tcp&, host)
if err != nil {
return nil, err
_, err = c.Do(&SELECT&, config.RedisDb)
return c, err
另外使用的时候也要把连接放回到池子里面, 否则也会导致连接数居高不下。用完之后调用rd.Close(), 这个Close并不是真的关闭连接,而是放回到池子里面。
如何全局捕获panic级别错误:
defer func() {
if err := recover(); err != nil {
lib.Log4e(&Panic error&, err)
1. 需要注意的是捕获到pannic之后, 程序的执行点不会回到触发pannic的地方,需要程序再次执行, 一些框架支持这一点,比如martini里面有c.Next()。
2. 如果程序main里启动了多个goroutine, 每个goroutine里面都应该捕获pannic级别错误, 否则某个goroutine触发panic级别错误之后,整个程序退出, 这是非常不合理的。
最容易出错的地方:
使用指针,但是没有判断指针是否为nil, Golang中array, struct是&#20540;语义, slice,map, chanel是引用传递。
如何获取程序执行栈:
defer func() {
if err := recover(); err != nil {
var st = func(all bool) string {
// Reserve 1K buffer at first
buf := make([]byte, 512)
size := runtime.Stack(buf, all)
// The size of the buffer may be not enough to hold the stacktrace,
// so double the buffer size
if size == len(buf) {
buf = make([]byte, len(buf)&&1)
return string(buf)
lib.Log4e(&panic:& + toString(err) + &\nstack:& + st(false))
具体方法就是调用 runtime.Stack。
如何执行异步任务:
比如用户提交email, 给用户发邮件, 发邮件的步骤是比较耗时的, 这个场景适合可以使用异步任务:
result := global.ResponseResult{ErrorCode: 0, ErrorMsg: &GetInviteCode success!&}
render.JSON(200, &result)
go func() {
type data struct {
Url string
name := &beta_test&
subject := &We would like to invite you to the private beta of Screenshot.&
url := config.HttpProto + r.Host + &/user/register/& + *uniqid
html := ParseMailTpl(&name, &beta_test_mail_content, data{url})
e := this.SendMail(mail, subject, html.String())
if e != nil {
lib.Log4w(&GetInviteCode, SendMail faild&, mail, uniqid, e)
lib.Log4w(&GetInviteCode, SendMail success&, mail, uniqid)
思路是启动一个goroutine执行异步的操作, 当前goroutine继续向下执行。特别需要注意的是新启动的个goroutine如果对全局变量有读写操作的话,需要注意避免发生竞态条件, 可能需要加锁。
如何使用定时器:
通常情况下, 写一些定时任务需要用到crontab, 在Golang里面是不需要的, 提供了非常好用的定时器。举例如下:
func Init() {
ticker := time.NewTicker(30 * time.Minute)
case c := &-global.TaskCmdChannel:
switch *c {
case c := &-global.TaskImageMessageChannel:
m := new(model.TaskModel)
m.CreateImageMessage(c)
case &-ticker.C:
m := new(model.TaskModel)
m.CleanUserExpiredSessionKey()
多goroutine执行如果避免发生竞态条件:
Data races are among the most common and hardest to debug types of bugs in concurrent systems. A data race occurs when two goroutines
access the same variable concurrently and at least one of the accesses is a write. See the The Go Memory Model for details.
官方相关说明:
多goroutine执行,访问全局的变量,比如map,可能会发生竞态条件, 如何检查呢?首先在编译的时候指定 -race参数,指定这个参数之后,编译出来的程序体积大一倍以上, 另外cpu,内存消耗比较高,适合测试环境, 但是发生竞态条件的时候会panic,有详细的错误信息。go内置的数据结构array,slice,
map都不是线程安全的。
没有设置runtime.GOMAXPROCS会有竞态条件的问题吗?
答案是没有, 因为没有设置runtime.GOMAXPROCS的情况下, 所有的goroutine都是在一个原生的系统thread里面执行, 自然不会有竞态条件。
如何充分利用CPU多核:
runtime.GOMAXPROCS(runtime.NumCPU() * 2)
以上是根据经验得出的比较合理的设置。
解决并发情况下的竞态条件的方法:
1. &channel, 但是channel并不能解决所有的情况,channel的底层实现里面也有用到锁, 某些情况下channel还不一定有锁高效, 另外channel是Golang里面最强大也最难掌握的一个东西, 如果发生阻塞不好调试。
2. 加锁, 需要注意高并发情况下,锁竞争也是影响性能的一个重要因素, 使用读写锁,在很多情况下更高效, 举例如下:
var mu sync.RWMutex
mu.RLock()
defer mu.RUnlock()
conns := h.all_connections[img_id]
for _, c := range conns {
if c == nil /*|| c.uid == uid */ {
case c.send &- []byte(message):
h.conn_unregister(c)
使用锁有个主意的地方是避免死锁,比如循环加锁。
3. 原子操作(CAS), Golang的atomic包对原子操作提供支持,Golang里面锁的实现也是用的原子操作。
获取程序绝对路径:
&&&Golang编译出来之后是独立的可执行程序, 不过很多时候需要读取配置,由于执行目录有时候不在程序所在目录,路径的问题经常让人头疼,正确获取绝对路径非常重要, 方法如下:
func GetCurrPath() string {
file, _ := exec.LookPath(os.Args[0])
path, _ := filepath.Abs(file)
index := strings.LastIndex(path, string(os.PathSeparator))
ret := path[:index]
return ret
Golang函数默认参数:
&&&大家都知道Golang是一门简洁的语言, 不支持函数默认参数. 这个特性有些情况下确实是有用的,如果不支持,往往需要重写函数,或者多写一个函数。其实这个问题非常好解决, 举例如下:
func (this *ImageModel) GetImageListCount(project_id int64,
paramter_optional ...int) int {
expire_time := 600
if len(paramter_optional) & 0 {
expire_time = paramter_optional[0]
性能监控:
go func() {
profServeMux := http.NewServeMux()
profServeMux.HandleFunc(&/debug/pprof/&, pprof.Index)
profServeMux.HandleFunc(&/debug/pprof/cmdline&, pprof.Cmdline)
profServeMux.HandleFunc(&/debug/pprof/profile&, pprof.Profile)
profServeMux.HandleFunc(&/debug/pprof/symbol&, pprof.Symbol)
err := http.ListenAndServe(&:7789&, profServeMux)
if err != nil {
panic(err)
接下来就可以使用go tool pprof分析。
如何进行程序调试:
&&&对于调试,每个人理解不一样, 如果要调试程序功能, 重新编译即可, Golang的编译速度极快。如果在开发的时候调试程序逻辑, 一般用log即可, Golang里面最好用的log库是log4go, 支持log级别。如果要进行断点调试, GoEclipse之类的是支持的,
依赖Mingw和GDB, 我个人不习惯这种调试方法。
守护进程(daemon)
下面给出完整的真正可用的例子:
package main
func daemon(nochdir, noclose int) int {
var ret, ret2 uintptr
var err syscall.Errno
darwin := runtime.GOOS == &darwin&
// already a daemon
if syscall.Getppid() == 1 {
// fork off the parent process
ret, ret2, err = syscall.RawSyscall(syscall.SYS_FORK, 0, 0, 0)
if err != 0 {
// failure
if ret2 & 0 {
os.Exit(-1)
// handle exception for darwin
if darwin && ret2 == 1 {
// if we got a good PID, then we call exit the parent process.
if ret & 0 {
os.Exit(0)
/* Change the file mode mask */
_ = syscall.Umask(0)
// create a new SID for the child process
s_ret, s_errno := syscall.Setsid()
if s_errno != nil {
log.Printf(&Error: syscall.Setsid errno: %d&, s_errno)
if s_ret & 0 {
if nochdir == 0 {
os.Chdir(&/&)
if noclose == 0 {
f, e := os.OpenFile(&/dev/null&, os.O_RDWR, 0)
if e == nil {
fd := f.Fd()
syscall.Dup2(int(fd), int(os.Stdin.Fd()))
syscall.Dup2(int(fd), int(os.Stdout.Fd()))
syscall.Dup2(int(fd), int(os.Stderr.Fd()))
func main() {
daemon(0, 1)
fmt.Println(&hello&)
time.Sleep(1 * time.Second)
进程管理:
个人比较喜欢用supervisord来进行进程管理,支持进程自动重启,supervisord是一个python开发的工具, 用pip安装即可。
代码热更新:
代码热更新一直是解释型语言比较擅长的,Golang里面不是做不到,只是稍微麻烦一些, 就看必要性有多大。如果是线上在线人数很多, 业务非常重要的场景, 还是有必要, 一般情况下没有必要。
因为配置文件一般是个json或者ini&#26684;式的文件,是不需要编译的, 在线更新配置还是相对比较容易的, 思路就是使用信号, 比如SIGUSER2, 程序在信号处理函数中重新加载配置即可。
热更新代码.
目前网上有多种第三方库, 实现方法大同小异。先编译代码(这一步可以使用fsnotify做到监控代码变化,自动编译),关键是下一步graceful restart进程,实现方法可参考:
&&也是创建子进程,杀死父进程的方法。
条件编译时一个非常有用的特性,一般一个项目编译出一个可执行文件,但是有些情况需要编译成多个可执行文件,执行不同的逻辑,这比通过命令行参数执行不同的逻辑更清晰.比如这样一个场景,一个web项目,是常驻进程的, 但是有时候需要执行一些程序步骤初始化数据库,导入数据,执行一个特定的一次性的任务等。假如项目中有一个main.go,
里面定义了一个main函数,同目录下有一个task.go函数,里面也定义了一个main函数,正常情况下这是无法编译通过的, 会提示“main redeclared”。解决办法是使用go build 的-tags参数。步骤如下(以windows为例说明):
1.在main.go头部加上// &#43;build main
2. 在task.go头部加上// &#43;build task
3. 编译住程序:go build -tags 'main'
4. 编译task:go build -tags 'task' -o task.exe
官方说明:
Build Constraints
A build constraint is a line comment beginning with the directive &&#43;build that lists the conditions under which a file should be included
in the package. Constraints may appear in any kind of source file (not just Go), but they must appear near the top of the file, preceded only by blank lines and other line comments.
To distinguish build constraints from package documentation, a series of build constraints must be followed by a blank line.
如果将项目有关资源文件打包进主程序:
使用go generate命令,参考godoc的实现。
与C/C&#43;&#43; 交互
1.Cgo,Cgo支持Golang和C/C&#43;&#43;混编,
在Golang里面使用pthread,libuv之类的都不难,github上也有相关开源代码;
2.Swig, 很多库都用Swig实现了Golang的绑定,Swig也可以反向回调Golang代码。
3. syscall包, 该包让你以Golang的方式进行系统编程,不需要再使用C/C&#43;&#43;,
syscall提供了很多系统接口,比如epoll,原始socket套接字编程接口等。
&&&&近几年最热门的技术之一Docker是用Golang开发的, 已经有相关的书出版, 对系统运维,云计算感兴趣的可以了解。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:919次
排名:千里之外
(1)(1)(1)(2)(5)(1)(1)(2)GO语言实现批量压缩图片和水印
投稿:hebedich
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了GO语言实现批量压缩图片和水印,主要用到了/nfnt/resize这个第三方库,仅仅支持JPG图片格式,有相同需求的小伙伴参考下吧。
前段时间想做个图片站,就用手机照了很多相片,但是要一个个用PS去压缩修改尺寸太麻烦了。最后想到了用golang去实现,算是边学边练吧。其中用到了/nfnt/resize这个第三方库,仅仅支持JPG图片格式。
package main
&&& "/nfnt/resize"
&&& "image"
&&& "image/draw"
&&& "image/jpeg"
&&& "image/png"
&&& "io/ioutil"
&&& "math/rand"
&&& "runtime"
&&& "strconv"
&&& "strings"
&&& "time"
func main() {
&&& runtime.GOMAXPROCS(runtime.NumCPU())
&&& cmd("data/")
&&& fmt.Println("OK!")
// 执行操作
func cmd(path string) {
&&& files, _ := ioutil.ReadDir(path)
&&& for _, file := range files {
&&&&&&& if file.IsDir() {
&&&&&&&&&&& fmt.Println("目录" + file.Name())
&&&&&&&&&&& cmd(path + file.Name() + "/")
&&&&&&& } else {
&&&&&&&&&&& if strings.Contains(strings.ToLower(file.Name()), ".jpg") {
&&&&&&&&&&&&&&& // 随机名称
&&&&&&&&&&&&&&& to := path + random_name() + ".jpg"
&&&&&&&&&&&&&&& origin := path + file.Name()
&&&&&&&&&&&&&&& fmt.Println("正在处理" + origin + "&&&" + to)
&&&&&&&&&&&&&&& cmd_resize(origin, 2048, 0, to)
&&&&&&&&&&&&&&& defer os.Remove(origin)
&&&&&&&&&&& }
// 改变大小
func cmd_resize(file string, width uint, height uint, to string) {
&&& // 打开图片并解码
&&& file_origin, _ := os.Open(file)
&&& origin, _ := jpeg.Decode(file_origin)
&&& defer file_origin.Close()
&&& canvas := resize.Resize(width, height, origin, resize.Lanczos3)
&&& file_out, err := os.Create(to)
&&& if err != nil {
&&&&&&& log.Fatal(err)
&&& defer file_out.Close()
&&& jpeg.Encode(file_out, canvas, &jpeg.Options{80})
&&& // cmd_watermark(to, strings.Replace(to, ".jpg", "@big.jpg", 1))
&&& cmd_thumbnail(to, 480, 360, strings.Replace(to, ".jpg", "@small.jpg", 1))
func cmd_thumbnail(file string, width uint, height uint, to string) {
&&& // 打开图片并解码
&&& file_origin, _ := os.Open(file)
&&& origin, _ := jpeg.Decode(file_origin)
&&& defer file_origin.Close()
&&& canvas := resize.Thumbnail(width, height, origin, resize.Lanczos3)
&&& file_out, err := os.Create(to)
&&& if err != nil {
&&&&&&& log.Fatal(err)
&&& defer file_out.Close()
&&& jpeg.Encode(file_out, canvas, &jpeg.Options{80})
func cmd_watermark(file string, to string) {
&&& // 打开图片并解码
&&& file_origin, _ := os.Open(file)
&&& origin, _ := jpeg.Decode(file_origin)
&&& defer file_origin.Close()
&&& // 打开水印图并解码
&&& file_watermark, _ := os.Open("watermark.png")
&&& watermark, _ := png.Decode(file_watermark)
&&& defer file_watermark.Close()
&&& //原始图界限
&&& origin_size := origin.Bounds()
&&& //创建新图层
&&& canvas := image.NewNRGBA(origin_size)
&&& // 贴原始图
&&& draw.Draw(canvas, origin_size, origin, image.ZP, draw.Src)
&&& // 贴水印图
&&& draw.Draw(canvas, watermark.Bounds().Add(image.Pt(30, 30)), watermark, image.ZP, draw.Over)
&&& //生成新图片
&&& create_image, _ := os.Create(to)
&&& jpeg.Encode(create_image, canvas, &jpeg.Options{95})
&&& defer create_image.Close()
// 随机生成文件名
func random_name() string {
&&& rand.Seed(time.Now().UnixNano())
&&& return strconv.Itoa(rand.Int())
以上就是本文所述的全部内容了,希望能够对大家熟练掌握go语言有所帮助。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具在的时候就习惯使用zlib进行压缩。 golang下同样使用zlib进行压缩解压缩。& zlib官方给出的方法很简单,这里权当一个补充.
zlib.NewWriter() 只能传递 []byte类型数据.&& NewWriterLevel 可以传递压缩的等级.
"compress/zlib"
func main() {
var in bytes.Buffer
b := []byte(`xiorui.cc`)
w := zlib.NewWriter(&in)
w.Write(b)
var out bytes.Buffer
r, _ := zlib.NewReader(&in)
io.Copy(&out, r)
fmt.Println(out.String())
import "compress/zlib"
func NewWriter
func NewWriter(w io.Writer) *Writer
读取压缩的数据
func NewReader
func NewReader(r io.Reader) (io.ReadCloser, error)
设置压缩等级,并压缩数据
func NewWriterLevel(w io.Writer, level int) (io.WriteCloser, os.Error)
下面是几个级别.
NoCompression = 0
BestCompression
DefaultCompression = -1
NoCompression
= flate.NoCompression
= flate.BestSpeed
BestCompression
= flate.BestCompression
DefaultCompression = flate.DefaultCompression
func (*Writer) Write
func (z *Writer) Write(p []byte) (n int, err error)
func (*Writer) Close
func (z *Writer) Close() error
Golang zlib压缩的效率和性能都还可以, 毕竟rsync也在用这个压缩算法。& 其实zlib和gzip对比,貌似用gzip的多一点。 比如nginx的gzip压缩. 以前看过国外一个帖子,是说zlib比gzip更适合那种速度跟压缩效果均衡的场景。golang zip 压缩,解压(含目录文件)
| Go语言中文网 | Golang中文社区 | Golang中国
<meta name="author" content="polaris ">
golang zip 压缩,解压(含目录文件)
golang zip 压缩,解压(含目录文件)
xiaofengshuyu
每天学习一点go src。
今天学习了zip包的简单使用,实现了含目录的压缩与解压。
写了两个方法,实现了压缩、解压。
package ziptest
&#34;archive/zip&#34;
&#34;io&#34;
&#34;os&#34;
&#34;strings&#34;
//压缩文件
//files 文件数组,可以是不同dir下的文件或者文件夹
//dest 压缩文件存放地址
func Compress(files []*os.File, dest string) error {
d, _ := os.Create(dest)
defer d.Close()
w := zip.NewWriter(d)
defer w.Close()
for _, file := range files {
err := compress(file, &#34;&#34;, w)
if err != nil {
return err
return nil
func compress(file *os.File, prefix string, zw *zip.Writer) error {
info, err := file.Stat()
if err != nil {
return err
if info.IsDir() {
prefix = prefix + &#34;/&#34; + info.Name()
fileInfos, err := file.Readdir(-1)
if err != nil {
return err
for _, fi := range fileInfos {
f, err := os.Open(file.Name() + &#34;/&#34; + fi.Name())
if err != nil {
return err
err = compress(f, prefix, zw)
if err != nil {
return err
header, err := zip.FileInfoHeader(info)
header.Name = prefix + &#34;/&#34; + header.Name
if err != nil {
return err
writer, err := zw.CreateHeader(header)
if err != nil {
return err
_, err = io.Copy(writer, file)
file.Close()
if err != nil {
return err
return nil
func DeCompress(zipFile, dest string) error {
reader, err := zip.OpenReader(zipFile)
if err != nil {
return err
defer reader.Close()
for _, file := range reader.File {
rc, err := file.Open()
if err != nil {
return err
defer rc.Close()
filename := dest + file.Name
err = os.MkdirAll(getDir(filename), 0755)
if err != nil {
return err
w, err := os.Create(filename)
if err != nil {
return err
defer w.Close()
_, err = io.Copy(w, rc)
if err != nil {
return err
rc.Close()
return nil
func getDir(path string) string {
return subString(path, 0, strings.LastIndex(path, &#34;/&#34;))
func subString(str string, start, end int) string {
rs := []rune(str)
length := len(rs)
if start & 0 || start & length {
panic(&#34;start is wrong&#34;)
if end & start || end & length {
panic(&#34;end is wrong&#34;)
return string(rs[start:end])
测试代码:
package ziptest
&#34;os&#34;
&#34;testing&#34;
func TestCompress(t *testing.T) {
f1, err := os.Open(&#34;/home/zzw/test_data/ziptest/gophercolor16x16.png&#34;)
if err != nil {
t.Fatal(err)
defer f1.Close()
f2, err := os.Open(&#34;/home/zzw/test_data/ziptest/readme.notzip&#34;)
if err != nil {
t.Fatal(err)
defer f2.Close()
f3, err := os.Open(&#34;/home/zzw/test_data&#34;)
if err != nil {
t.Fatal(err)
defer f3.Close()
var files = []*os.File{f1, f2, f3}
dest := &#34;/home/zzw/test_data/test.zip&#34;
err = Compress(files, dest)
if err != nil {
t.Fatal(err)
func TestDeCompress(t *testing.T) {
err := DeCompress(&#34;/home/zzw/test_data/test.zip&#34;, &#34;/home/zzw/test_data/de&#34;)
if err != nil {
t.Fatal(err)
支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
支持 @ 本站用户;支持表情(输入 : 提示),见
每天学习一点go src。
今天学习了zip包的简单使用,实现了含目录的压缩与解压。
写了两个方法,实现了压缩、解压。
package ziptest
&#34;archive/zip&#34;
&#34;io&#34;
&#34;os&#34;
&#34;strings&#34;
//压缩文件
//files 文件数组,可以是不同dir下的文件或者文件夹
//dest 压缩文件存放地址
func Compress(files []*os.File, dest string) error {
d, _ := os.Create(dest)
defer d.Close()
w := zip.NewWriter(d)
defer w.Close()
for _, file := range files {
err := compress(file, &#34;&#34;, w)
if err != nil {
return err
return nil
func compress(file *os.File, prefix string, zw *zip.Writer) error {
info, err := file.Stat()
if err != nil {
return err
if info.IsDir() {
prefix = prefix + &#34;/&#34; + info.Name()
fileInfos, err := file.Readdir(-1)
if err != nil {
return err
for _, fi := range fileInfos {
f, err := os.Open(file.Name() + &#34;/&#34; + fi.Name())
if err != nil {
return err
err = compress(f, prefix, zw)
if err != nil {
return err
header, err := zip.FileInfoHeader(info)
header.Name = prefix + &#34;/&#34; + header.Name
if err != nil {
return err
writer, err := zw.CreateHeader(header)
if err != nil {
return err
_, err = io.Copy(writer, file)
file.Close()
if err != nil {
return err
return nil
func DeCompress(zipFile, dest string) error {
reader, err := zip.OpenReader(zipFile)
if err != nil {
return err
defer reader.Close()
for _, file := range reader.File {
rc, err := file.Open()
if err != nil {
return err
defer rc.Close()
filename := dest + file.Name
err = os.MkdirAll(getDir(filename), 0755)
if err != nil {
return err
w, err := os.Create(filename)
if err != nil {
return err
defer w.Close()
_, err = io.Copy(w, rc)
if err != nil {
return err
rc.Close()
return nil
func getDir(path string) string {
return subString(path, 0, strings.LastIndex(path, &#34;/&#34;))
func subString(str string, start, end int) string {
rs := []rune(str)
length := len(rs)
if start & 0 || start & length {
panic(&#34;start is wrong&#34;)
if end & start || end & length {
panic(&#34;end is wrong&#34;)
return string(rs[start:end])
测试代码:
package ziptest
&#34;os&#34;
&#34;testing&#34;
func TestCompress(t *testing.T) {
f1, err := os.Open(&#34;/home/zzw/test_data/ziptest/gophercolor16x16.png&#34;)
if err != nil {
t.Fatal(err)
defer f1.Close()
f2, err := os.Open(&#34;/home/zzw/test_data/ziptest/readme.notzip&#34;)
if err != nil {
t.Fatal(err)
defer f2.Close()
f3, err := os.Open(&#34;/home/zzw/test_data&#34;)
if err != nil {
t.Fatal(err)
defer f3.Close()
var files = []*os.File{f1, f2, f3}
dest := &#34;/home/zzw/test_data/test.zip&#34;
err = Compress(files, dest)
if err != nil {
t.Fatal(err)
func TestDeCompress(t *testing.T) {
err := DeCompress(&#34;/home/zzw/test_data/test.zip&#34;, &#34;/home/zzw/test_data/de&#34;)
if err != nil {
t.Fatal(err)
记住登录状态
还不是会员

我要回帖

更多关于 java编译可执行文件 的文章

 

随机推荐