读取文本文件并将其存储为字符串数组(以及写入)

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

Read text file into string array (and write)

问题

读取(和写入)文本文件到字符串数组中的能力,我相信是一个相当常见的需求。当开始使用一种语言时,这也非常有用,因为最初不需要访问数据库。在Golang中存在这样的功能吗?
例如:

func ReadLines(sFileName string, iMinLines int) ([]string, bool) {

func WriteLines(saBuff[]string, sFilename string) (bool) { 

我更愿意使用现有的功能,而不是重复造轮子。

英文:

The ability to read (and write) a text file into and out of a string array is I believe a fairly common requirement. It is also quite useful when starting with a language removing the need initially to access a database. Does one exist in Golang?
e.g.

func ReadLines(sFileName string, iMinLines int) ([]string, bool) {

and

func WriteLines(saBuff[]string, sFilename string) (bool) { 

I would prefer to use an existing one rather than duplicate.

答案1

得分: 155

从Go1.1版本开始,有一个bufio.Scanner API可以轻松地从文件中读取行。考虑上面的示例,使用Scanner进行重写:

package main

import (
    "bufio"
    "fmt"
    "log"
    "os"
)

// readLines将整个文件读入内存,并返回其行的切片。
func readLines(path string) ([]string, error) {
    file, err := os.Open(path)
    if err != nil {
        return nil, err
    }
    defer file.Close()

    var lines []string
    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        lines = append(lines, scanner.Text())
    }
    return lines, scanner.Err()
}

// writeLines将行写入给定的文件。
func writeLines(lines []string, path string) error {
    file, err := os.Create(path)
    if err != nil {
        return err
    }
    defer file.Close()

    w := bufio.NewWriter(file)
    for _, line := range lines {
        fmt.Fprintln(w, line)
    }
    return w.Flush()
}

func main() {
    lines, err := readLines("foo.in.txt")
    if err != nil {
        log.Fatalf("readLines: %s", err)
    }
    for i, line := range lines {
        fmt.Println(i, line)
    }

    if err := writeLines(lines, "foo.out.txt"); err != nil {
        log.Fatalf("writeLines: %s", err)
    }
}
英文:

As of Go1.1 release, there is a bufio.Scanner API that can easily read lines from a file. Consider the following example from above, rewritten with Scanner:

package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
)

// readLines reads a whole file into memory
// and returns a slice of its lines.
func readLines(path string) ([]string, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var lines []string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}
	return lines, scanner.Err()
}

// writeLines writes the lines to the given file.
func writeLines(lines []string, path string) error {
	file, err := os.Create(path)
	if err != nil {
		return err
	}
	defer file.Close()

	w := bufio.NewWriter(file)
	for _, line := range lines {
		fmt.Fprintln(w, line)
	}
	return w.Flush()
}

func main() {
	lines, err := readLines("foo.in.txt")
	if err != nil {
		log.Fatalf("readLines: %s", err)
	}
	for i, line := range lines {
		fmt.Println(i, line)
	}

	if err := writeLines(lines, "foo.out.txt"); err != nil {
		log.Fatalf("writeLines: %s", err)
	}
}

答案2

得分: 137

注意:自Go 1.16起,ioutil已被弃用。

如果文件不太大,可以使用ioutil.ReadFilestrings.Split函数来实现:

content, err := ioutil.ReadFile(filename)
if err != nil {
    //处理错误
}
lines := strings.Split(string(content), "\n")

您可以阅读ioutilstrings包的文档。

英文:

Note: ioutil is deprecated as of Go 1.16.

If the file isn't too large, this can be done with the ioutil.ReadFile and strings.Split functions like so:

content, err := ioutil.ReadFile(filename)
if err != nil {
    //Do something
}
lines := strings.Split(string(content), "\n")

You can read the documentation on ioutil and strings packages.

答案3

得分: 34

无法更新第一个答案。无论如何,在Go1发布之后,有一些破坏性的变化,所以我更新如下所示:

package main

import (
    "os"
    "bufio"
    "bytes"
    "io"
    "fmt"
    "strings"
)

// 将整个文件读入内存,并将其存储为行的数组
func readLines(path string) (lines []string, err error) {
    var (
        file *os.File
        part []byte
        prefix bool
    )
    if file, err = os.Open(path); err != nil {
        return
    }
    defer file.Close()

    reader := bufio.NewReader(file)
    buffer := bytes.NewBuffer(make([]byte, 0))
    for {
        if part, prefix, err = reader.ReadLine(); err != nil {
            break
        }
        buffer.Write(part)
        if !prefix {
            lines = append(lines, buffer.String())
            buffer.Reset()
        }
    }
    if err == io.EOF {
        err = nil
    }
    return
}

func writeLines(lines []string, path string) (err error) {
    var (
        file *os.File
    )

    if file, err = os.Create(path); err != nil {
        return
    }
    defer file.Close()

    //writer := bufio.NewWriter(file)
    for _,item := range lines {
        //fmt.Println(item)
        _, err := file.WriteString(strings.TrimSpace(item) + "\n"); 
        //file.Write([]byte(item)); 
        if err != nil {
            //fmt.Println("debug")
            fmt.Println(err)
            break
        }
    }
    /*content := strings.Join(lines, "\n")
    _, err = writer.WriteString(content)*/
    return
}

func main() {
    lines, err := readLines("foo.txt")
    if err != nil {
        fmt.Println("Error: %s\n", err)
        return
    }
    for _, line := range lines {
        fmt.Println(line)
    }
    //array := []string{"7.0", "8.5", "9.1"}
    err = writeLines(lines, "foo2.txt")
    fmt.Println(err)
}
英文:

Cannot update first answer.
Anyway, after Go1 release, there are some breaking changes, so I updated as shown below:

package main

import (
    "os"
    "bufio"
    "bytes"
    "io"
    "fmt"
    "strings"
)

// Read a whole file into the memory and store it as array of lines
func readLines(path string) (lines []string, err error) {
    var (
        file *os.File
        part []byte
        prefix bool
    )
    if file, err = os.Open(path); err != nil {
        return
    }
    defer file.Close()

    reader := bufio.NewReader(file)
    buffer := bytes.NewBuffer(make([]byte, 0))
    for {
        if part, prefix, err = reader.ReadLine(); err != nil {
            break
        }
        buffer.Write(part)
        if !prefix {
            lines = append(lines, buffer.String())
            buffer.Reset()
        }
    }
    if err == io.EOF {
        err = nil
    }
    return
}

func writeLines(lines []string, path string) (err error) {
    var (
        file *os.File
    )

    if file, err = os.Create(path); err != nil {
        return
    }
    defer file.Close()

    //writer := bufio.NewWriter(file)
    for _,item := range lines {
        //fmt.Println(item)
        _, err := file.WriteString(strings.TrimSpace(item) + "\n"); 
        //file.Write([]byte(item)); 
        if err != nil {
            //fmt.Println("debug")
            fmt.Println(err)
            break
        }
    }
    /*content := strings.Join(lines, "\n")
    _, err = writer.WriteString(content)*/
    return
}

func main() {
    lines, err := readLines("foo.txt")
    if err != nil {
        fmt.Println("Error: %s\n", err)
        return
    }
    for _, line := range lines {
        fmt.Println(line)
    }
    //array := []string{"7.0", "8.5", "9.1"}
    err = writeLines(lines, "foo2.txt")
    fmt.Println(err)
}

答案4

得分: 19

你可以使用os.File(实现了io.Reader接口)和bufio包来实现。然而,这些包是根据固定的内存使用情况构建的(无论文件有多大),并且非常快速。

不幸的是,这使得将整个文件读入内存变得有些复杂。如果行的部分超过了行限制,你可以使用bytes.Buffer来连接行的部分。无论如何,我建议你在项目中直接使用行读取器(特别是如果你不知道文本文件有多大!)。但是如果文件很小,下面的示例可能对你足够了:

package main

import (
    "os"
    "bufio"
    "bytes"
    "fmt"
)

// 将整个文件读入内存并将其存储为行的数组
func readLines(path string) (lines []string, err os.Error) {
    var (
        file *os.File
        part []byte
        prefix bool
    )
    if file, err = os.Open(path); err != nil {
        return
    }
    reader := bufio.NewReader(file)
    buffer := bytes.NewBuffer(make([]byte, 1024))
    for {
        if part, prefix, err = reader.ReadLine(); err != nil {
            break
        }
        buffer.Write(part)
        if !prefix {
            lines = append(lines, buffer.String())
            buffer.Reset()
        }
    }
    if err == os.EOF {
        err = nil
    }
    return
}

func main() {
    lines, err := readLines("foo.txt")
    if err != nil {
        fmt.Println("Error: %s\n", err)
        return
    }
    for _, line := range lines {
        fmt.Println(line)
    }
}

另一种选择可能是使用io.ioutil.ReadAll一次性读取整个文件,然后按行进行切片。我没有给出一个明确的示例来将行写回文件,但基本上是一个os.Create()后面跟着一个类似示例中的循环(参见main())。

英文:

You can use os.File (which implements the io.Reader interface) with the bufio package for that. However, those packages are build with fixed memory usage in mind (no matter how large the file is) and are quite fast.

Unfortunately this makes reading the whole file into the memory a bit more complicated. You can use a bytes.Buffer to join the parts of the line if they exceed the line limit. Anyway, I recommend you to try to use the line reader directly in your project (especially if do not know how large the text file is!). But if the file is small, the following example might be sufficient for you:

package main

import (
    "os"
    "bufio"
    "bytes"
    "fmt"
)

// Read a whole file into the memory and store it as array of lines
func readLines(path string) (lines []string, err os.Error) {
    var (
        file *os.File
        part []byte
        prefix bool
    )
    if file, err = os.Open(path); err != nil {
        return
    }
    reader := bufio.NewReader(file)
    buffer := bytes.NewBuffer(make([]byte, 1024))
    for {
        if part, prefix, err = reader.ReadLine(); err != nil {
            break
        }
        buffer.Write(part)
        if !prefix {
            lines = append(lines, buffer.String())
            buffer.Reset()
        }
    }
    if err == os.EOF {
        err = nil
    }
    return
}

func main() {
    lines, err := readLines("foo.txt")
    if err != nil {
        fmt.Println("Error: %s\n", err)
        return
    }
    for _, line := range lines {
        fmt.Println(line)
    }
}

Another alternative might be to use io.ioutil.ReadAll to read in the complete file at once and do the slicing by line afterwards. I don't give you an explicit example of how to write the lines back to the file, but that's basically an os.Create() followed by a loop similar to that one in the example (see main()).

答案5

得分: 4

func readToDisplayUsingFile1(f *os.File){
defer f.Close()
reader := bufio.NewReader(f)
contents, _ := ioutil.ReadAll(reader)
lines := strings.Split(string(contents), '\n')
}

or

func readToDisplayUsingFile1(f *os.File){
defer f.Close()
slice := make([]string,0)

reader := bufio.NewReader(f)

for{

str, err := reader.ReadString('\n')
if err == io.EOF{
    break
}

    slice = append(slice, str)
}

}

英文:
func readToDisplayUsingFile1(f *os.File){
	defer f.Close()
	reader := bufio.NewReader(f)
	contents, _ := ioutil.ReadAll(reader)
	lines := strings.Split(string(contents), '\n')
}

or

func readToDisplayUsingFile1(f *os.File){
	defer f.Close()
	slice := make([]string,0)
	
	reader := bufio.NewReader(f)
	
	for{
	
	str, err := reader.ReadString('\n')
	if err == io.EOF{
		break
	}
	
		slice = append(slice, str)
	}

答案6

得分: 0

我更喜欢编写一个更简单的通用函数来从io.Reader中读取(io.Reader是任何可读数据流(包括文件、内存缓冲区、字符串和字节切片、HTTP请求体等)实现的通用接口)。

func ReadLines(r io.Reader) ([]string, error) {
    var lines []string
    s := bufio.NewScanner(r)
    for s.Scan() {
        lines = append(lines, s.Text())
    }
    if err := s.Err(); err != nil {
        return nil, err
    }
    return lines, nil
}

以下是使用字符串的示例。

const data = `
line 1
line 2
line 3	
`

lines, _ := ReadLines(strings.NewReader(data))
fmt.Println(lines)

在此处运行:https://go.dev/play/p/NcbEIVmGXpX

英文:

I prefer to write a simpler generic function to read from an io.Reader (the generic interface implemented by any readable data stream including files, memory buffers, strings and byte slices, http request body etc.

func ReadLines(r io.Reader) ([]string, error) {
	var lines []string
	s := bufio.NewScanner(r)
	for s.Scan() {
		lines = append(lines, s.Text())
	}
	if err := s.Err(); err != nil {
		return nil, err
	}
	return lines, nil
}

Example of its use with a string.

const data = `
line 1
line 2
line 3	
`

lines, _ := ReadLines(strings.NewReader(data))
fmt.Println(lines)

run it here: https://go.dev/play/p/NcbEIVmGXpX

huangapple
  • 本文由 发表于 2011年5月4日 21:27:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/5884154.html
匿名

发表评论

匿名网友

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

确定