我一直在尝试自己学习Go,但是在尝试读取和写入普通文件时遇到了麻烦。
我可以说到最远inFile, _ := os.Open(INFILE, 0, 0)
,但是实际上获取文件的内容没有任何意义,因为read函数将a []byte
作为参数。
func (file *File) Read(b []byte) (n int, err Error)
我一直在尝试自己学习Go,但是在尝试读取和写入普通文件时遇到了麻烦。
我可以说到最远inFile, _ := os.Open(INFILE, 0, 0)
,但是实际上获取文件的内容没有任何意义,因为read函数将a []byte
作为参数。
func (file *File) Read(b []byte) (n int, err Error)
Answers:
让我们列出与Go 1兼容的清单,其中列出了在Go中读取和写入文件的所有方式。
由于文件API最近已更改,并且大多数其他答案不适用于Go1。他们也错过了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.Open
并且os.Create
它们是方便的包装器os.OpenFile
。我们通常不需要OpenFile
直接致电。
注意处理EOF。Read
尝试填充buf
每个调用,并io.EOF
在到达文件末尾时返回错误。在这种情况下buf
仍将保留数据。到随之而来的电话Read
返回零的字节数读取和同样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,可轻松灵活地进行读写,同时还能处理后台缓冲,因此非常有用。
使用 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)
}
}
非常简单!但是,只有在确定不处理大文件时才使用它。
panic("error in writing")
)中进行额外检查。
这是好版本:
package main
import (
"io/ioutil";
)
func main() {
contents,_ := ioutil.ReadFile("plikTekstowy.txt")
println(string(contents))
ioutil.WriteFile("filename", contents, 0644)
}
0x777
是假的。无论如何,它都应该更像0644
或0755
(八进制,而不是十六进制)。
使用 io.Copy
package main
import (
"io"
"log"
"os"
)
func main () {
// open files r and w
r, err := os.Open("input.txt")
if err != nil {
panic(err)
}
defer r.Close()
w, err := os.Create("output.txt")
if err != nil {
panic(err)
}
defer w.Close()
// do the actual work
n, err := io.Copy(w, r)
if err != nil {
panic(err)
}
log.Printf("Copied %v bytes\n", n)
}
如果您不想重新发明轮子,the io.Copy
和io.CopyN
可能会为您服务。如果您检查 io.Copy函数的源代码,那么它只是Go库中打包的Mostafa解决方案之一(实际上是“基本”解决方案)。但是,他们使用的缓冲区比他大得多。
w.Sync()
之后io.Copy(w, r)
io.Copy()
则只会写入与数据一起提供的数据,因此,如果现有文件中包含更多内容,则不会删除该文件,这可能会导致文件损坏。
w, err := os.Create("output.txt")
,您描述的内容将不会发生,因为“创建会创建或截断该命名文件。如果该文件已存在,则将其截断。” golang.org/pkg/os/#Create。
使用更新的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")
}
这将覆盖文件的内容(如果不存在则创建一个新文件)。
[]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();
}
if
块外部
尝试这个:
package main
import (
"io";
)
func main() {
contents,_ := io.ReadFile("filename");
println(string(contents));
io.WriteFile("filename", contents, 0644);
}
只是看一下文档,似乎您应该只声明[] byte类型的缓冲区并将其传递给read,然后它将读取多达这么多的字符并返回实际读取的字符数(以及错误)。
医生说
读取从文件中读取多达len(b)个字节。它返回读取的字节数和一个错误(如果有)。通过将err设置为EOF的零计数来发信号通知EOF。
那行不通吗?
编辑:另外,我认为您也许应该使用bufio包中声明的Reader / Writer接口,而不要使用os包。