手动实现
思路就是:先创立一个切片 而后通过Read办法操作源文件把数据读到切片中,而后再通过Write办法把切片外面的数据写到指标文件外面。
具体怎么应用呢?
举个例子:
如果我有一个文件test.txt,而后我想要把这个文件复制到destination.txt,就能够这样写:
package mainimport ( "fmt" "io" "os")func main() { // 拷贝文件 srcFile := "/Users/liberhome/GolandProjects/awesomeProject/I-package/April28_Go_io/test.txt" destFile := "destination.txt" total, err := copyFile1(srcFile, destFile) //函数的具体实现在上面 fmt.Println(total, err)}func copyFile1(srcFile, destFile string) (int, error) { //返回值是实现拷贝数据的字节数&err file1, err := os.Open(srcFile) //这里读 所以用open就足够了 if err != nil { return 0, err } file2, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE, os.ModePerm) //这里要写文件 所以须要用到OpenFile if err != nil { return 0, err } // 敞开文件 defer file1.Close() defer file2.Close() //读写文件 bs := make([]byte, 1024, 1024)//用make发明切片 n := -1 //每次读取的字节数 total := 0 //读取的总数量 for { n, err = file1.Read(bs) if err == io.EOF || n == 0 { fmt.Println("copy is complete") break } else if err != nil { fmt.Println("error happen") return total, err } total += n file2.Write(bs[:n]) } return total, nil}
当然了,这段代码不仅能够复制txt文件,其余类型,比方png什么的都不在话下,毕竟是通过字节传递的。
以上就是手动实现copy,当然这太麻烦了,理论工作中很少这么用,之所以放在这里,是为了更深层的了解他的实现原理,万变不离其宗,这就是宗。
接下来介绍一下理论罕用的
库函数实现
io.Copy()办法实现
func Copy(dst Writer, src Reader) (written int64, err error) {}
这个函数须要两个参数,第一个是向外写的目标对象,第二个是读进来的对象;返回值有两个,一个是复制的总数据量,一个是谬误。须要留神的是,如果胜利拷贝,返回值是nil 不是EOF。
具体怎么应用呢?
还是复制下面例子中的文件,代码如下
package mainimport ( "fmt" "io" "os")func main() { // 拷贝文件 srcFile := "/Users/liberhome/GolandProjects/awesomeProject/I-package/April28_Go_io/test.txt" destFile := "destination2.txt" //total, err := copyFile1(srcFile, destFile) //函数的具体实现在上面 total, err := copyFile2(srcFile, destFile) //函数的具体实现在上面 fmt.Println(total, err)}func copyFile1(srcFile, destFile string) (int, error) { //返回值是实现拷贝数据的字节数&err file1, err := os.Open(srcFile) //这里读 所以用open就足够了 if err != nil { return 0, err } file2, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE, os.ModePerm) //这里要写文件 所以须要用到OpenFile if err != nil { return 0, err } // 敞开文件 defer file1.Close() defer file2.Close() //读写文件 bs := make([]byte, 1024, 1024) n := -1 //每次读取的字节数 total := 0 //读取的总数量 for { n, err = file1.Read(bs) if err == io.EOF || n == 0 { fmt.Println("copy is complete") break } else if err != nil { fmt.Println("error happen") return total, err } total += n file2.Write(bs[:n]) } return total, nil}func copyFile2(srcFile, destFile string) (int64, error) { file1, err := os.Open(srcFile) //这里读 所以用open就足够了 if err != nil { return 0, err } file2, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE, os.ModePerm) //这里要写文件 所以须要用到OpenFile if err != nil { return 0, err } // 敞开文件 defer file1.Close() defer file2.Close() //就是在这里间接调用库函数~ return io.Copy(file2, file1)}
ioutil包的办法实现
然而因为ioutil包中的writeFile和readFile办法都是一次性读取再一次性写入,对大文件并不敌对,这里不再开展。
参考资料起源:bilibili