菩提香珊 發表於 2020-6-5 22:28:00

Go文件操作

<p></p><div class="toc"><div class="toc-container-header">目录</div><ul><li>示例1: 打开和关闭文件</li><li>示例2: 打开文件并读取内容</li><li>示例3: 一次性读取文件</li><li>示例4: 带缓冲的Reader读文件</li><li>示例5: 创建文件并写入内容</li><li>示例6: 写文件的四种方式</li><li>示例7: 把一个文件内容写入到另一个文件</li><li>示例8:使用bufio获取用户输入</li><li>示例9: 判断文件或目录是否存在</li><li>示例10: 拷贝文件、图片音视频</li><li>示例11: 遍历目录<ul><li>遍历目录</li><li>仅遍历目录,忽略文件</li></ul></li><li>示例12: 修改文件名</li><li>示例13:创建目录</li><li>示例14:删除文件</li></ul></div><p></p>
<p>对于文件,我们并不陌生,文件是数据源(保存数据的地方)的一种,比如大家经常使用的word文档,txt文件,Excel文件...等等都是文件。文件最主要的作用就是保存数据,它既可以保存一张图片,也可以保存视频,声音......<br>
文件在程序中是以流的形式来操作的。</p>
<p><img src="https://img2020.cnblogs.com/blog/720430/202006/720430-20200605222309306-1647050472.png" alt="" loading="lazy"></p>
<p><strong>流</strong>:数据在数据源(文件)和程序(内存)之间经历的路径<br>
输出流:数据从程序(内存)到数据源(文件)的路径<br>
输入流:数据从数据源(文件)到程序(内存)的路径<br>
输入与输出都是相对于内存而言的,从内存向外流就是输出,从外部向内存流就是输入</p>
<p>在Go中,我们操作文件的方法在os包中,会经常使用到os.File结构体 Go语言标准库文档</p>
<p><img src="https://img2020.cnblogs.com/blog/720430/202006/720430-20200605222403814-1175317630.png" alt="" loading="lazy"></p>
<p><img src="https://img2020.cnblogs.com/blog/720430/202006/720430-20200605222435222-1135705862.png" alt="" loading="lazy"></p>
<p><img src="https://img2020.cnblogs.com/blog/720430/202006/720430-20200605222524234-1665009916.png" alt="" loading="lazy"></p>
<h3 id="示例1-打开和关闭文件">示例1: 打开和关闭文件</h3>
<pre><code class="language-go">package main

import (
    "fmt"
    "os"
)

func main() {

    //打开文件(/Users/xxx/Go/src/file.txt)
    //概念说明:file的叫法
    //1.file 叫 file对象
    //2.file 叫 file指针
    //3.file 叫 file文件句柄
    file, err := os.Open("/Users/itbsl/Go/src/file.txt")
    if err != nil {
      fmt.Println("文件打开失败,原因是:", err)
      //os.Exit(0)
    }
    defer func() {
      //文件及时关闭
      err = file.Close()
      if err != nil {
            fmt.Println("文件关闭失败,原因是", err)
      }
    }()
}
</code></pre>
<h3 id="示例2-打开文件并读取内容">示例2: 打开文件并读取内容</h3>
<p>使用Read()函数按照字节读</p>
<pre><code class="language-go">package main

import (
        "fmt"
        "io"
        "os"
)

func main() {

        file, err := os.Open("./test.txt")
        if err != nil {
                fmt.Printf("open file failed, err:%v\n", err)
                return
        }
        defer func() {
                err = file.Close()
                if err != nil {
                        fmt.Printf("close file failed, err:%v\n", err)
                }
        }()

        var content []byte
        var tmp = make([]byte, 128)
        for {
                n, err := file.Read(tmp)
                //为什么是tmp[:n]而不是tmp[:]?
                //因为当读取到最后一行的内容长度不足tmp的长度的时候
                //新读取的内容只会覆盖前半部分上次读取到的tmp的内容,
                //后半部分还是上一次读取的内容,如果用tmp[:]就会导致
                //后半部分久内容又会被重新赋值一次,这其实是错误的
                content = append(content, tmp[:n]...)
                if err == io.EOF {//读到文件末尾
                        break
                }
        }
        fmt.Printf("读取出来的内容为:\n")
        fmt.Printf("%q\n", string(content))
}
</code></pre>
<h3 id="示例3-一次性读取文件">示例3: 一次性读取文件</h3>
<p>读取文件内容并显示在终端,将文件内容一次性读取到终端,适用于文件不大的情况。</p>
<pre><code class="language-go">package main

import (
    "fmt"
    "io/ioutil"
)

func main() {

    //打开文件,文件路径相对于GOPATH开始,或者写全路径(/Users/xxx/Go/src/file.txt)
    file, err := ioutil.ReadFile("src/file.txt")
    if err != nil {
      fmt.Println("文件打开失败,原因是:", err)
    }

    fmt.Printf("%s", string(file))
}
</code></pre>
<h3 id="示例4-带缓冲的reader读文件">示例4: 带缓冲的Reader读文件</h3>
<p>读取文件的内容并显示在终端(带缓冲区的方式),使用<code>os.Open</code>, <code>file.Close</code>,<code>bufio.NewReader</code>,<code>reader.ReadString</code>函数和方法。适合读取大文件<br>
1.使用ReadBytes方法<br>
代码1:</p>
<pre><code class="language-go">package main

import (
        "bufio"
        "fmt"
        "io"
        "log"
        "os"
)

func main() {

        file, err := os.Open("./test.txt")
        if err != nil {
                log.Fatalf("open file failed, err: %v\n", err)
        }
        defer func() {
                err = file.Close()
                if err != nil {
                        log.Fatalf("close file failed, err: %v\n", err)
                }
        }()

        //定义变量result用来存储读取结果
        var result string
        //创建一个带有缓冲区的reader
        reader := bufio.NewReader(file)
        for {
                buf, err := reader.ReadBytes('\n')
                if err != nil &amp;&amp; err == io.EOF { //EOF代表文件的末尾
                        //注意:为什么要判断err是否等于io.EOF?
                        //因为存在这种情况,文件有内容的最后那一行尾部没有换行
                        //当使用ReadBytes或者ReadString方法按照'\n'换行读取时,读到尾部没有换行的这种情况时就会报io.EOF错误
                        //此时buf是读取到了内容的,如果忽略掉了,那么最终的读取结果会少了最后一行的内容
                        result += string(buf)
                        break
                }
                result += string(buf)
        }
        fmt.Println(result)
}
</code></pre>
<p>代码2:</p>
<pre><code class="language-go">package main

import (
        "bufio"
        "fmt"
        "io"
        "log"
        "os"
)

func main() {

        file, err := os.Open("./test.txt")
        if err != nil {
                log.Fatalf("open file failed, err: %v\n", err)
        }
        defer func() {
                err = file.Close()
                if err != nil {
                        log.Fatalf("close file failed, err: %v\n", err)
                }
        }()

        //定义变量result用来存储读取结果
        var result string
        //创建一个带有缓冲区的reader
        reader := bufio.NewReader(file)
        for {
                buf, err := reader.ReadBytes('\n')
                if err != nil {
                        if err == io.EOF { //EOF代表文件的末尾
                        //注意:为什么要判断err是否等于io.EOF?
                        //因为存在这种情况,文件有内容的最后那一行尾部没有换行
                        //当使用ReadBytes或者ReadString方法按照'\n'换行读取时,读到尾部没有换行的这种情况时就会报io.EOF错误
                        //此时buf是读取到了内容的,如果忽略掉了,那么最终的读取结果会少了最后一行的内容
                                result += string(buf)
                                break
                        } else {
                                log.Fatalf("ReadBytes failed, err: %v\n", err)
                        }
                }
                result += string(buf)
        }
        fmt.Println(result)
}
</code></pre>
<p>2.ReadString方法</p>
<pre><code class="language-go">package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
)

func main() {

    //打开文件
    file, err := os.Open("./files/test.txt")
    if err != nil {
      fmt.Println("文件打开失败,原因是:", err)
      return
    }

    //当函数退出时,要及时的关闭file
    defer func() {
      //文件及时关闭
      err = file.Close()
      if err != nil {
            fmt.Println("文件关闭失败,原因是", err)
      }
    }()

    //创建一个 *Reader,是带缓冲的
    reader := bufio.NewReader(file)
    var result string
    //循环读取文件内容
    for {
      str, err := reader.ReadString('\n') //读到一个换行就结束
      result += str
      if err == io.EOF {//io.EOF代表文件的末尾
            //注意:如果文件最后一行文字没有换行,则会一直读取到文件末尾,
            //所以即使是判断读到了文件末尾,也要把读取的内容输出一下
            break
      }
    }
    fmt.Println(result)
}
</code></pre>
<h3 id="示例5-创建文件并写入内容">示例5: 创建文件并写入内容</h3>
<p><img src="https://img2020.cnblogs.com/blog/720430/202006/720430-20200605222628825-589104591.png" alt="" loading="lazy"></p>
<p>第二个参数:文件代开模式(可以组合);第三个参数:权限控制(如0755)<br>
<img src="https://img2020.cnblogs.com/blog/720430/202006/720430-20200605222639678-1763642532.png" alt="" loading="lazy"></p>
<pre><code class="language-go">package main

import (
        "fmt"
        "os"
)

func main() {

        //1.创建文件file.txt
        file, err := os.OpenFile("src/file.txt", os.O_WRONLY | os.O_CREATE, 0755)
        if err != nil {
                fmt.Println("文件打开/创建失败,原因是:", err)
                return
        }

        defer func() {
                err= file.Close()
                if err != nil {
                        fmt.Println("文件关闭失败,原因是:", err)
                }
        }()

        //写入数据
        var str = "暗黑西游狮驼岭,斗战胜佛孙悟空。\n"

        for i := 0; i &lt; 5; i++ {
                file.WriteString(str)
        }
}
</code></pre>
<h3 id="示例6-写文件的四种方式">示例6: 写文件的四种方式</h3>
<p>1.使用WriteAt()搭配Seek()方法实现写文件功能</p>
<pre><code class="language-go">package main

import (
        "io"
        "log"
        "os"
)

func main() {

        file, err := os.OpenFile("./test.txt", os.O_RDWR|os.O_CREATE, 0755)
        if err != nil {
                log.Fatalf("open file failed, err: %v\n", err)
        }
        defer func() {
                err = file.Close()
                if err != nil {
                        log.Fatalf("close file failed, err: %v\n", err)
                }
        }()
    //Seek(): 修改文件的读写指针位置.
    //参数1: 偏移量. 正:向文件尾部偏移, 负:向文件头部偏移
    //参数2: 偏移起始位置
    //       io.SeekStart: 文件起始位置
    //       io.SeekCurrent: 文件当前位置
    //       io.SeekEnd: 文件结尾位置
    //返回值:表示从文件起始位置,到当前文件读写指针位置的偏移量。
    //WriteAt(): 在文件指定偏移位置,写入[]byte,通常搭配Seek()
    //参数1: 待写入的数据
    //参数2: 偏移量
    //返回: 实际写出的字节数
        for i := 0; i &lt; 5; i++ {
                offset, _ := file.Seek(-3, io.SeekEnd)
                _, _ = file.WriteAt([]byte("你好"), offset)
        }
}
</code></pre>
<p><strong>注意</strong>: 由于使用的OpenFile函数打开的文件,所以在选择打开模式的时候不能选择<code>os.O_APPEND</code>模式,因为该模式表示的是在文件末尾追加,这与WriteAt在指定的位置写是想冲突的,虽然我在测试的时候加上<code>os.O_APPEND</code>模式并没有报错,但是代码执行完之后发现,想要写入的内容并没有真正的写入到文件中。<br>
写入前<br>
<img src="https://img2020.cnblogs.com/blog/720430/202006/720430-20200605222701905-679738111.png" alt="" loading="lazy"></p>
<p>写入后<br>
<img src="https://img2020.cnblogs.com/blog/720430/202006/720430-20200605222711489-1916066275.png" alt="" loading="lazy"></p>
<p>2.一次性写文件</p>
<pre><code class="language-go">package main

import (
        "io/ioutil"
        "log"
)

func main() {
        str := "hello树先生"
        //如果文件已存在,则会清空原来的内容,写入新内容,如果文件不存在,则会创建文件并写入内容
        err := ioutil.WriteFile("./test.txt", []byte(str), 0755)
        if err != nil {
                log.Fatalf("写入文件错误,错误为:%v\n", err)
        }
}
</code></pre>
<p>3.使用带缓冲的方式写文件</p>
<pre><code class="language-go">package main

import (
        "bufio"
        "fmt"
        "os"
)

func main() {

        //1.创建文件file.txt
        file, err := os.OpenFile("src/file.txt", os.O_WRONLY | os.O_CREATE | os.O_TRUNC, 0755)
        defer func() {
                err= file.Close()
                if err != nil {
                        fmt.Println("文件关闭失败,原因是:", err)
                }
        }()

        if err != nil {
                fmt.Println("文件创建失败,原因是:", err)
                return
        }

        //写入数据
        var str = "你好,世界\n"

        //写入时,使用带缓存的*Writer
        writer := bufio.NewWriter(file)

        for i := 0; i &lt; 5; i++ {
                writer.WriteString(str)
        }

        //因为writer是带缓存的,因此在调用writeString方法时,其实内容是先写入到缓存
        //因此需要调用Flush方法,将缓存数据写入到文件中,否则文件中会丢失数据
        writer.Flush()
}
</code></pre>
<h3 id="示例7-把一个文件内容写入到另一个文件">示例7: 把一个文件内容写入到另一个文件</h3>
<pre><code class="language-go">package main

import (
    "fmt"
    "io/ioutil"
)

func main() {

    //打开文件,文件路径相对于GOPATH开始,或者写全路径(/Users/xxx/Go/src/file.txt)
    data, err := ioutil.ReadFile("src/1.txt")
    if err != nil {
      fmt.Println("文件打开失败,原因是:", err)
    }

    err = ioutil.WriteFile("src/2.txt", data, 0755)

    if err != nil {
      fmt.Println("文件写入失败,原因是:", err)
    }
}
</code></pre>
<h3 id="示例8使用bufio获取用户输入">示例8:使用bufio获取用户输入</h3>
<pre><code class="language-go">package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    var s string
    var reader = bufio.NewReader(os.Stdin)
    s, _ = reader.ReadString('\n')
    fmt.Printf("读取到的内容为:%s\n", s)
}
</code></pre>
<h3 id="示例9-判断文件或目录是否存在">示例9: 判断文件或目录是否存在</h3>
<p>Go判断文件或文件夹是否存在的方法为使用os.Stat()函数返回的错误值进行判断:<br>
(1)如果返回的错误为nil,说明文件或文件夹存在<br>
(2)如果返回的类型使用os.IsNotExist()判断为true,说明文件或文件夹不存在<br>
(3)如果返回的错误为其它类型,则不确定是否存在</p>
<pre><code class="language-go">package main

import (
        "fmt"
        "os"
)

func main() {

        isExist, err := isFileExists("src/sfile.txt")
        if err != nil {
                fmt.Println("发生错误:", err)
        }

        if isExist {
                fmt.Println("存在")
        } else {
                fmt.Println("不存在")
        }
}

//判断文件或者目录是否存在
func isFileExists(path string) (bool, error) {

        _, err := os.Stat(path)
        if err == nil {
                return true, nil
        }
        if os.IsNotExist(err) {
                return false, nil
        }
        return false, err
}
</code></pre>
<h3 id="示例10-拷贝文件图片音视频">示例10: 拷贝文件、图片音视频</h3>
<p>io.Copy方法</p>
<pre><code class="language-go">package main

import (
        "fmt"
        "io"
        "os"
)
func CopyFile(srcFileName string, dstFileName string) (int64, error) {

        //源文件处理
        srcFile, err := os.Open(srcFileName)
        defer func() {
                err = srcFile.Close()
                if err != nil {
                        fmt.Println("源文件关闭失败,原因是:", err)
                }
        }()

        if err != nil {
                fmt.Println("源文件打开失败,原因是:", err)
                return 0, err
        }

        //目标文件处理
        dstFile, err := os.OpenFile(dstFileName, os.O_CREATE | os.O_WRONLY, 0755)
        defer func() {
                err = dstFile.Close()
                if err != nil {
                        fmt.Println("目标文件关闭失败,原因是:", err)
                }
        }()
        if err != nil {
                fmt.Println("目标文件打开失败,原因是:", err)
                return 0, err
        }

        return io.Copy(dstFile, srcFile)
}

func main() {

        result, err := CopyFile("src/dst.jpeg", "src/哈哈.jpeg")

        if err == nil {
                fmt.Println("拷贝成功!拷贝的字节数为: ", result)
        }
}
</code></pre>
<p>对于大文件,我们还可以采用下面的方式</p>
<pre><code class="language-go">package main

import (
        "io"
        "log"
        "os"
)

func CopyFile(srcFileName string, dstFileName string) {
        //打开源文件
        srcFile, err := os.Open(srcFileName)
        if err != nil {
                log.Fatalf("源文件读取失败,原因是:%v\n", err)
        }
        defer func() {
                err = srcFile.Close()
                if err != nil {
                        log.Fatalf("源文件关闭失败,原因是:%v\n", err)
                }
        }()

        //创建目标文件,稍后会向这个目标文件写入拷贝内容
        distFile, err := os.Create(dstFileName)
        if err != nil {
                log.Fatalf("目标文件创建失败,原因是:%v\n", err)
        }
        defer func() {
                err = distFile.Close()
                if err != nil {
                        log.Fatalf("目标文件关闭失败,原因是:%v\n", err)
                }
        }()
        //定义指定长度的字节切片,每次最多读取指定长度
        var tmp = make([]byte, 1024*4)
        //循环读取并写入
        for {
                n, err := srcFile.Read(tmp)
                n, _ = distFile.Write(tmp[:n])
                if err != nil {
                        if err == io.EOF {//读到了文件末尾,并且写入完毕,任务完成返回(关闭文件的操作由defer来完成)
                                return
                        } else {
                                log.Fatalf("拷贝过程中发生错误,错误原因为:%v\n", err)
                        }
                }
        }
}

func main() {
        CopyFile("./worm.mp4", "./dist.mp4")
}
</code></pre>
<h3 id="示例11-遍历目录">示例11: 遍历目录</h3>
<h4 id="遍历目录">遍历目录</h4>
<pre><code class="language-go">package main

//我们读写的文件一般存放于目录中.因此,有时需要指定到某一个目录下,根据目录存储的状况
//再进行文件的特定操作.接下来我们看看目录的基本操作方法.
import (
        "fmt"
        "log"
        "os"
)
//打开目录
//打开目录我们也使用OpenFile函数,但要指定不同的参数来通知系统,要打开的是一个目录文件.
//func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
//参数1: name,表示要打开的目录名称.使用绝对路径较多
//参数2: flag,表示打开文件的读写模式
//参数3: perm,表示打开权限.但对于目录来说有所不同,通常传os.ModeDir.
//返回值:由于是操作目录,所以file是指向目录的文件指针.err中保存错误信息

//读目录内容
//这与读文件有所不同.目录中存放的是文件名和子目录名.所以使用Readdir函数
//func (f *File) Readdir(n int) (fi []FileInfo, err error)
//如果n&gt;0,Readdir函数会返回一个最多n个成员的切片。这时,如果Readdir返回一个空切片,
//它会返回一个非nil的错误说明原因。如果到达了目录f的结尾,返回值err会是io.EOF。
//
//如果n&lt;=0,Readdir函数返回目录中剩余所有文件对象的FileInfo构成的切片。
//此时,如果Readdir调用成功(读取所有内容直到结尾),它会返回该切片和nil的错误值。
//如果在到达结尾前遇到错误,会返回之前成功读取的FileInfo构成的切片和该错误。

func main() {
        //不推荐,因为通过查看ioutil.ReadDir()函数可知,官方使用的是os.Open()函数打开的目录
        //file, err := os.OpenFile("./dir", os.O_RDWR, os.ModeDir)
        file, err := os.Open("./dir")
        if err != nil {
                log.Fatalf("文件打开失败,原因是:%v\n", err)
        }
        defer func() {
                err = file.Close()
                if err != nil {
                        log.Fatalf("文件关闭失败,原因是:%v\n", err)
                }
        }()
        //Readdir方法返回一个FileInfo接口类型的切片和一个error类型的错误
        infos, err := file.Readdir(-1)
        for _, info := range infos {
                fmt.Printf("%v, %v\n", info.Name(), info.IsDir())
        }
}
</code></pre>
<h4 id="仅遍历目录忽略文件">仅遍历目录,忽略文件</h4>
<p>方法1:使用os包</p>
<pre><code class="language-go">package main

import (
    "fmt"
    "os"
)

var dirNames = make([]string, 0, 50)
var pathSeparator = string(os.PathSeparator)
func traverseDir(filePath string) error {
    file, err := os.Open(filePath)
    if err != nil {
      return err
    }
    fileInfo, err := file.Readdir(0)
    if err != nil {
      return err
    }

    for _, value := range fileInfo {
      if value.IsDir() {
            dirNames = append(dirNames, value.Name())
            err = traverseDir(filePath+pathSeparator+value.Name())
            if err != nil {
                return err
            }
      }
    }
    return err
}

func main() {

    var filePath = "./dir"
    err := traverseDir(filePath)
    if err != nil {
      fmt.Println(err)
    }
    fmt.Println(dirNames)
}
</code></pre>
<p>方法2:使用ioutil包</p>
<pre><code class="language-go">package main

import (
    "fmt"
    "io/ioutil"
    "os"
)

var dirNames = make([]string, 0, 50)
var pathSeparator = string(os.PathSeparator)
func traverseDir(filePath string) error {
    fileInfos, err := ioutil.ReadDir(filePath)
    if err != nil {
      return err
    }
    for _, fileInfo :=range fileInfos {
      if fileInfo.IsDir() {
            dirNames = append(dirNames, fileInfo.Name())
            err =traverseDir(filePath+pathSeparator+fileInfo.Name())
            if err != nil {
                return err
            }
      }
    }
    return err
}

func main() {

    var filePath = "./dir"
    err := traverseDir(filePath)
    if err != nil {
      fmt.Println(err)
    }
    fmt.Println(dirNames)
}
</code></pre>
<h3 id="示例12-修改文件名">示例12: 修改文件名</h3>
<pre><code class="language-go">package main

import (
    "fmt"
    "io/ioutil"
    "os"
    "strings"
)

var pathSeparator = string(os.PathSeparator)
//重命名文件
func renameFileName(filePath string, old string, new string) error {
    files, err := ioutil.ReadDir(filePath)
    if err != nil {
      return err
    }
    for _, fileInfo := range files {
      if !fileInfo.IsDir() {
            err = os.Rename(filePath + pathSeparator + fileInfo.Name(),
                filePath + pathSeparator + strings.Replace(fileInfo.Name(), old, new, -1),
            )
            if err != nil {
                return err
            }
      }
    }
    return err
}

func main() {
    var filePath = "./dir"
    err := renameFileName(filePath, "f", "kkk")
    if err != nil {
      fmt.Printf("错误: %v\n", err)
    }
}
</code></pre>
<h3 id="示例13创建目录">示例13:创建目录</h3>
<pre><code class="language-go">package main

import (
        "fmt"
        "os"
)

func main() {
        //Mkdir使用指定的权限和名称创建一个目录。如果出错,会返回*PathError底层类型的错误。
        err := os.Mkdir("./foo", 0755)
        if os.IsExist(err) {
                fmt.Println("目录已存在")
                return
        }

        //MkdirAll使用指定的权限和名称创建一个目录,包括任何必要的上级目录,并返回nil,否则返回错误。
        //权限位perm会应用在每一个被本函数创建的目录上。如果path指定了一个已经存在的目录,MkdirAll不做任何操作并返回nil。
        err = os.MkdirAll("./foo/bar", 0755)
        if err != nil {
                fmt.Printf("%v\n", err)
                return
        }
}
</code></pre>
<h3 id="示例14删除文件">示例14:删除文件</h3>
<pre><code class="language-go">package main

import (
        "fmt"
        "os"
)

func main() {
        //Remove删除name指定的文件或目录。如果出错,会返回*PathError底层类型的错误。
        //该方法不能删除非空目录,如果想删除目录以及目录下的所有文件,可以使用RemoveAll
        err := os.Remove("./def")
        if os.IsNotExist(err) {
                fmt.Println("您要删除的文件或目录不存在")
                return
        }
        if err != nil {
                fmt.Println(err)
        }

        //RemoveAll删除path指定的文件,或目录及它包含的任何下级对象。
        //它会尝试删除所有东西,除非遇到错误并返回。
        //如果path指定的对象不存在,RemoveAll会返回nil而不返回错误。
        err = os.RemoveAll("./def")
        if err != nil {
                fmt.Println(err)
        }
}
</code></pre><br><br>
来源:https://www.cnblogs.com/itbsl/p/13052631.html
頁: [1]
查看完整版本: Go文件操作