[英]Is there a way to get transfer speed from io.Copy?
I am copying a network stream to a file using io.Copy.我正在使用 io.Copy 将网络流复制到文件中。 I would like to extract the current speed, preferably in bytes per second, that the transfer is operating at.
我想提取传输运行的当前速度,最好以每秒字节数为单位。
res, err := http.Get(url)
if err != nil {
panic(err)
}
// Open output file
out, err := os.OpenFile("output", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
panic(err)
}
// Close output file as well as body
defer out.Close()
defer func(Body io.ReadCloser) {
err := Body.Close()
if err != nil {
panic(err)
}
}(res.Body)
_, err := io.Copy(out, res.Body)
As noted in the comments - the entire transfer rate is easily computed after the fact - especially when using io.Copy
.如评论中所述 - 事后很容易计算整个传输速率 - 特别是在使用
io.Copy
时。 If you want to track "live" transfer rates - and poll the results over a long file transfer - then a little more work is involved.如果您想跟踪“实时”传输速率 - 并在长时间文件传输中轮询结果 - 那么需要做更多的工作。
Below I've outlined a simple io.Reader
wrapper to track the overall transfer rate.下面我概述了一个简单的
io.Reader
包装器来跟踪整体传输速率。 For brevity, it is not goroutine safe, but would be trivial do make it so.为简洁起见,它不是 goroutine 安全的,但这样做是微不足道的。 And then one could poll from another goroutine the progress, while the main goroutine does the reading.
然后可以从另一个 goroutine 轮询进度,而主 goroutine 进行读取。
You can create a io.Reader
wrapper - and use that to track the moment of first read - and then track future read byte counts.您可以创建一个
io.Reader
包装器 - 并使用它来跟踪第一次读取的时刻 - 然后跟踪未来的读取字节数。 The final result may look like this:最终结果可能如下所示:
r := NewRater(resp.Body) // io.Reader wrapper
n, err := io.Copy(out, r)
log.Print(r) // stringer method shows human readable "b/s" output
To implement this, one approach:为了实现这一点,一种方法:
type rate struct {
r io.Reader
count int64 // may have large (2GB+) files - so don't use int
start, end time.Time
}
func NewRater(r io.Reader) *rate { return &rate{r: r} }
then we need the wrapper Read
to track the underlying io.Readers
progress:那么我们需要包装器
Read
来跟踪底层的io.Readers
进度:
func (r *rate) Read(b []byte) (n int, err error) {
if r.start.IsZero() {
r.start = time.Now()
}
n, err = r.r.Read(b) // underlying io.Reader read
r.count += int64(n)
if err == io.EOF {
r.end = time.Now()
}
return
}
the rate at any time can be polled like so - even before EOF
:任何时候的利率都可以像这样轮询——甚至在
EOF
之前:
func (r *rate) Rate() (n int64, d time.Duration) {
end := r.rend
if end.IsZero() {
end = time.Now()
}
return r.count, end.Sub(r.start)
}
and a simple Stringer
method to show b/s
:和一个简单的
Stringer
方法来显示b/s
:
func (r *rate) String() string {
n, d := r.Rate()
return fmt.Sprintf("%.0f b/s", float64(n)/(d.Seconds()))
}
Note: the above io.Reader
wrapper has no locking in place, so operations must be from the same goroutine.注意:上面的
io.Reader
包装器没有锁定,所以操作必须来自同一个 goroutine。 Since the question relates to io.Copy
- then this is a safe assumption to make.由于问题与
io.Copy
- 那么这是一个安全的假设。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.