我编写了一个函数,它使用 http.Get() 从 Nginx 服务器(与仅用于测试的获取文件的主机位于同一主机上)获取文件。代码是这样的:

res,err := http.Get(addr)  // addr is the file address on Nginx server 
defer res.Body.Close() 
 
for { 
    v := &vFile{path,0}    // path is the file path to write 
    bv :=bufio.NewWriterSize(v,1024*1024)  // Write 1MB each time 
    _, err:= io.Copy(bv,res.Body) 
    if err == nil { err = bv.Flush() } 
} 

vFile 和 Write 函数定义如下

type vFile struct { 
    path string 
    cur int64 
} 
func (wtr *vFile) Write(buf []byte) { 
    var f *os.File 
    if wtr.cur == 0 { f,wtr.err = os.Create(wtr.path) } 
    else { f,wtr.err = os.OpenFile(wtr.path,os.O_RDWR|os.O_APPEND,0666) } 
    _, err := f.WriteAt(buf,twr.path) 
} 

但是在高并发的情况下(比如并发数为500),大量的文件没有抓取完整,Nginx日志中HTTP响应为200,文件长度不正确:

"GET /videos/4b42d6e8e138233c7eb62939.mp4 HTTP/1.1" 200 37863424 "-" "Go 1.1 package http" "-" 

该文件的大小为 75273523 字节,而仅提取了 37863424 字节。如果我将大小从 1MB 更改为 32KB,情况会好很多,但仍有一些文件不完整。那么代码可能有什么问题?

请您参考如下方法:

在此函数中,您不会关闭 os.File。我怀疑这就是它出错的原因。

func (wtr *vFile) Write(buf []byte) { 
    var f *os.File 
    if wtr.cur == 0 { f,wtr.err = os.Create(wtr.path) } 
    else { f,wtr.err = os.OpenFile(wtr.path,os.O_RDWR|os.O_APPEND,0666) } 
    _, err := f.WriteAt(buf,twr.path) 
} 

如果没有发布完整的编译 gofmt-ed 示例!


评论关闭
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!