当前位置: 首页 > 科技观察

Go中复制文件的三种方式

时间:2023-03-13 05:54:01 科技观察

本文将向您展示如何使用Go编程语言复制文件。在Go中复制文件的方法有很多种,我只介绍三种最常见的方法:使用Go库中的io.Copy()函数调用,一次读取输入文件并将其写入另一个文件,以及使用缓冲区逐块复制文件。方法一:使用io.Copy()第一种方法是使用Go标准库的io.Copy()函数。在copy()函数的代码中可以找到它的实现逻辑,如下:funccopy(src,dststring)(int64,error){sourceFileStat,err:=os.Stat(src)iferr!=nil{return0,err}if!sourceFileStat.Mode().IsRegular(){return0,fmt.Errorf("%sisnotaregularfile",src)}source,err:=os.Open(src)iferr!=nil{return0,err}defersource.Close()destination,err:=os.Create(dst)iferr!=nil{return0,err}deferdestination.Close()nBytes,err:=io.Copy(destination,source)returnnBytes,err}首先,上面的代码为了保证可以打开读取做了两个判断:一是判断要复制的文件是否存在(os.Stat(src)),二就是判断是否是正规文件(sourceFileStat.Mode().IsRegular())。所有其余的都由io.Copy(destination,source)代码行完成。io.Copy()函数执行完毕后,会返回复制的字节数和复制过程中出现的第一条错误信息。在Go中,如果没有错误信息,错误变量的值为nil。您可以在io包的文档页面中了解有关io.Copy()函数的更多信息。运行cp1.go将产生以下输出:$goruncp1.go请提供两个命令行参数!$goruncp1.gofileCP.txt/tmp/fileCPCOPY复制了3826字节!$difffileCP.txt/tmp/fileCPCOPY这个方法已经很简单了,但是它没有为开发者提供灵活性。这并不总是一件坏事,但是,有时开发人员可能需要/想要告诉程序如何读取文件。方法二:使用ioutil.WriteFile()和ioutil.ReadFile()复制文件的第二种方法是使用ioutil.ReadFile()和ioutil.WriteFile()函数。第一个函数用于一次性将整个文件的内容读取到内存中的一个字节片中;第二个函数用于将字节片的内容写入磁盘文件。实现代码如下:input,err:=ioutil.ReadFile(sourceFile)iferr!=nil{fmt.Println(err)return}err=ioutil.WriteFile(destinationFile,input,0644)iferr!=nil{fmt.Println("Errorcreating",destinationFile)fmt.Println(err)return}上面的代码包括了两个if代码块(嗯,Go中程序是这样写的),程序的实际功能实际体现出来了在ioutil.ReadFile()和ioutil.WriteFile()这两行代码中。运行cp2.go,您将获得以下输出:$goruncp2.go请提供两个命令行参数!$goruncp2.gofileCP.txt/tmp/copyFileCP$difffileCP.txt/tmp/copyFileCP请注意,虽然此方法可以复制文件,但在复制大文件时可能效率不高。这是因为当文件很大时,ioutil.ReadFile()返回的字节切片可能会非常大。方法三:在Go中使用os.Read()和os.Write()复制文件第三种方法是下面介绍的cp3.go。它接受三个参数:输入文件名、输出文件名和缓冲区大小。cp3.go最重要的部分位于下面的for循环中,您可以在copy()函数中找到,如下所示:buf:=make([]byte,BUFFERSIZE)for{n,err:=source.Read(buf)iferr!=nil&&err!=io.EOF{returnerr}ifn==0{break}if_,err:=destination.Write(buf[:n]);}err!=nil{returnerr}}此方法使用os.Read()将输入文件的一小部分读入名为buf的缓冲区,然后使用os.Write()将该缓冲区的内容写入文件。当发生读取错误或到达文件末尾(io.EOF)时,复制过程将停止。运行cp3.go,你会得到如下输出:cp3.gofileCP.txt/tmp/buf2020CopyingfileCP.txtto/tmp/buf20在下面的benchmarks中,你会发现buffer的大小对cp3.go的性能影响很大。运行基准测试在本文的最后一部分,我将尝试比较这三个程序以及cp3.go在不同缓冲区大小下的性能(使用time(1)命令行工具)。以下输出显示复制500MB文件大小时cp1.go、cp2.go和cp3.go的性能比较:$ls-lINPUT-rw-r--r--1mtsoukstaff512000000Jun509:39INPUT$timegoruncp1.goINPUT/tmp/cp1复制了512000000字节!real0m0.980suser0m0.219ssys0m0.719s$timegoruncp2.goINPUT/tmp/cp2real0m1.139suser0m0.196ssys0m0.654s$timegoruncp3.goINPUT/tmp/cp31000000复制INPUTto/tmp/cp3real0m1.025suser0m0.195ssys0m0.486s我们可以看到这三个程序的性能非常接近,这意味着Go标准库函数的实现非常巧妙和充分优化。现在,让我们测试缓冲区大小如何影响cp3.go的性能!执行cp3.go,指定缓冲区大小分别为10、20、1000字节,在运行速度快的机器上复制一个500MB的文件。结果如下:$ls-lINPUT-rw-r--r--1mtsoukstaff512000000Jun509:39INPUT$timegoruncp3.goINPUT/tmp/buf1010CopyingINPUTto/tmp/buf10真正的6m39.721s用户1m18.457s系统5m19.186s$时间去运行cp3。goINPUT/tmp/buf2020将INPUT复制到/tmp/buf20real3m20.819s用户0m39.444ssys2m40.380s$timegoruncp3.goINPUT/tmp/buf10001000将INPUT复制到/tmp/buf1000real6s4.91用户0m1.001ssys0m3.986s我们可以看到缓冲区越大,cp3.go运行的越快,这或多或少符合预期。此外,复制缓冲区小于20字节的大文件可能会非常慢,应该避免。您可以在GitHub上找到cp1.go、cp2.go和cp3.go的Go代码。

最新推荐
猜你喜欢