如何在Go语言中读取二进制文件

36

我完全不了解 Go 语言,现在想要逐字节或逐段读取一个二进制文件。但是文档并没有提供很多帮助,我也找不到任何教程或简单的示例(顺便问一下,Google 怎么会给他们的语言起这样一个难以搜索的名字呢?)。基本上,我应该如何打开一个文件,并将一些字节读入缓冲区?有什么建议吗?


1
使用术语“golang”搜索谷歌会有所帮助。 - Daniel
1
https://dev59.com/aHI-5IYBdhLWcg3wf4hD - Vahid Farahmand
1
你可能会发现这个链接很有用。https://dev59.com/aHI-5IYBdhLWcg3wf4hD - Daniel
5个回答

32

对于文件操作来说,os包是你的好朋友:

f, err := os.Open("myfile")
if err != nil {
   panic(err)
}
defer f.Close()

若想更加精细地控制文件的打开方式,请参阅os.OpenFile()(doc))。

读取文件有多种方法。通过os.Open函数打开文件后返回的os.File类型对象(上述示例中的f),实现了io.Reader接口(拥有正确签名的Read()方法),可以直接用于将一些数据读入缓冲区(一个[]byte数组),或者也可以被包装在缓存读取器(bufio.Reader类型)中。

对于二进制数据,encoding/binary包可能很有用,可以将一系列字节读入某个特定类型的数据结构中。您可以在Go doc here中看到一个示例。由于如前所述,os.Open()返回的是一个io.Reader,因此可以使用binary.Read()函数与该函数读取的文件一起使用。

还有一个简单易用的io/ioutil包,允许您一次读取整个文件为字节切片(ioutil.ReadFile(),它需要一个文件名,因此您甚至不必自己打开/关闭文件),或者ioutil.ReadAll(),它需要一个io.Reader并返回包含整个文件的字节切片。这里是ioutil文档

最后,正如其他人提到的,您可以使用"golang"在谷歌上搜索关于Go语言的信息,应该会找到所有你所需要的。golang-nuts邮件列表也是寻找答案的好地方(在发布问题之前请确保首先进行搜索,因为很多东西已经有了答案)。要查找第三方软件包,请查看godoc.org网站。

希望对你有所帮助。


从Go 1.16开始,ioutil.ReadFile已被弃用。请使用os.ReadFile - Dmitrii I.

19

这是我用来将整个二进制文件读入内存的方法

func RetrieveROM(filename string) ([]byte, error) {
    file, err := os.Open(filename)

    if err != nil {
        return nil, err
    }
    defer file.Close()

    stats, statsErr := file.Stat()
    if statsErr != nil {
        return nil, statsErr
    }

    var size int64 = stats.Size()
    bytes := make([]byte, size)

    bufr := bufio.NewReader(file)
    _,err = bufr.Read(bytes)

    return bytes, err
}

8
为什么不直接使用 Go 语言 io/ioutil 包中的 func ReadFile(filename string) ([]byte, error) 函数呢? - peterSO
4
@djhworld很有趣,我正在用Go编写模拟器,搜索关于二进制文件的内容时偶然发现了你的答案;) - Rob Morgan
我建议不要使用 bytes 作为 []byte 的名称,因为这也是一个库的名称,也许取一些其他的名称会更好,比如 byteArray 或者其他类似的名称,除此之外,这个代码可以正常工作。 - Cesar Celis

10
例如,要计算文件中零字节的数量:
package main

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

func main() {
    f, err := os.Open("filename")
    if err != nil {
        fmt.Println(err)
        return
    }
    defer f.Close()
    data := make([]byte, 4096)
    zeroes := 0
    for {
        data = data[:cap(data)]
        n, err := f.Read(data)
        if err != nil {
            if err == io.EOF {
                break
            }
            fmt.Println(err)
            return
        }
        data = data[:n]
        for _, b := range data {
            if b == 0 {
                zeroes++
            }
        }
    }
    fmt.Println("zeroes:", zeroes)
}

3
你不能像在C语言中那样随意将基本类型转换为(char*),所以对于任何二进制数据的(反)序列化,请使用encoding/binary包。http://golang.org/pkg/encoding/binary。我无法改进那里的示例。

0
这是一个使用Read方法的示例:
package main

import (
   "io"
   "os"
)

func main() {
   f, e := os.Open("a.go")
   if e != nil {
      panic(e)
   }
   defer f.Close()
   for {
      b := make([]byte, 10)
      _, e = f.Read(b)
      if e == io.EOF {
         break
      } else if e != nil {
         panic(e)
      }
      // do something here
   }
}

https://golang.org/pkg/os#File.Read


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接