记录一次httpClient下载文件的坑

用httpClient模拟浏览器下载文件的代码,网上是很多的,自己copy了一个就高兴的用起来,下载了几百个文件之后,MD发现所有下载的文件都是损坏的、根本打不开,这TM就尴尬了啊,用浏览器下载是没问题的啊。

下面看一下当时用的代码:

 private static void down(String url, String path, int index) {

        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(url);
        // 这个地方根据浏览器里的内容复制过来
        httpGet.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
        httpGet.setHeader("Connection", "keep-alive");
        httpGet.setHeader("Cookie", "XXXXX浏览器里的cookie复制过来就可以");
        httpGet.setHeader("Host", "XX.XX.XX");


        try {
            CloseableHttpResponse response = httpclient.execute(httpGet);
            HttpEntity httpEntity = response.getEntity();
            InputStream in = httpEntity.getContent();

            String fileName = getFileName(response);


            File file = new File(path + fileName);

            FileOutputStream fOut = new FileOutputStream(file);

           // IOUtils.copy(in,fOut);

            byte[] buffer = new byte[4*1024];

            
            while (in.read(buffer) != -1) {
                fOut.write(buffer);
            }

            fOut.flush();
            in.close();
            fOut.close();


            System.out.println(index+"=============ok================" + path + fileName);

        } catch (IOException e) {
            e.printStackTrace();
        }


    }

坑就坑在这个地方:

while (in.read(buffer) != -1) {
    fOut.write(buffer);
}

httpClient传输过来的流不一定会每次把 byte[] buffer写满,这种写法在本地复制文件的时候是可以的,但是网络流上就会出大问题,也就是out.write()的起终点没有显示的指定而是默认取buffer.length,每次缓存基本上都是读不满的,所以导致写入大量的空流到文件中。这也长了个教训,以后在调用API的时候能显示指定的就不要用默认值,你不知道会出什么问题。

正确的写法是这样的:

int n = 0;
while ((n=in.read(buffer)) != -1) {
    fOut.write(buffer,0,n);
}

或者有工具类可以用 IOUtils.copy(in,out);这个方法里的实现是一样的。

 

另外:获取文件名的方法附上:

private static String getFileName(CloseableHttpResponse response) {

        String fileName = "";
        Header header = response.getFirstHeader("Content-disposition");
        //System.out.println(JSONObject.toJSONString(response));
        //System.out.println(JSONObject.toJSONString(header));
        if (header != null) {
            HeaderElement[] headerElements = header.getElements();
            NameValuePair nameValuePair = headerElements[0].getParameterByName("filename");
            fileName = nameValuePair.getValue();

            //System.out.println("============fileName==============" + fileName);

            //System.out.println(nameValuePair.getName());

        }
        return fileName;
    }

 

你可能感兴趣的:(java,功能实现,下载文件,httpclient,文件格式损坏)