我一直在尝试自己学习Go,但在尝试读取和写入普通文件时,我被难住了。

我可以到inFile, _:= os。Open(INFILE, 0,0),但实际上获取文件的内容没有意义,因为read函数以[]字节作为参数。

func (file *File) Read(b []byte) (n int, err Error)

当前回答

[]byte是字节数组的全部或部分的切片(类似于子字符串)。可以将切片看作一个值结构,它带有一个隐藏的指针字段,用于系统定位和访问数组(切片)的全部或部分,加上用于切片长度和容量的字段,您可以使用len()和cap()函数访问这些字段。

这里有一个工作的入门套件,它可以读取和打印二进制文件;您将需要更改inName字面值以引用系统上的一个小文件。

package main
import (
    "fmt";
    "os";
)
func main()
{
    inName := "file-rw.bin";
    inPerm :=  0666;
    inFile, inErr := os.Open(inName, os.O_RDONLY, inPerm);
    if inErr == nil {
        inBufLen := 16;
        inBuf := make([]byte, inBufLen);
        n, inErr := inFile.Read(inBuf);
        for inErr == nil {
            fmt.Println(n, inBuf[0:n]);
            n, inErr = inFile.Read(inBuf);
        }
    }
    inErr = inFile.Close();
}

其他回答

请注意。ioutil自Go 1.16起已弃用。

使用较新的Go版本,读取/写入文件或从文件中写入文件很容易。从文件中读取:

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    data, err := ioutil.ReadFile("text.txt")
    if err != nil {
        return
    }
    fmt.Println(string(data))
}

写入文件:

package main

import "os"

func main() {
    file, err := os.Create("text.txt")
    if err != nil {
        return
    }
    defer file.Close()

    file.WriteString("test\nhello")
}

这将覆盖文件的内容(如果文件不存在,则创建一个新文件)。

看看文档,似乎你应该声明一个类型为[]字节的缓冲区,并将其传递给read,然后读取到这么多字符,并返回实际读取的字符数(和一个错误)。

医生说

Read从文件中读取最多len(b)个字节。它返回读取的字节数和一个Error(如果有的话)。EOF的信号是一个零计数,err设置为EOF。

这样不行吗?

编辑:另外,我认为你可能应该使用bufio包中声明的Reader/Writer接口,而不是使用os包。

新方法

从Go 1.16开始,使用os。ReadFile将文件加载到内存中,并使用os。从内存写入文件的WriteFile (ioutil。ReadFile现在调用os。ReadFile,已弃用)。

小心操作系统。因为它将整个文件读入内存。

package main

import "os"

func main() {
    b, err := os.ReadFile("input.txt")
    if err != nil {
        log.Fatal(err)
    }

    // `b` contains everything your file has.
    // This writes it to the Standard Out.
    os.Stdout.Write(b)

    // You can also write it to a file as a whole.
    err = os.WriteFile("destination.txt", b, 0644)
    if err != nil {
        log.Fatal(err)
    }
}

你也可以使用FMT包:

package main

import "fmt"

func main(){
    file, err := os.Create("demo.txt")
    if err != nil {
        panic(err)
    }
    defer file.Close()
    
    fmt.Fprint(file, name)
}

让我们列出一个与Go 1兼容的列表,其中包括在Go中读写文件的所有方法。

因为文件API最近发生了变化,大多数其他答案都不适合Go 1。他们也想念bufio,这很重要。

在下面的例子中,我通过从文件中读取并写入目标文件来复制一个文件。

从基础开始

package main

import (
    "io"
    "os"
)

func main() {
    // open input file
    fi, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    // close fi on exit and check for its returned error
    defer func() {
        if err := fi.Close(); err != nil {
            panic(err)
        }
    }()

    // open output file
    fo, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    // close fo on exit and check for its returned error
    defer func() {
        if err := fo.Close(); err != nil {
            panic(err)
        }
    }()

    // make a buffer to keep chunks that are read
    buf := make([]byte, 1024)
    for {
        // read a chunk
        n, err := fi.Read(buf)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }

        // write a chunk
        if _, err := fo.Write(buf[:n]); err != nil {
            panic(err)
        }
    }
}

这里我用os。打开和操作。创建它们是os.OpenFile的方便包装器。我们通常不需要直接调用OpenFile。

注意处理EOF。Read尝试在每次调用时填充buf,并返回io。EOF作为错误,如果它达到文件的结束这样做。在这种情况下,buf仍将保存数据。对Read的后续调用返回0作为读取的字节数和相同的io。EOF作为错误。任何其他错误都会导致恐慌。

使用bufio

package main

import (
    "bufio"
    "io"
    "os"
)

func main() {
    // open input file
    fi, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    // close fi on exit and check for its returned error
    defer func() {
        if err := fi.Close(); err != nil {
            panic(err)
        }
    }()
    // make a read buffer
    r := bufio.NewReader(fi)

    // open output file
    fo, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    // close fo on exit and check for its returned error
    defer func() {
        if err := fo.Close(); err != nil {
            panic(err)
        }
    }()
    // make a write buffer
    w := bufio.NewWriter(fo)

    // make a buffer to keep chunks that are read
    buf := make([]byte, 1024)
    for {
        // read a chunk
        n, err := r.Read(buf)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }

        // write a chunk
        if _, err := w.Write(buf[:n]); err != nil {
            panic(err)
        }
    }

    if err = w.Flush(); err != nil {
        panic(err)
    }
}

Bufio在这里只是充当缓冲区,因为我们与数据没有太多关系。在大多数其他情况下(特别是文本文件),bufio非常有用,它为我们提供了一个很好的API,可以轻松灵活地读写,同时它在幕后处理缓冲。


注意:以下代码适用于较旧的Go版本(Go 1.15及之前)。事情发生了变化(ioutil自Go 1.16以来已弃用)。关于新方法,看看这个答案。

使用ioutil

package main

import (
    "io/ioutil"
)

func main() {
    // read the whole file at once
    b, err := ioutil.ReadFile("input.txt")
    if err != nil {
        panic(err)
    }

    // write the whole body at once
    err = ioutil.WriteFile("output.txt", b, 0644)
    if err != nil {
        panic(err)
    }
}

易如反掌!但只有在确定处理的不是大文件时才使用它。