go文件操作实践[读写zip tar xlsx文件]

这篇我接着实践zip,tar和xlsx文件的读写操作。简单介绍一下 tar吧:

tar 是一种打包格式,但不对文件进行压缩,所以打包后的文档一般远远大于 zip 和 tar.gz,因为不需要压缩的原因,所以打包的速度是非常快的,打包时 CPU 占用率也很低。

tar 的目的在于方便文件的管理,比如在我们的生活中,有很多小物品分散在房间的各个角落,为了方便整洁可以将这些零散的物品整理进一个箱子中,而 tar 的功能就类似这样。

创建 tar 归档文件与创建 .zip 归档文件非常类似,主要不同点在于我们将所有数据都写入相同的 writer 中,并且在写入文件的数据之前必须写入完整的头部,而非仅仅是一个文件名。

tar 打包实现原理如下:

创建一个文件 x.tar,然后向 x.tar 写入 tar 头部信息;

打开要被 tar 的文件,向 x.tar 写入头部信息,然后向 x.tar 写入文件信息;

当有多个文件需要被 tar 时,重复第二步直到所有文件都被写入到 x.tar 中;

关闭 x.tar,完成打包

package main
 
import (
    "archive/tar"
    "archive/zip"
    "bytes"
    "fmt"
    "io"
    "os"
    "strings"
 
    "github.com/tealeg/xlsx"
)
 
type Website struct {
    Name    string `xml:"name,attr"`
    Content []string
}
 
var info []Website
 
func init() {
    info = []Website{
        {"Golang.txt", []string{"http://c.biancheng.net/cplus/", "http://c.biancheng.net/linux_tutorial/"}},
        {"Java.txt", []string{"http://c.biancheng.net/socket/", "http://c.biancheng.net/python/"}},
    }
    /*
        列举了一些常用的 flag 文件处理参数:
        O_RDONLY:只读模式打开文件;
        O_WRONLY:只写模式打开文件;
        O_RDWR:读写模式打开文件;
        O_APPEND:写操作时将数据附加到文件尾部(追加);
        O_CREATE:如果不存在将创建一个新文件;
        O_EXCL:和 O_CREATE 配合使用,文件必须不存在,否则返回一个错误;
        O_SYNC:当进行一系列写操作时,每次都要等待上次的 I/O 操作完成再进行;
        O_TRUNC:如果可能,在打开时清空文件。
    */
}
 
// 检查文件或目录是否存在
// 如果由 filename 指定的文件或目录存在则返回 true,否则返回 false
func IsExist(filename string) bool {
    _, err := os.Stat(filename)
    return err == nil || os.IsExist(err)
}
func main() {
    WriteZip()
    ReadZip()
    WriteTar()
    ReadTar()
    WriteXlsx()
    ReadXlsx()
}
 
func WriteZip() {
    // 创建一个缓冲区用来保存压缩文件内容
    buf := new(bytes.Buffer)
    // 创建一个压缩文档
    w := zip.NewWriter(buf)
    // 创建文件 写入内容
    for _, file := range info {
        f, err := w.Create(file.Name)
        if err != nil {
            fmt.Printf("create zip fiel [%s] has error:%v \r\n", file.Name, err)
            return
        }
        for _, content := range file.Content {
            _, err = f.Write([]byte(content + "\r\n"))
            if err != nil {
                fmt.Printf("zip write content [%s] has error:%v\r\n", content, err)
            }
 
        }
 
    }
    // 关闭压缩文档
    err := w.Close()
    if err != nil {
        fmt.Printf("zip close has error:%v\r\n", err)
    }
    // 将压缩文档内容写入文件
    path := "./file.zip"
    if IsExist(path) {
        os.Remove(path)
    }
    f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0666)
    defer f.Close()
    if err != nil {
        fmt.Printf("zip create has error:%v\r\n", err)
    }
    buf.WriteTo(f)
    fmt.Println("zip create done")
}
 
func ReadZip() {
    path := "./file.zip"
    if !IsExist(path) {
        fmt.Printf("zip  file [%s] not exist\r\n", path)
        return
    }
    // 打开一个zip格式文件
    r, err := zip.OpenReader(path)
    if err != nil {
        fmt.Printf("zip read[OpenReader] has error:%v\r\n", err)
        return
    }
    defer r.Close()
    // 迭代压缩文件中的文件,打印出文件中的内容
    for _, f := range r.File {
        fmt.Printf("ReadZip open file: %s\n", f.Name)
        rc, err := f.Open()
        if err != nil {
            fmt.Printf(err.Error())
        }
        _, err = io.CopyN(os.Stdout, rc, int64(f.UncompressedSize64))
        if err != nil {
            fmt.Printf(err.Error())
        }
        rc.Close()
    }
}
 
/*
tar 打包实现原理如下:
创建一个文件 x.tar,然后向 x.tar 写入 tar 头部信息;
打开要被 tar 的文件,向 x.tar 写入头部信息,然后向 x.tar 写入文件信息;
当有多个文件需要被 tar 时,重复第二步直到所有文件都被写入到 x.tar 中;
关闭 x.tar,完成打包。
*/
func WriteTar() {
    path := "./output.tar"
    if IsExist(path) {
        os.Remove(path)
    }
    f, err := os.Create(path) //创建一个 tar 文件
    if err != nil {
        fmt.Printf("create tar has error %v\r\n", err)
        return
    }
    defer f.Close()
    tw := tar.NewWriter(f)
    defer tw.Close()
 
    for _, file := range info {
        //preare file
        f, err := os.Create(file.Name)
 
        if err != nil {
            fmt.Printf("create tar fiel [%s] has error:%v \r\n", file.Name, err)
            return
        }
        for _, content := range file.Content {
            _, err = f.Write([]byte(content + "\r\n"))
            if err != nil {
                fmt.Printf("tar write content [%s] has error:%v\r\n", content, err)
            }
 
        }
        f.Close()
        ///
        fileInfo, _ := os.Stat("./" + file.Name)
        hdr, err := tar.FileInfoHeader(fileInfo, "")
        if err != nil {
            fmt.Println(err)
        }
        err = tw.WriteHeader(hdr) //写入头文件信息
        if err != nil {
            fmt.Println(err)
        }
        f1, err := os.Open("./" + file.Name)
        if err != nil {
            fmt.Println(err)
            return
        }
        m, err := io.Copy(tw, f1) //将main.exe文件中的信息写入压缩包中
        if err != nil {
            fmt.Println(err)
        }
        fmt.Println(m)
    }
    fmt.Println("tar wirte done")
 
}
 
func ReadTar() {
    path := "./output.tar"
    if !IsExist(path) {
        fmt.Printf("tar  file [%s] not exist\r\n", path)
        return
    }
    f, err := os.Open(path)
    if err != nil {
        fmt.Println("文件打开失败", err)
        return
    }
    defer f.Close()
    r := tar.NewReader(f)
    for hdr, err := r.Next(); err != io.EOF; hdr, err = r.Next() {
        if err != nil {
            fmt.Println(err)
            return
        }
        fileinfo := hdr.FileInfo()
        fmt.Println(fileinfo.Name())
        /*
            f, err := os.Create("123" + fileinfo.Name())
            if err != nil {
                fmt.Println(err)
            }
            defer f.Close()
        */
        _, err = io.Copy(os.Stdout, r)
        if err != nil {
            fmt.Println(err)
        }
    }
}
 
func WriteXlsx() {
    path := "./info.xlsx"
    if IsExist(path) {
        os.Remove(path)
    }
    xlsxfile := xlsx.NewFile()
    ///创建sheet 写入数据
    for _, file := range info {
        fileName := strings.Replace(file.Name, ".txt", "", 1)
        sheet, err := xlsxfile.AddSheet(fileName)
        if err != nil {
            fmt.Printf("xlsx create sheet [%s] has error %v\r\n", fileName, err)
            continue
        }
        row := sheet.AddRow()
        row.SetHeightCM(1)
        cell := row.AddCell()
        cell.Value = "Content"
        for _, content := range file.Content {
            addRow := sheet.AddRow()
            addCell := addRow.AddCell()
            addCell.Value = content
        }
    }
    err := xlsxfile.Save(path)
    if err != nil {
        fmt.Printf("xlsx save has error:%v\r\n", err)
    }
    fmt.Println("write xlsx done")
}
 
func ReadXlsx() {
    path := "./info.xlsx"
    if !IsExist(path) {
        return
    }
    // 读取文件内容
    xlFile, err := xlsx.OpenFile(path)
    if err != nil {
        fmt.Printf("read xlsx has error %v\r\n", err)
    }
    for name, sheet := range xlFile.Sheet {
        fmt.Println(name)
        for rowindex, row := range sheet.Rows {
            for cellindex, cell := range row.Cells {
                fmt.Printf("sheet [%s] %d rows %d cell=%s\r\n", name, rowindex, cellindex, cell.Value)
            }
        }
    }
    fmt.Println("read xlsx done")
}