英文:
io.Copy() erase the Reader content
问题
package main
import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
)
func main() {
	file, err := os.Open("HelloWorld")
	if nil != err {
		fmt.Println(err)
	}
	defer file.Close()
	fileTo, err := os.Create("fileTo")
	if nil != err {
		fmt.Println(err)
	}
	defer fileTo.Close()
	_, err = io.Copy(fileTo, file)
	if nil != err {
		fmt.Println(err)
	}
	fileByteOne, err := ioutil.ReadAll(file)
	if nil != err {
		fmt.Println(err)
	}
	fmt.Println(fileByteOne)
}
io.Copy()函数会擦除文件内容,输出结果为:
[]
Copy(dst Writer, src Reader)函数会从src复制到dst,它会擦除src的内容。有没有办法避免擦除呢?
英文:
	package main
	import (
		"fmt"
		"io"
		"io/ioutil"
		"os"
	)
	func main() {
		file, err := os.Open("HelloWorld")
		if nil != err {
			fmt.Println(err)
		}
		defer file.Close()
		fileTo, err := os.Create("fileTo")
		if nil != err {
			fmt.Println(err)
		}
		defer file.Close()
		_, err = io.Copy(fileTo, file)
		if nil != err {
			fmt.Println(err)
		}
		fileByteOne, err := ioutil.ReadAll(file)
		if nil != err {
			fmt.Println(err)
		}
		fmt.Println(fileByteOne)
	}
io.Copy() will erase the file content, the output is :
[]
Copy(dst Writer, src Reader) copies from src to dst, it will erase the src content. Is there
any way to avoid erasing?
答案1
得分: 4
io.Copy(fileTo, file)不会擦除文件内容,但它会将读取位置移动到文件末尾(EOF),这意味着下一个ioutil.ReadAll()将从文件末尾开始读取。你可以在ioutil.ReadAll()之前关闭并重新打开file。另外,你有两个defer file.Close()实例,第二个应该是defer fileTo.Close()。或者,更简单的方法是使用SectionReader.Seek()进行重置,正如PeterSO的答案中所建议的那样。
 _, err = file.Seek(0, io.SeekStart)
这也在GoByExamples Reading Files中有说明:
没有内置的倒带功能,但
Seek(0, 0)可以实现这个目的。
(os.SEEK_SET在os常量中定义为0)
const SEEK_SET int = 0 // 相对于文件起始位置的偏移量
现在(2020年)已被弃用,并被io.SeekStart取代。另请参阅“Golang, a proper way to rewind file pointer”。
英文:
<!-- language-all: go -->
> io.Copy(fileTo, file) will erase the file content
It won't. But it will move the read position to EOF, meaning the next ioutil.ReadAll() will start at ... EOF.
You could close it and re-open 'file'before your ioutil.ReadAll().
By the way, you have two defer file.Close() instances: the second one should be defer  fileTo.Close().
Or, simpler, reset it with a SectionReader.Seek(), as suggested by PeterSO's answer.
 _, err = file.Seek(0, io.SeekStart)
It is also illustrated in GoByExamples Reading Files:
> There is no built-in rewind, but Seek(0, 0) accomplishes this.
(os.SEEK_SET is define in os constants, as 0)
const SEEK_SET int = 0 // seek relative to the origin of the file
Now (2020) deprecated and replaced with io.SeekStart.
See also "Golang, a proper way to rewind file pointer".
答案2
得分: 2
从文件的末尾重置到文件的开头,可以使用 seek 函数。例如:
package main
import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
)
func main() {
	file, err := os.Open("HelloWorld")
	if err != nil {
		fmt.Println(err)
	}
	defer file.Close()
	fileTo, err := os.Create("fileTo")
	if err != nil {
		fmt.Println(err)
	}
	defer fileTo.Close()
	_, err = io.Copy(fileTo, file)
	if err != nil {
		fmt.Println(err)
	}
	_, err = file.Seek(0, os.SEEK_SET) // 文件开头
	if err != nil {
		fmt.Println(err)
	}
	fileByteOne, err := ioutil.ReadAll(file)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(fileByteOne)
}
输出结果:
[72 101 108 108 111 44 32 87 111 114 108 100 33 10]
英文:
Reset from the end of the file to the start of the file with a seek. For example.
package main
import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
)
func main() {
	file, err := os.Open("HelloWorld")
	if err != nil {
		fmt.Println(err)
	}
	defer file.Close()
	fileTo, err := os.Create("fileTo")
	if err != nil {
		fmt.Println(err)
	}
	defer fileTo.Close()
	_, err = io.Copy(fileTo, file)
	if err != nil {
		fmt.Println(err)
	}
	_, err = file.Seek(0, os.SEEK_SET) // start of file
	if err != nil {
		fmt.Println(err)
	}
	fileByteOne, err := ioutil.ReadAll(file)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(fileByteOne)
}
Output:
[72 101 108 108 111 44 32 87 111 114 108 100 33 10]
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论