美文网首页
go语言文件读取以及IO操作

go语言文件读取以及IO操作

作者: __robin | 来源:发表于2019-02-19 18:46 被阅读0次

    文章目录

    • 文件信息接口os.FileInfo
    • 文件的常规操作 (os包)
    • 文件的读取和写入 (io及os包)
    • ioutil包
    • bufio包

    一、文件信息

    os.FileInfo接口

    接口属性

    type FileInfo interface {
        Name() string       // 文件的名字
        Size() int64        // 普通文件返回值表示其大小;其他文件的返回值含义各系统不同
        Mode() FileMode     // 文件的模式位 (例-rw-rw-r--)
        ModTime() time.Time // 文件的修改时间
        IsDir() bool        // 等价于Mode().IsDir()
        Sys() interface{}   // 底层数据来源(可以返回nil)
    }
    

    os.fileStat结构体实现了FileInfo接口的所有方法

    type fileStat struct {
        name    string
        size    int64
        mode    FileMode
        modTime time.Time
        sys     syscall.Stat_t
    }
    

    示例

    fileInfo, err := os.Stat("./aa.txt")
    if err != nil{
        fmt.Println(err)
        return
    }
    fmt.Printf("%T: %v", fileInfo, fileInfo)  // *os.fileStat: &{aa.txt 23 ...}
    fmt.Println(fileInfo.Name())              // aa.txt
    fmt.Println(fileInfo.IsDir())             // false
    fmt.Println(fileInfo.Size())              // 23
    fmt.Println(fileInfo.Mode())              // -rw-rw-r--
    fmt.Println(fileInfo.ModTime())           // 2019-02-15 14:44:39.745 +0800 CST
    

    文件路径相关函数

    路径相关的函数有两个包,pathpath/filepath,
    两个包内有一些相同的函数,如IsAbs()Join()Dir()
    filepath中的函数兼容各个操作系统,涉及到windows系统路径操作时,应该使用filepath

    • filepath.Rel(basepath, targpath string) (string, error)获取相对路径
    • filepath.Abs(path string) (string, error)获取绝对路径,如果path不是绝对路径,会加入当前工作目录以使之成为绝对路径。
    • path.Join(elem ...string) string路径拼接
    • path.IsAbs(path string) bool判断文件是否是绝对路径
    • path.Dir(path string) string获取目录

    二、文件的常规操作

    创建目录 如果存在则失败

    • os.Mkdir(name string, perm FileMode) error
      • 仅创建一层
      • 相当于linux命令mkdir
    • os.MkdirAll(path string, perm FileMode) error
      • 创建多层
      • 相当于linux命令mkdir -p

    创建文件 如果存在会覆盖

    • os.Create(name string) (file *File, err error)
      • 底层调用 os.OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
      • 采用模式0666(任何人都可读写,不可执行)
      • 如果文件存在会清空它

    打开文件

    • os.Open(name string) (file *File, err error)

      • 底层调用OpenFile(name, O_RDONLY, 0)
      • 以只读的方式打开文件
    • os.OpenFile(name string, flag int, perm FileMode) (file *File, err error)

      • perm可为06660777
      • flagos包中定义的常量:
    const (
        O_RDONLY int = syscall.O_RDONLY // 只读模式打开文件
        O_WRONLY int = syscall.O_WRONLY // 只写模式打开文件
        O_RDWR   int = syscall.O_RDWR   // 读写模式打开文件
        O_APPEND int = syscall.O_APPEND // 写操作时将数据附加到文件尾部
        O_CREATE int = syscall.O_CREAT  // 如果不存在将创建一个新文件
        O_EXCL   int = syscall.O_EXCL   // 和O_CREATE配合使用,文件必须不存在
        O_SYNC   int = syscall.O_SYNC   // 打开文件用于同步I/O
        O_TRUNC  int = syscall.O_TRUNC  // 如果可能,打开时清空文件
    )
    

    关闭文件

    • file.Close() error
      • *File指针的方法
      • 程序与文件之间的连接断开

    删除文件或目录

    • os.Remove(name string) error
      • 只删除一层
      • 相当于linux命令rm
    • os.RemoveAll(path string) error
      • 删除path指定的文件,或目录及它包含的任何下级对象
      • 相当于linux命令rm -r

    三、文件的读写操作

    读取文件

    • os.Open(filename) --> *File
    • file.Read([]byte) --> n, err
      • 单次读取的字节数最大为[]byte的长度
      • n为实际读取到的字节数
      • 读取到末尾时errEOF(end of file)
    • file.Close()关闭文件

    示例:

    //step1:打开文件
    fileName := ".text.txt"
    file, err := os.Open(fileName)
    if err != nil {
        fmt.Println("打开错误", err)
        return
    }
    //step2:读/写
    //从file中读取最多len(bs)个字节,存入bs切边中,n是实际读取的数量
    bs := make([]byte, 1024, 1024)
    for {
        n, err := file.Read(bs)
        if n == 0 || err == io.EOF {
            fmt.Println("读取结束")
            break
        }
        fmt.Println(string(bs[:n]))
    }
    //step3:关闭文件
    file.Close()
    

    写入文件

    写入文件与读取类似

    • os.Open(filename) --> *File
    • file.Write([]byte) --> n, err
      • []byte中的数据写入文件
    • file.WriteString(string) --> n, err
      • string写入文件
    • file.Close()

    文件复制

    • io.Copy(dst Writer, src Reader) (written int64, err error)
      • dst和src为实现了接口io.Writer和io.Reader的实例

    示例:

    func copyFile(srcFile, destFile string) (int64, error) {
        file1, err := os.Open(srcFile)
        if err != nil {
            return 0, err
        }
        file2, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE, os.ModePerm)
        if err != nil {
            return 0, err
        }
        defer file1.Close()
        defer file2.Close()
        return io.Copy(file2, file1)
    }
    

    四、ioutil包

    • ReadFile() --> ([]byte, error)
      • 读取所有数据,返回字节数组
    • WriteFile(filename string, data []byte, perm os.FileMode) --> error
      • 文件不存在则创建文件,存在则清空文件
      • os.FileMode可以直接用0666或者0777
    • ReadDir() --> ([]os.FileInfo, error)
      • 读取一个目录下的字内容,目录或文件,但是只有一层
      • 返回一个os.FileInfo切片

    示例:

    data, err := ioutil.ReadFile("aa.txt")
    fmt.Println(string(data))
    if err != nil {
        fmt.Println(err)
        return
    }
    
    err = ioutil.WriteFile("bb.txt", data, 0666)
    if err != nil {
        fmt.Println(err)
        return
    }
    
    fileInfos, err := ioutil.ReadDir(".")
    if err != nil {
        fmt.Println(err)
        return
    }
    for i := range fileInfos {
        fmt.Println(i, fileInfos[i].IsDir(), fileInfos[i].Name())
    }
    

    五、bufio包

    • bufio包实现了有缓冲的I/O
    • bufio封装了一个Reader݊及Writer结构体,分别实现了io.Readerio.Writer接口
    • 通过对对io模块的封装,提供了带有缓冲的io操作,减小了大块数据读写的io开销

    io.Reader和io.Writer

    type Reader interface {
        Read(p []byte) (n int, err error)
    }
    
    type Writer interface {
        Write(p []byte) (n int, err error)
    }
    

    os.Open(name string) (*File, error)返回的文件指针就实现了io.Reader

    bufio.Reader结构体

    • NewReader(rd io.Reader) *Reader
      • NewReader创建一个具有默认大小缓冲、从r读取的*Reader
    • Reader.Read(p []byte) (n int, err error)
      • Read读取数据写入p。本方法返回写入p的字节数
      • 返回值n可能小于len(p),读取到达结尾时,返回值n将为0err将为io.EOF
      • 类似File.Read()方法

    示例:

    s := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
    br := bufio.NewReader(s)
    b := make([]byte, 20)
    
    n, err := br.Read(b)
    fmt.Printf("%-20s %-2v %v\n", b[:n], n, err)  // ABCDEFGHIJKLMNOPQRST 20 <nil>
    
    n, err = br.Read(b)
    fmt.Printf("%-20s %-2v %v\n", b[:n], n, err)  // UVWXYZ1234567890 16 <nil>
    
    n, err = br.Read(b)
    fmt.Printf("%-20s %-2v %v\n", b[:n], n, err)  // 0 EOF
    
    • Reader.ReadBytes(delim byte) (line []byte, err error)
      • delimdelimiter的缩写意为定位符
      • ReadBytes读取直到第一次遇到delim字节,返回一个包含已读取的数据和delim字节的切片

    示例:

    s := strings.NewReader("ABCDEFG\n123456\n")
    br := bufio.NewReader(s)
    
    for {
        sli, err := br.ReadBytes('\n')
        if err err == io.EOF {
            break
        }
        fmt.Println(sli)
    }
    // [65 66 67 68 69 70 71 10]
    // [49 50 51 52 53 54 10]
    
    • Reader.ReadString(delim byte) (line string, err error)
      • 返回的是字符串类型

    示例:

    s := strings.NewReader("ABCDEFG\n123456\n")
    br := bufio.NewReader(s)
    for {
        s, err := br.ReadString('\n')
        if err err == io.EOF {
            break
        }
        fmt.Print(s)
    }
    // ABCDEFG
    // 123456
    

    bufio.Writer结构体

    • NewWriter(w io.Writer) *Writer
      • NewWriter创建一个具有默认大小缓冲、写入w*Writer
    • Writer.Write(p []byte) (nn int, err error)
      • Writep的内容写入缓冲。返回写入的字节数。如果返回值nn < len(p),还会返回一个错误说明原因
      • 类似File.Write()方法
    • Writer.WriteString(s string) (int, error)
      • 写入一个字符串,返回写入的字节数
    • Writer.Flush() error
      • Flush方法将缓冲中的数据输出

    示例:

    file1, _ := os.Open("aa.txt")
    defer file1.Close()
    reader := bufio.NewReader(file1)
    file2, _ := os.Create("cc.txt")
    defer file2.Close()
    writer := bufio.NewWriter(file2)
    
    for {
        bs, err := reader.ReadBytes('\n')
        if err == io.EOF {
            fmt.Println("读取完毕")
            break
        }
        writer.Write(bs)
        writer.Flush()
    }
    

    bufio.Scanner结构体

    • NewScanner(r io.Reader) *Scanner
      • 创建并返回一个从r读取数据的Scanner,默认的分割函数是ScanLines
      • 通过Scanner.Split(split SplitFunc)方法,可以为Scanner指定splitFunc
      • Scanner可以通过plitFunc将r中的数据拆分为多个token,然后通过Scanner.Scan()依次读取
    • bufio中提供的默认splitFunc
      • ScanBytes,按照byte进程拆分
      • ScanRunes,按照行("\n")进程拆分
      • ScanWords,按照utf-8字符进行拆分
      • ScanLines,按照单词(" ")进程拆分
    • 常用方法
      • Split(split SplitFunc)
      • Scan() bool
      • Text() string
      • Bytes() []byte

    示例:

    scanner := bufio.NewScanner(os.Stdin)
    scanner.Split(bufio.ScanLines)
    for scanner.Scan() {
        if scanner.Text() == "q" {
            break
        }
        fmt.Println(scanner.Text()) // Println will add back the final '\n'
    }
    if err := scanner.Err(); err != nil {
        fmt.Fprintln(os.Stderr, "reading standard input:", err)
    }
    

    相关文章

      网友评论

          本文标题:go语言文件读取以及IO操作

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