美文网首页Golang程序员go语言学习
Golang 学习笔记(08)—— 文件操作

Golang 学习笔记(08)—— 文件操作

作者: ChainZhang | 来源:发表于2018-01-02 16:03 被阅读96次

    本文为转载,原文:Golang 学习笔记(08)—— 文件操作

    Golang

    path

    在path包中封装了一些路径相关的操作,在开始接触文件操作之前,我们先看看路径的相关函数。在Linux中,路径的格式为/user/bin路径中分隔符是/;Windows中的路径格式为c:\Windows路径中的分隔符是\。而在go中只认/。所以在windows中,需要把path中的\替换为/。

    func Base

    func Base(path string) string
    

    Base函数返回路径的最后一个元素。在提取元素前会求掉末尾的斜杠。 如果路径是"",会返回"."; 如果路径是只有一个斜杆构成,会返回"/"

    func Clean

    func Clean(path string) string
    

    Clean函数通过单纯的词法操作返回和path代表同一地址的最短路径。

    它会不断的依次应用如下的规则,直到不能再进行任何处理:

    1. 将连续的多个斜杠替换为单个斜杠
    2. 剔除每一个.路径名元素(代表当前目录)
    3. 剔除每一个路径内的..路径名元素(代表父目录)和它前面的非..路径名元素
    4. 剔除开始一个根路径的..路径名元素,即将路径开始处的"/.."替换为"/"

    只有路径代表根地址"/"时才会以斜杠结尾。如果处理的结果是空字符串,Clean会返回"."。

    func Dir

    func Dir(path string) stringDir
    

    返回路径除去最后一个路径元素的部分,即该路径最后一个元素所在的目录。在使用Split去掉最后一个元素后,会简化路径并去掉末尾的斜杠。如果路径是空字符串,会返回".";如果路径由1到多个斜杠后跟0到多个非斜杠字符组成,会返回"/";其他任何情况下都不会返回以斜杠结尾的路径。

    func Ext

    func Ext(path string) string
    

    Ext函数返回path文件扩展名。返回值是路径最后一个斜杠分隔出的路径元素的最后一个'.'起始的后缀(包括'.')。如果该元素没有'.'会返回空字符串。

    func IsAbs

    func IsAbs(path string) bool
    

    IsAbs返回路径是否是一个绝对路径。

    func Split

    func Split(path string) (dir, file string)
    

    Split函数将路径从最后一个斜杠后面位置分隔为两个部分(dir和file)并返回。如果路径中没有斜杠,函数返回值dir会设为空字符串,file会设为path。两个返回值满足path == dir+file。

    func Join

    func Join(elem ...string) string
    

    Join函数可以将任意数量的路径元素放入一个单一路径里,会根据需要添加斜杠。结果是经过简化的,所有的空字符串元素会被忽略。

    示例

    package main
    
    import (
        "path"
        "fmt"
    )
    
    func main(){
        fmt.Println("path.Base: ",path.Base("C:/Users/zzc/go/src/channelDemo"))
        fmt.Println("path.Clean: ",path.Clean("C:/Users/zzc/./go///src/../../channelDemo/"))
        fmt.Println("path.Ext: ",path.Ext("C:/Users/zzc/go/src/channelDemo/main.go"))
        fmt.Println("path.Dir: ",path.Dir("C:/Users/zzc/go/src/channelDemo/main.go"))
        fmt.Println("path.IsAbs: ",path.IsAbs("C:/Users/zzc/go/src/channelDemo/main.go"))
        dir, file := path.Split("C:/Users/zzc/go/src/channelDemo/main.go")
        fmt.Println("path.Split: ",dir, file)
        fmt.Println("path.Join: ",path.Join("c:/Users", "zzc", "go", "src"))
    }
    
    运行结果

    文件读写

    在os包中提供了一下文件操作的函数。

    创建文件

    • Create
    func Create(name string) (file *File, err error)
    

    Create采用模式0666(任何人都可读写,不可执行)创建一个名为name的文件,如果文件已存在会截断它(为空文件)。如果成功,返回的文件对象可用于I/O;对应的文件描述符具有O_RDWR模式。如果出错,错误底层类型是*PathError。
    例如:

    file, err := os.Create("d:/my.txt")
    

    打开文件

    open

    func Open(name string) (file *File, err error)
    

    Open打开一个文件用于读取。如果操作成功,返回的文件对象的方法可用于读取数据;对应的文件描述符具有O_RDONLY模式。如果出错,错误底层类型是*PathError。

    OpenFile

    func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
    

    OpenFile是一个更一般性的文件打开函数,大多数调用者都应用Open或Create代替本函数。它会使用指定的选项(如O_RDONLY等)、指定的模式(如0666等)打开指定名称的文件。如果操作成功,返回的文件对象可用于I/O。如果出错,错误底层类型是*PathError
    name : 要打开或要创建的文件名
    flag : 是打开文件的方式,可以取以下值:

    1. O_RDONLY:以只读的方式打开
    2. O_WRONLY:以只写的方式打开
    3. O_RDWR:以读写的方式打开
    4. O_APPEND:以追加方式打开文件,写入的数据将追加到文件尾
    5. O_CREATE:当文件不存在时创建文件
    6. O_EXCL:与O_CREATE一起使用,当文件存在时Open失败
    7. O_SYNC:以同步方式打开文件。每次write系统调用后等等待实际的物理I/O完成后才返回,默认(不使用该标记)是使用缓冲的,也就是说每次的写操作是写到系统内核缓冲区中,等系统缓冲区满后才写到实际存储设备中。
    8. O_TRUNC:如果文件已存在,打开是会清空文件内容。必须于O_WRONLY或O_RDWR配合使用。截断文件,需要有写的权限。

    FileMode: 是文件的权限,只有在文件不存在,新建文件时该参数才有效。用来指定新建的文件的权限。必须跟O_CREATE配合使用。

    写文件

    Write

    func (f *File) Write(b []byte) (n int, err error)
    

    Write向文件中写入len(b)字节数据。它返回写入的字节数和可能遇到的任何错误。如果返回值n!=len(b),本方法会返回一个非nil的错误。

    WriteString

    func (f *File) WriteString(s string) (ret int, err error)
    

    WriteString类似Write,但接受一个字符串参数。

    WriteAt

    func (f *File) WriteAt(b []byte, off int64) (n int, err error)
    

    WriteAt在指定的位置(相对于文件开始位置)写入len(b)字节数据。它返回写入的字节数和可能遇到的任何错误。如果返回值n!=len(b),本方法会返回一个非nil的错误。

    读文件

    Read

    func (f *File) Read(b []byte) (n int, err error)
    

    Read方法从f中读取最多len(b)字节数据并写入b。它返回读取的字节数和可能遇到的任何错误。文件终止标志是读取0个字节且返回值err为io.EOF。

    ReadAt

    func (f *File) ReadAt(b []byte, off int64) (n int, err error)
    

    ReadAt从指定的位置(相对于文件开始位置)读取len(b)字节数据并写入b。它返回读取的字节数和可能遇到的任何错误。当n<len(b)时,本方法总是会返回错误;如果是因为到达文件结尾,返回值err会是io.EOF。

    其他

    Close

    func (f *File) Close() error
    

    Close关闭文件f,使文件不能用于读写。它返回可能出现的错误。

    Seek

    func (f *File) Seek(offset int64, whence int) (ret int64, err error)
    

    Seek设置下一次读/写的位置。offset为相对偏移量,而whence决定相对位置:0为相对文件开头,1为相对当前位置,2为相对文件结尾。它返回新的偏移量(相对开头)和可能的错误。
    whence在系统中定义的有常量:
    SEEK_SET:0
    SEEK_CUR:1
    SEEK_END:2

    例子

    package main
    
    import (
        "io"
        "fmt"
        "os"
    )
    
    func main(){
        testio()
    }
    
    func testio(){
        //若文件不存在则创建文件,以append方式打开
        file, err := os.OpenFile("d:/test.txt", os.O_CREATE|os.O_APPEND, 0666)
        if err != nil{
            fmt.Println(err)
            return
        }
        defer file.Close() //关闭文件
        file.WriteString("i am chain ") //写入文件
        buf := make([]byte, 1024)
        var str string
        file.Seek(0, os.SEEK_SET) //重置文件指针
        //读取文件
      for {
            n, ferr := file.Read(buf)
            if ferr != nil && ferr != io.EOF{
                fmt.Println(ferr.Error())
                break
            }
            if n == 0{
                break
            }
            str += string(buf[0:n])
        }
        fmt.Println("file content: ", str)
    }
    

    执行两次之后的结果如下图


    运行结果

    ioutil

    在ioutil中封装了一些函数,让IO操作更简单方便

    ReadAll

    func ReadAll(r io.Reader) ([]byte, error)
    

    ReadAll从r读取数据直到EOF或遇到error,返回读取的数据和遇到的错误。成功的调用返回的err为nil而非EOF。因为本函数定义为读取r直到EOF,它不会将读取返回的EOF视为应报告的错误。

    ReadFile

    func ReadFile(filename string) ([]byte, error)
    

    ReadFile 从filename指定的文件中读取数据并返回文件的内容。成功的调用返回的err为nil而非EOF。因为本函数定义为读取整个文件,它不会将读取返回的EOF视为应报告的错误。

    WriteFile

    func WriteFile(filename string, data []byte, perm os.FileMode)
    

    error函数向filename指定的文件中写入数据。如果文件不存在将按给出的权限创建文件,否则在写入数据之前清空文件。

    例子

    package main
    
    import (
        "io"
        "io/ioutil"
        "fmt"
        "os"
    )
    
    func main(){
        testioutil()
    }
    
    func testioutil(){
        str := "i am chain, i am a good boy. "
        //写入数据
        err := ioutil.WriteFile("d:/a.txt",[]byte(str), 0666)
        if err != nil{
            fmt.Println(err.Error())
        }else{
            fmt.Println("write success!")
        }
      //通过readfile函数读取数据
        buf1, err1 := ioutil.ReadFile("d:/a.txt")
        if err1 != nil{
            fmt.Println(err1.Error())
        }else{
            fmt.Println("Read File: ", string(buf1))
        }
      //通过readall读取数据
        f, err2 := os.OpenFile("d:/a.txt", os.O_RDONLY, 0666)
        if err2 != nil{
            fmt.Println(err2.Error())
            return
        }
        defer f.Close()
        buf2, err3 := ioutil.ReadAll(f)
        if err3 != nil{
            fmt.Println(err3.Error())
        }else{
            fmt.Println("read all: ", string(buf2))
        }
    }
    
    运行结果

    目录操作

    os/Readdir

    func (f *File) Readdir(n int) (fi []FileInfo, err error)
    

    Readdir读取目录f的内容,返回一个有n个成员的[]FileInfo,这些FileInfo是被Lstat返回的,采用目录顺序。对本函数的下一次调用会返回上一次调用剩余未读取的内容的信息。

    如果n>0,Readdir函数会返回一个最多n个成员的切片。这时,如果Readdir返回一个空切片,它会返回一个非nil的错误说明原因。如果到达了目录f的结尾,返回值err会是io.EOF。

    如果n<=0,Readdir函数返回目录中剩余所有文件对象的FileInfo构成的切片。此时,如果Readdir调用成功(读取所有内容直到结尾),它会返回该切片和nil的错误值。如果在到达结尾前遇到错误,会返回之前成功读取的FileInfo构成的切片和该错误。

    package main
    
    import (
        "fmt"
        "os"
    )
    
    func main(){
        f, err := os.OpenFile("D:/code/", os.O_RDONLY, 0666)
        if err != nil{
            fmt.Println(err.Error())
            return
        }
        arrFiles, err1:=f.Readdir(0)
        if err1 != nil{
            fmt.Println(err1.Error())
            return
        }
        for k, v := range arrFiles{
            fmt.Println(k, "\t", v, "\t", v.IsDir())
        }
    }
    
    运行结果

    ioutil/ReadDir

    func ReadDir(dirname string) ([]os.FileInfo, error)
    

    返回dirname指定的目录的目录信息的有序列表。

    package main
    
    import (
        "io"
        "io/ioutil"
        "fmt"
    )
    
    func main(){
        arrFiles, err1 := ioutil.ReadDir("D:/code/")
        if err1 != nil{
            fmt.Println(err1.Error())
            return
        }
        for k, v := range arrFiles{
            fmt.Println(k, "\t", v, "\t", v.IsDir())
        }
    }
    
    运行结果

    gob序列化

    序列化就是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。之后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

    gob是go中特有的序列化技术,它支持除interface,function,channel外的所有go数据类型。序列化用Encoder,反序列化用Decoder。

    package main
    
    import (
        "encoding/gob"
        "os"
        "fmt"
    )
    
    type Student struct{
        Name string
        Age int
    }
    
    func main(){
        stu := &Student{"chain", 23}
        f, err := os.Create("d:/stu.txt")
        if err != nil{
            fmt.Println(err.Error())
            return
        }
        defer f.Close()
        //创建Encoder对象
        encode := gob.NewEncoder(f)
        //将stu序列化到f中
        encode.Encode(stu)
        //重置文件指针
        f.Seek(0, os.SEEK_SET)
        //创建decoder对象
        decoder := gob.NewDecoder(f)
        var s1 Student
        //反序列化对象
        decoder.Decode(&s1)
        fmt.Println(s1)
    }
    
    gob序列化示例

    转载请注明出处
    Golang 学习笔记(08)—— 文件操作

    目录
    上一节:Golang 学习笔记(07)—— 错误及异常处理
    下一节:Golang 学习笔记(09)—— json和xml解析

    相关文章

      网友评论

        本文标题:Golang 学习笔记(08)—— 文件操作

        本文链接:https://www.haomeiwen.com/subject/iyqqnxtx.html