如何读取文本文件?

huangapple go评论110阅读模式
英文:

How to read a text file?

问题

我正在尝试使用Golang读取"file.txt"文件,并将其内容放入一个变量中。以下是我尝试过的代码:

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "log"
  6. )
  7. func main() {
  8. file, err := os.Open("file.txt")
  9. if err != nil {
  10. log.Fatal(err)
  11. }
  12. fmt.Print(file)
  13. }

文件成功读取,并且os.Open的返回类型是os.File

英文:

I'm trying to read "file.txt" and put the contents into a variable using Golang. Here is what I've tried...

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "log"
  6. )
  7. func main() {
  8. file, err := os.Open("file.txt")
  9. if err != nil {
  10. log.Fatal(err)
  11. }
  12. fmt.Print(file)
  13. }

The file gets read successfully and the return from os.Open returns a type of *os.File

答案1

得分: 131

这取决于你想要做什么。

  1. file, err := os.Open("file.txt")
  2. fmt.print(file)

它输出&{0xc082016240}是因为你打印的是文件描述符(*os.File)的指针值,而不是文件内容。要获取文件内容,你可以从文件描述符中进行读取。

要将文件的所有内容(以字节形式)读取到内存中,可以使用ioutil.ReadAll

  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "log"
  7. )
  8. func main() {
  9. file, err := os.Open("file.txt")
  10. if err != nil {
  11. log.Fatal(err)
  12. }
  13. defer func() {
  14. if err = file.Close(); err != nil {
  15. log.Fatal(err)
  16. }
  17. }()
  18. b, err := ioutil.ReadAll(file)
  19. fmt.Print(b)
  20. }

但是,有时候如果文件大小很大,只读取一部分(缓冲区大小)可能更节省内存,因此你可以使用*os.Fileio.Reader.Read实现。

  1. func main() {
  2. file, err := os.Open("file.txt")
  3. if err != nil {
  4. log.Fatal(err)
  5. }
  6. defer func() {
  7. if err = file.Close(); err != nil {
  8. log.Fatal(err)
  9. }
  10. }()
  11. buf := make([]byte, 32*1024) // 在这里定义你的缓冲区大小。
  12. for {
  13. n, err := file.Read(buf)
  14. if n > 0 {
  15. fmt.Print(buf[:n]) // 你的读取缓冲区。
  16. }
  17. if err == io.EOF {
  18. break
  19. }
  20. if err != nil {
  21. log.Printf("read %d bytes: %v", n, err)
  22. break
  23. }
  24. }
  25. }

另外,你还可以使用标准库bufio中的Scanner来处理文件。Scanner按分隔符将文件读取为标记。

默认情况下,Scanner使用换行符作为分隔符(当然你可以自定义Scanner如何将文件分词,可以从这里了解更多信息:bufio测试)。

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "log"
  6. "bufio"
  7. )
  8. func main() {
  9. file, err := os.Open("file.txt")
  10. if err != nil {
  11. log.Fatal(err)
  12. }
  13. defer func() {
  14. if err = file.Close(); err != nil {
  15. log.Fatal(err)
  16. }
  17. }()
  18. scanner := bufio.NewScanner(file)
  19. for scanner.Scan() { // 内部根据分隔符推进标记
  20. fmt.Println(scanner.Text()) // 以Unicode字符形式的标记
  21. fmt.Println(scanner.Bytes()) // 以字节形式的标记
  22. }
  23. }

最后,我还想向你推荐这个很棒的网站:Go语言文件速查表。它涵盖了与Go语言文件操作相关的几乎所有内容,希望你会觉得有用。

英文:

It depends on what you are trying to do.

  1. file, err := os.Open("file.txt")
  2. fmt.print(file)

The reason it outputs &{0xc082016240}, is because you are printing the pointer value of a file-descriptor (*os.File), not file-content. To obtain file-content, you may READ from a file-descriptor.


To read all file content(in bytes) to memory, ioutil.ReadAll

  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "log"
  7. )
  8. func main() {
  9. file, err := os.Open("file.txt")
  10. if err != nil {
  11. log.Fatal(err)
  12. }
  13. defer func() {
  14. if err = file.Close(); err != nil {
  15. log.Fatal(err)
  16. }
  17. }()
  18. b, err := ioutil.ReadAll(file)
  19. fmt.Print(b)
  20. }

But sometimes, if the file size is big, it might be more memory-efficient to just read in chunks: buffer-size, hence you could use the implementation of io.Reader.Read from *os.File

  1. func main() {
  2. file, err := os.Open("file.txt")
  3. if err != nil {
  4. log.Fatal(err)
  5. }
  6. defer func() {
  7. if err = file.Close(); err != nil {
  8. log.Fatal(err)
  9. }
  10. }()
  11. buf := make([]byte, 32*1024) // define your buffer size here.
  12. for {
  13. n, err := file.Read(buf)
  14. if n > 0 {
  15. fmt.Print(buf[:n]) // your read buffer.
  16. }
  17. if err == io.EOF {
  18. break
  19. }
  20. if err != nil {
  21. log.Printf("read %d bytes: %v", n, err)
  22. break
  23. }
  24. }
  25. }

Otherwise, you could also use the standard util package: bufio, try Scanner. A Scanner reads your file in tokens: separator.

By default, scanner advances the token by newline (of course you can customise how scanner should tokenise your file, learn from here the bufio test).

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "log"
  6. "bufio"
  7. )
  8. func main() {
  9. file, err := os.Open("file.txt")
  10. if err != nil {
  11. log.Fatal(err)
  12. }
  13. defer func() {
  14. if err = file.Close(); err != nil {
  15. log.Fatal(err)
  16. }
  17. }()
  18. scanner := bufio.NewScanner(file)
  19. for scanner.Scan() { // internally, it advances token based on sperator
  20. fmt.Println(scanner.Text()) // token in unicode-char
  21. fmt.Println(scanner.Bytes()) // token in bytes
  22. }
  23. }

Lastly, I would also like to reference you to this awesome site: go-lang file cheatsheet. It encompassed pretty much everything related to working with files in go-lang, hope you'll find it useful.

huangapple
  • 本文由 发表于 2016年3月20日 16:47:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/36111777.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定