doumowu7371 2015-05-20 01:42
浏览 46
已采纳

io.copyN在第一次不被调用时无法工作

I'm trying to download a image from a site, and the steps are as follow:

  • use http.Get to fetch the image
  • use os.Create to create a new file in current folder
  • use io.copyN to copy the image into the file

But it is weird if the io.CopyN is failed at the first time, it seems never success later

code fragment:

    download_again:
        copy_byte, copy_err := io.CopyN(file, res.Body, res.ContentLength)
        fmt.Fprintf(os.Stderr, "img(%s) size: %d
", name, res.ContentLength)
        if copy_err == nil && res.ContentLength == copy_byte {
            fmt.Fprintf(os.Stderr, "Success to download img(%s)[%f KB(%d B)]: %s
", img_url, float64(copy_byte)/1024, copy_byte, name)
        } else {
            if try_i > download_times {
                fmt.Fprintf(os.Stderr, "[fatal] fail to download img(%s) %s
", img_url, name)
                fout.WriteString(name + "
")
                return
            }
            fmt.Fprintf(os.Stderr, "error in download img(%s)[%f KB(%d B)]: %s, try %d times
", img_url, float64(copy_byte)/1024, copy_byte, name, try_i)
            try_i++
            goto download_again
        }

and the output message:

img(11085) size: 273047
error in download img(./style/images/dszp/11085.jpg)[171.447266 KB(175562 B)]: 11085 , try 1 times
img(11085) size: 273047
error in download img(./style/images/dszp/11085.jpg)[0.000000 KB(0 B)]: 11085 , try 2 times
img(11085) size: 273047
error in download img(./style/images/dszp/11085.jpg)[0.000000 KB(0 B)]: 11085, try 3 times
img(11085) size: 273047
error in download img(./style/images/dszp/11085.jpg)[0.000000 KB(0 B)]: 11085, try 4 times
img(11085) size: 273047
error in download img(./style/images/dszp/11085.jpg)[0.000000 KB(0 B)]: 11085, try 5 times
img(11085) size: 273047
error in download img(./style/images/dszp/11085.jpg)[0.000000 KB(0 B)]: 11085, try 6 times

Any help will be appreciated :)

  • 写回答

1条回答 默认 最新

  • duanqian6982 2015-05-20 03:49
    关注

    You need to retry the http request. (not just the io.CopyN)

    Here is a (mostly untested) implementation of a resumable download:

    func downloadFile(dst *os.File, url string, offset int64) (int64, error) {
        req, err := http.NewRequest("GET", url, nil)
        if err != nil {
            return 0, err
        }
        // try to use a range header
        if offset > 0 {
            req.Header.Set("Range", fmt.Sprintf("bytes=%d-", offset))
        }
        res, err := http.DefaultClient.Do(req)
        if err != nil {
            return 0, err
        }
        defer res.Body.Close()
    
        // some http servers don't support range, so in that case we discard the first
        // offset bytes
        if offset > 0 && res.StatusCode != http.StatusPartialContent {
            _, err = io.CopyN(ioutil.Discard, res.Body, offset)
            if err != nil {
                return offset, err
            }
        }
    
        n, err := io.CopyN(dst, res.Body, res.ContentLength)
        return offset + n, err
    }
    

    You can pass that function an offset and it will try to pick up from that point (either by telling the HTTP server, or by discarding the bytes). It also returns the progress you've made, so you can then wrap this function in a retry loop:

    func example() error {
        f, err := os.Create("/tmp/pkg.png")
        if err != nil {
            return err
        }
        defer f.Close()
    
        offset := int64(0)
        delay := time.Second
        // try 5 times
        for i := 0; i < 5; i++ {
            offset, err = downloadFile(f, "http://golang.org/doc/gopher/pkg.png", offset)
            if err == nil {
                return nil
            }
            // wait a little while before trying again
            time.Sleep(delay)
            delay *= 2
        }
        return fmt.Errorf("failed to download file after 5 tries")
    }
    

    Incidentally, you should really avoid using goto for loops.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 stm32代码移植没反应
  • ¥15 matlab基于pde算法图像修复,为什么只能对示例图像有效
  • ¥100 连续两帧图像高速减法
  • ¥15 组策略中的计算机配置策略无法下发
  • ¥15 如何绘制动力学系统的相图
  • ¥15 对接wps接口实现获取元数据
  • ¥20 给自己本科IT专业毕业的妹m找个实习工作
  • ¥15 用友U8:向一个无法连接的网络尝试了一个套接字操作,如何解决?
  • ¥30 我的代码按理说完成了模型的搭建、训练、验证测试等工作(标签-网络|关键词-变化检测)
  • ¥50 mac mini外接显示器 画质字体模糊