Golang,有没有更好的方法将一个整数文件读入数组中?

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

Golang, is there a better way read a file of integers into an array?

问题

我需要将一个包含整数的文件读入到一个数组中。我已经用以下代码实现了这个功能:

  1. package main
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. )
  7. func readFile(filePath string) (numbers []int) {
  8. fd, err := os.Open(filePath)
  9. if err != nil {
  10. panic(fmt.Sprintf("open %s: %v", filePath, err))
  11. }
  12. var line int
  13. for {
  14. _, err := fmt.Fscanf(fd, "%d\n", &line)
  15. if err != nil {
  16. fmt.Println(err)
  17. if err == io.EOF {
  18. return
  19. }
  20. panic(fmt.Sprintf("Scan Failed %s: %v", filePath, err))
  21. }
  22. numbers = append(numbers, line)
  23. }
  24. return
  25. }
  26. func main() {
  27. numbers := readFile("numbers.txt")
  28. fmt.Println(len(numbers))
  29. }

文件 numbers.txt 的内容如下:

  1. 1
  2. 2
  3. 3
  4. ...

ReadFile() 函数看起来有点长(可能是因为错误处理的原因)。

有没有更短、更符合 Go 语言习惯的方法来加载一个文件?

英文:

I need to read a file of integers into an array. I have it working with this:

  1. package main
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. )
  7. func readFile(filePath string) (numbers []int) {
  8. fd, err := os.Open(filePath)
  9. if err != nil {
  10. panic(fmt.Sprintf("open %s: %v", filePath, err))
  11. }
  12. var line int
  13. for {
  14. _, err := fmt.Fscanf(fd, "%d\n", &line)
  15. if err != nil {
  16. fmt.Println(err)
  17. if err == io.EOF {
  18. return
  19. }
  20. panic(fmt.Sprintf("Scan Failed %s: %v", filePath, err))
  21. }
  22. numbers = append(numbers, line)
  23. }
  24. return
  25. }
  26. func main() {
  27. numbers := readFile("numbers.txt")
  28. fmt.Println(len(numbers))
  29. }

The file numbers.txt is just:

  1. 1
  2. 2
  3. 3
  4. ...

ReadFile() seems too long (maybe because of the error handing).

Is there a shorter / more Go idiomatic way to load a file?

答案1

得分: 25

使用bufio.Scanner很方便。我还使用了io.Reader而不是使用文件名。通常这是一个很好的技巧,因为它允许代码在_任何_类似文件的对象上使用,而不仅仅是磁盘上的文件。这里它从一个字符串中“读取”。

  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "io"
  6. "strconv"
  7. "strings"
  8. )
  9. // ReadInts从r中读取以空格分隔的整数。如果有错误,它会返回到目前为止成功读取的整数以及错误值。
  10. func ReadInts(r io.Reader) ([]int, error) {
  11. scanner := bufio.NewScanner(r)
  12. scanner.Split(bufio.ScanWords)
  13. var result []int
  14. for scanner.Scan() {
  15. x, err := strconv.Atoi(scanner.Text())
  16. if err != nil {
  17. return result, err
  18. }
  19. result = append(result, x)
  20. }
  21. return result, scanner.Err()
  22. }
  23. func main() {
  24. tf := "1\n2\n3\n4\n5\n6"
  25. ints, err := ReadInts(strings.NewReader(tf))
  26. fmt.Println(ints, err)
  27. }
英文:

Using a bufio.Scanner makes things nice. I've also used an io.Reader rather than taking a filename. Often that's a good technique, since it allows the code to be used on any file-like object and not just a file on disk. Here it's "reading" from a string.

  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "io"
  6. "strconv"
  7. "strings"
  8. )
  9. // ReadInts reads whitespace-separated ints from r. If there's an error, it
  10. // returns the ints successfully read so far as well as the error value.
  11. func ReadInts(r io.Reader) ([]int, error) {
  12. scanner := bufio.NewScanner(r)
  13. scanner.Split(bufio.ScanWords)
  14. var result []int
  15. for scanner.Scan() {
  16. x, err := strconv.Atoi(scanner.Text())
  17. if err != nil {
  18. return result, err
  19. }
  20. result = append(result, x)
  21. }
  22. return result, scanner.Err()
  23. }
  24. func main() {
  25. tf := "1\n2\n3\n4\n5\n6"
  26. ints, err := ReadInts(strings.NewReader(tf))
  27. fmt.Println(ints, err)
  28. }

答案2

得分: 5

我会这样做:

  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "strconv"
  6. "strings"
  7. )
  8. // 最好让这样的函数返回错误,而不是自己处理错误。
  9. func readFile(fname string) (nums []int, err error) {
  10. b, err := ioutil.ReadFile(fname)
  11. if err != nil { return nil, err }
  12. lines := strings.Split(string(b), "\n")
  13. // 为了避免每次追加都重新分配内存,给切片分配容量。
  14. nums = make([]int, 0, len(lines))
  15. for _, l := range lines {
  16. // 当使用Split时,文件末尾会出现空行。
  17. if len(l) == 0 { continue }
  18. // 当我们确切知道要处理的内容时,Atoi更适合这个任务。Scanf是更通用的选项。
  19. n, err := strconv.Atoi(l)
  20. if err != nil { return nil, err }
  21. nums = append(nums, n)
  22. }
  23. return nums, nil
  24. }
  25. func main() {
  26. nums, err := readFile("numbers.txt")
  27. if err != nil { panic(err) }
  28. fmt.Println(len(nums))
  29. }
英文:

I would do it like this:

  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "strconv"
  6. "strings"
  7. )
  8. // It would be better for such a function to return error, instead of handling
  9. // it on their own.
  10. func readFile(fname string) (nums []int, err error) {
  11. b, err := ioutil.ReadFile(fname)
  12. if err != nil { return nil, err }
  13. lines := strings.Split(string(b), "\n")
  14. // Assign cap to avoid resize on every append.
  15. nums = make([]int, 0, len(lines))
  16. for _, l := range lines {
  17. // Empty line occurs at the end of the file when we use Split.
  18. if len(l) == 0 { continue }
  19. // Atoi better suits the job when we know exactly what we're dealing
  20. // with. Scanf is the more general option.
  21. n, err := strconv.Atoi(l)
  22. if err != nil { return nil, err }
  23. nums = append(nums, n)
  24. }
  25. return nums, nil
  26. }
  27. func main() {
  28. nums, err := readFile("numbers.txt")
  29. if err != nil { panic(err) }
  30. fmt.Println(len(nums))
  31. }

答案3

得分: 0

你使用 fmt.Fscanf 的解决方案是可以的。根据你的情况,当然还有其他几种方法可以实现。Mostafa 的技巧是我经常使用的一种(尽管我可能会使用 make 一次性分配结果。哎呀!划掉。他确实这样做了。),但是为了最大的控制力,你应该学习 bufio.ReadLine。请参考 https://stackoverflow.com/questions/6141604/go-readline-string 上的一些示例代码。

英文:

Your solution with fmt.Fscanf is fine. There are certainly a number of other ways to do though, depending on your situation. Mostafa's technique is one I use a lot (although I might allocate the result all at once with make. oops! scratch that. He did.) but for ultimate control you should learn bufio.ReadLine. See https://stackoverflow.com/questions/6141604/go-readline-string for some example code.

huangapple
  • 本文由 发表于 2012年3月26日 01:41:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/9862443.html
匿名

发表评论

匿名网友

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

确定