Go语言读取文件的方法小结

 更新时间:2024年01月22日 08:13:55   作者:hankeyyh  
写程序时经常需要从一个文件读取数据,然后输出到另一个文件,这篇文章主要为大家详细介绍了Go语言读取文件的几种方法,希望对大家有所帮助

写程序时经常需要从一个文件读取数据,然后输出到另一个文件。最典型的例子比如,从stdin读取,然后输出到stdout。go提供了几种读取文件的方式,我们逐个来看一看~

fmt.Scan

func fmtScan() {
    str := ""
    for {
        fmt.Scan(&str)
        fmt.Printf("[fmt.scan]: %q (%d)\n", str, len(str))
    }
}
// input: abc def ghi
// output:
//[fmt.scan]: "abc" (3)
//[fmt.scan]: "def" (3)
//[fmt.scan]: "ghi" (3)

fmt.Scan 从stdin读取数据,输出到内存变量。它会将空白符作为分割符,把分割后的字符串,依次赋值给传入参数。在上面的例子中,就是循环了3次分别赋值给str。

os.Stdin.Read

func osStdinRead() {
    p := make([]byte, 5)
    for {
        nn, err := os.Stdin.Read(p)
        if err != nil && err != io.EOF {
            panic(err)
        }
        fmt.Printf("[os.stdin.read]: %q (%d)\n", p, nn)
        p = make([]byte, 5) // 清空p
    }
}
// input: abcdefghijk
// output:
//[os.stdin.read]: "abcde" (5)
//[os.stdin.read]: "fghij" (5)
//[os.stdin.read]: "k\n\x00\x00\x00" (2)

最多读取len(p)大小的数据,如果输入的内容超出了len(p),则Read会在下一轮循环中接着读取。

io系列

ReadAll

func ioReadAll() {
    for {
        p, err := io.ReadAll(os.Stdin)
        if err != nil {
            panic(err)
        }
        fmt.Printf("[io.ReadAll]: %q (%d)\n", p, len(p))
    }
}

// input: abc\nEOF
// output: [io.ReadAll]: "abc\n" (4)

ReadAll 读取全部,不把EOF当作错误返回。

ReadFull

func ioReadFull() {
    p := make([]byte, 5)
    for {
        nn, err := io.ReadFull(os.Stdin, p)
        if err != nil && err != io.EOF {
            fmt.Printf("[io.ReadFull]: %q (%d)\n", p, nn)
            panic(err)
        }
        fmt.Printf("[io.ReadFull]: %q (%d)\n", p, nn)
        p = make([]byte, 5)
    }
}

// input: aaaaaa
// output: [io.ReadFull]: "aaaaa" (5)

// input: aa\n\x00
// output: [io.ReadFull]: "aa\n\x00\x00" (3)

ReadFull 的目标是把p填满,也就是说正常情况下只有读到的数据长度nn==len(p)才返回。这里有两种情况需要注意:

  • 没有数据可读,ReadFull返回 (0, EOF)
  • 有一些数据可读,但在填满p前遇到了EOF,ReadFull返回 (读取的长度, ErrUnexpectedEOF)

bufio系列

bufio给io操作提供了一个缓冲,避免了每次都要访问磁盘。

Read

func bufioRead() {
    br := bufio.NewReader(os.Stdin)
    p := make([]byte, 5)
    for {
        nn, err := br.Read(p)
        if err != nil && err != io.EOF{
            panic(err)
        }
        fmt.Printf("[bufio.read]: %q (%d)\n", p, nn)
    }
}

// input: abcdefghijk
// output:
//[bufio.read]: "abcde" (5)
//[bufio.read]: "fghij" (5)
//[bufio.read]: "k\n\x00\x00\x00" (2)

最多读取len(p)大小的数据,如果输入的内容超出了len(p),则Read会在下一轮循环中接着读取。

ReadBytes

func bufioReadBytes() {
    br := bufio.NewReader(os.Stdin)
    for {
        p, err := br.ReadBytes('\n')
        if err != nil && err != io.EOF{
            panic(err)
        }
        fmt.Printf("[bufio.ReadBytes]: %q (%d)\n", p, len(p))
    }
}
// input: abcdef
// output: [bufio.ReadBytes]: "abcdef\n" (7)

ReadBytes 读取直到遇到给定的分界符,这里是'\n'(返回的p包含\n)。如果在读到分界符之前遇到了err,则返回读到的数据和err(一般是EOF)。

ReadString

func bufioReadString() {
    br := bufio.NewReader(os.Stdin)
    for {
        str, err := br.ReadString('\n')
        if err != nil && err != io.EOF {
            panic(err)
        }
        fmt.Printf("[bufio.ReadString]: %q (%d)\n", str, len(str))
    }
}

// input: abcdef
// output: [bufio.ReadString]: "abcdef\n" (7)

ReadString 与 ReadBytes 类似,都是直到读到分界符才返回。

ReadRune

func bufioReadRune() {
    br := bufio.NewReader(os.Stdin)
    for {
        r, sz, err := br.ReadRune()
        if err != nil && err != io.EOF {
            panic(err)
        }
        fmt.Printf("[bufio.ReadRune]: %q (%d)\n", r, sz)
    }
}

// input: abc
// output: 
//[bufio.ReadRune]: 'a' (1)
//[bufio.ReadRune]: 'b' (1)
//[bufio.ReadRune]: 'c' (1)
//[bufio.ReadRune]: '\n' (1)

ReadRune 一次读取一个UTF8字符。

Scan

func bufioScan() {
    scanner := bufio.NewScanner(os.Stdin)
    for scanner.Scan() {
        text := scanner.Text()
        fmt.Printf("[bufio.Scan]: %q (%d)\n", text, len(text))
    }
    if scanner.Err() != nil {
        fmt.Print(scanner.Err().Error())
    }
}

Scan 扫描文件到下一个token并返回true,随后可以通过Text,Bytes读取token。当扫描停止时,Scan返回false,这时可以通过Err获取错误,如果是因为EOF而扫描停止,Err=nil。

scanner在创建时,默认使用 ScanLines 作为分割函数。它会将输入文本分割成一系列的行,每行作为一个token。除此之外还有其他分割函数:

  • ScanLines(默认):按行分割。
  • ScanWords:按空白字符分割的单词。
  • ScanBytes:按字节分割。
  • ScanRunes:按UTF-8编码的字符分割。

总结

如果只是简单从stdin读取,fmt.Scan 足够短小好用。当文件很大时 io.ReadAll, io.ReadFull 感觉在使用时不是很灵活,还是推荐用bufio的一系列方法操作。

到此这篇关于Go语言读取文件的方法小结的文章就介绍到这了,更多相关Go读取文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用go进行云存储上传实现实例

    使用go进行云存储上传实现实例

    这篇文章主要为大家介绍了使用go进行云存储上传实例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪<BR>
    2024-01-01
  • golang logrus日志框架实例详解

    golang logrus日志框架实例详解

    logrus是一个可插拔的、结构化的日志框架,这篇文章主要介绍了golang logrus日志框架实例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • Golang的Crypto/SHA256库实战指南

    Golang的Crypto/SHA256库实战指南

    无论是在保护数据安全、验证数据完整性,还是在构建复杂的安全系统中,crypto/sha256都是Golang程序员不可或缺的工具,本文主要介绍了Golang的Crypto/SHA256库实战指南,感兴趣的可以了解一下
    2024-02-02
  • Go语言封装HTTP请求的Curl工具包详解

    Go语言封装HTTP请求的Curl工具包详解

    在 Go 语言开发中,与 HTTP 服务进行交互是非常常见的需求,本文将分享一个用 Go 语言封装的 Curl 工具包,它提供了简洁易用的接口来进行 HTTP 请求,需要的可以了解下
    2025-03-03
  • 重学Go语言之如何使用Redis

    重学Go语言之如何使用Redis

    Redis是我们开发应用程序中很常用的NoSQL数据库,那么在Go语言中要如何连接和操作Redis呢,在这篇文章中,我们就来一起来探究一下吧
    2023-08-08
  • Go语言exec包的具体使用

    Go语言exec包的具体使用

    在Go中执行外部命令、调用系统程序,核心就是使用标准库os/exec,它能启动进程、传递参数、读写输入输出、控制超时,是脚本化、自动化、调用第三方工具的必备能力,下面就来详细的介绍一下
    2026-06-06
  • Go语言空结构体详解

    Go语言空结构体详解

    本文主要介绍了Go语言空结构体详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • vscode配置go开发环境的实战过程

    vscode配置go开发环境的实战过程

    vscode配置go的开发环境很简单,下面这篇文章主要给大家介绍了关于vscode配置go开发环境的实战过程,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-06-06
  • golang中配置 sql.DB获得更好的性能

    golang中配置 sql.DB获得更好的性能

    这篇文章主要介绍了golang中如何配置 sql.DB获得更好的性能,在这篇文章中,我想准确解释这些设置的作用,并展示它们可能产生的(积极和消极)影响,需要的朋友可以参考下
    2023-10-10
  • goweb模板语法html/template

    goweb模板语法html/template

    ​在Go语言里, html/template 包主要用于安全地生成HTML输出,它能够有效防止跨站脚本攻击(XSS),借助模板语法将数据动态填充到HTML文件中,下面就来详细的介绍一下
    2026-02-02

最新评论