package main
import (
"fmt"
"io"
"os"
)
func main() {
src, _ := os.Open("samples/1.mp4")
dst, _ := os.Create("samples/2.mp4")
nw, _ := io.Copy(dst, src)
fmt.Printf("nw = %d\n", nw)
}
package main
import (
"fmt"
"github.com/TwiN/go-color"
"github.com/langwan/langgo/helpers/os"
"math"
"strings"
)
type Listener struct {
}
func (l Listener) ProgressChanged(event *helper_os.ProgressEvent) {
if event.EventType == helper_os.TransferCompletedEvent {
fmt.Println("\nfinish")
} else {
progress(float64(event.ConsumedBytes) / float64(event.TotalBytes) * 100.0)
}
}
func main() {
listener := Listener{}
helper_os.CopyFileWatcher("samples/2.mp4", "samples/1.mp4", nil, &listener)
}
func progress(n float64) {
number := int(math.Round(n))
bar := strings.Repeat(" ", 100)
bar = strings.Replace(bar, " ", "=", number)
tag := fmt.Sprintf("%d%%", number)
if number >= 100 {
tag = "ok."
}
progress := fmt.Sprintf("%s [ %s%s%s ] %s%s\r", color.Green, color.Yellow, bar, color.Green, color.Purple, tag)
fmt.Print(progress)
}
func CopyFileWatcher(dst string, src string, buf []byte, listener IOProgressListener) (written int64, err error)
buf - 可以传 buf = nil 这时候内部会默认分配一个32K的 buf 实际上 io.Copy 内部也是32K,如果传入自定义buf会根据指定的大小来完成一次拷贝,但对于执行效率,没有决定性的影响,仅仅是影响回调的频率
func CopyFileWatcher(dst string, src string, buf []byte, listener IOProgressListener) (written int64, err error) {
var srcSize int64 = 0
defer func() {
if listener != nil {
if err != nil {
listener.ProgressChanged(&ProgressEvent{
ConsumedBytes: written,
TotalBytes: srcSize,
EventType: TransferFailedEvent,
})
} else {
listener.ProgressChanged(&ProgressEvent{
ConsumedBytes: written,
TotalBytes: srcSize,
EventType: TransferCompletedEvent,
})
}
}
}()
if buf == nil {
size := 32 * 1024
buf = make([]byte, size)
}
srcFile, err := os.Open(src)
if err != nil {
return written, fmt.Errorf("couldn't open source file: %s", err)
}
defer srcFile.Close()
srcStat, err := srcFile.Stat()
srcSize = srcStat.Size()
if err != nil {
return written, fmt.Errorf("source file stat: %s", err)
}
if listener != nil {
listener.ProgressChanged(&ProgressEvent{
ConsumedBytes: 0,
TotalBytes: srcSize,
EventType: TransferStartedEvent,
})
}
dstFile, err := os.Create(dst)
if err != nil {
return written, fmt.Errorf("couldn't open dest file: %s", err)
}
defer dstFile.Close()
for {
nr, er := srcFile.Read(buf)
if nr > 0 {
nw, ew := dstFile.Write(buf[0:nr])
if nw < 0 || nr < nw {
nw = 0
if ew == nil {
ew = ErrInvalidWrite
}
}
written += int64(nw)
if ew != nil {
err = ew
break
}
if nr != nw {
err = io.ErrShortWrite
break
}
}
if er != nil {
if er != io.EOF {
err = er
}
break
}
if listener != nil {
listener.ProgressChanged(&ProgressEvent{
ConsumedBytes: written,
TotalBytes: srcStat.Size(),
EventType: TransferDataEvent,
})
}
}
return written, err
}
代码 21-24 这个和 io.copyBuffer 是一致的 当 buf = nil 会自动创建一个 32 * 1024 的 buf 来提供读写缓存,提升 buf 大小只是影响 回调的频率,但对于花费的时间 影响不大