英文:
Is there a way to get transfer speed from io.Copy?
问题
我正在使用io.Copy将网络流复制到文件中。我想提取当前的传输速度,最好是以每秒字节数为单位。
res, err := http.Get(url)
if err != nil {
panic(err)
}
// 打开输出文件
out, err := os.OpenFile("output", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
panic(err)
}
// 关闭输出文件和响应体
defer out.Close()
defer func(Body io.ReadCloser) {
err := Body.Close()
if err != nil {
panic(err)
}
}(res.Body)
_, err := io.Copy(out, res.Body)
以上是代码部分,它将网络流复制到名为"output"的文件中。你可以使用io.Copy
函数来执行复制操作。要提取当前的传输速度,你需要使用其他方法来测量。
英文:
I am copying a network stream to a file using 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)
答案1
得分: 2
如评论中所述,整个传输速率可以在事后轻松计算,特别是在使用io.Copy
时。如果您想要实时跟踪传输速率,并在长时间文件传输过程中轮询结果,则需要进行一些额外的工作。
下面我概述了一个简单的io.Reader
包装器来跟踪整体传输速率。为了简洁起见,它不是goroutine安全的,但是可以很容易地使其安全。然后,您可以从另一个goroutine中轮询进度,而主要的goroutine负责读取。
您可以创建一个io.Reader
包装器,并使用它来跟踪第一次读取的时刻,然后跟踪未来的读取字节数。最终的结果可能如下所示:
r := NewRater(resp.Body) // io.Reader包装器
n, err := io.Copy(out, r)
log.Print(r) // stringer方法显示人类可读的“b/s”输出
要实现这个,可以采用以下方法:
type rate struct {
r io.Reader
count int64 // 可能有大文件(2GB+),所以不要使用int
start, end time.Time
}
func NewRater(r io.Reader) *rate { return &rate{r: r} }
然后我们需要包装器Read
来跟踪底层io.Reader
的进度:
func (r *rate) Read(b []byte) (n int, err error) {
if r.start.IsZero() {
r.start = time.Now()
}
n, err = r.r.Read(b) // 底层io.Reader读取
r.count += int64(n)
if err == io.EOF {
r.end = time.Now()
}
return
}
可以随时轮询当前速率,即使在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)
}
还有一个简单的Stringer
方法来显示b/s
:
func (r *rate) String() string {
n, d := r.Rate()
return fmt.Sprintf("%.0f b/s", float64(n)/(d.Seconds()))
}
注意:上述的io.Reader
包装器没有进行锁定操作,因此操作必须在同一个goroutine中进行。由于问题涉及到io.Copy
,所以可以做出这个安全的假设。
英文:
As noted in the comments - the entire transfer rate is easily computed after the fact - especially when using 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. For brevity, it is not goroutine safe, but would be trivial do make it so. And then one could poll from another goroutine the progress, while the main goroutine does the reading.
You can create a io.Reader
wrapper - and use that to track the moment of first read - and then track future read byte counts. 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:
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
:
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
:
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. Since the question relates to io.Copy
- then this is a safe assumption to make.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论