HttpURLConnection下载网络图片

1.这样获取网络图片对应的文件流

要下载一张网络图片,比如百度的Logo图片,地址是:http://www.baidu.com/img/bdlogo.gif

当然也可能是你所在的局域网, 比如把OA内部办公系统的新闻图片下载到本机。这种情况下你就得

确定是否要通过代理才能访问外部网络了。但是不管哪种情况,下载图片其实很平常,就是为了获取InputStream流

然后读取流里面的内容,保存到本机或者图片服务器。怎么样才能获得这个流呢,可以想下平常我们上传图片是怎么实现的。

无非就是Form表单来一次POST提交,在后台你用Servlet就能获取到上载的文件流了。

因此你知道一张图片地址,就可以针对这个地址模拟一次表单请求,就能获取到这个图片资源对应的流了。

 

2.下载网络图片代码示例

package io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;

/**
 * 
 * 〈一个简单的下载网络图片工具类,可以下载内网或者代理下载外网图片〉
 *
 * @author yli
 */
public class HttpProxyUtil {

    public static void main(String[] args) throws MalformedURLException, IOException {

        // 下载图片,不经过代理
        // String url1 = "http://oa.xxx.com/infoResource/imgs/1.jpg";
        // String saveUrl1 = "src/io/oa.jpg";
        // downImgFromInetDemo(url1, saveUrl1, null);
        
        // 经过代理下载图片
        String host = "192.168.120.177";  
        int port = 34878;
        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port));
        String url2 = "http://www.baidu.com/img/bdlogo.gif";
        String saveUrl2 = "src/io/bdlogo.gif";
        downImgFromInetDemo(url2, saveUrl2, proxy);
    }

    /**
     * 
     * 〈下载网络图片方法示例〉
     *
     * @param targetUrl[要下载的图片对应的网络地址]
     * @param saveUrl[要保存的地址]
     * @param proxy [不通过代理下载就直接传递null进来]
     * @throws MalformedURLException
     * @throws IOException
     */
    public static void downImgFromInetDemo(String targetUrl, String saveUrl, Proxy proxy)
            throws MalformedURLException, IOException {

        // 读取InputStream字节流,将图片内容读取到一个字节数组
        // 该字节数组就可以重复利用
        byte[] imgBytes = getByteArrayFromInputStream(proxy, targetUrl);

        // 获取图片基本信息:大小、宽度、高度和格式
        ImageInfo targetImg = getImageInfoFromInputStream(imgBytes);
        targetImg.setSize(imgBytes.length);

        // 实例化一个符合业务要求的图片对象
        ImageInfo validImg = new ImageInfo();
        validImg.setSize(500 * 1024); // 最大允许500KB
        validImg.setWidth(1500); // 最宽允许 1500px
        validImg.setHeight(1200); // 最高允许1200px
        validImg.setValidTypes("jpg", "jpeg", "gif", "png", "bmp");

        // 校验图片是否符合业务要求
        if (targetImg.isValidImg(validImg)) {
            // 保存图片
            ByteArrayInputStream in = new ByteArrayInputStream(imgBytes);
            saveImgFromInputStream(in, saveUrl);
            System.out.println("===>图片符合要求,保存成功");
        } else {
            System.out.println("===>图片不符合要求!");
        }

        // 可以简单的打印图片基本信息
        System.out.println(targetImg);
        System.out.println(validImg);

    }

    /**
     * 
     * 〈将图片文件流转换成字节数组〉
     * 〈好处就是字节数组可以多次利用,而流一旦读取过一次之后就不能再使用了〉
     *
     * @param proxy
     * @param targetUrl
     * @return
     * @throws MalformedURLException
     * @throws IOException
     */
    private static byte[] getByteArrayFromInputStream(Proxy proxy, String targetUrl)
            throws MalformedURLException, IOException {
        HttpURLConnection urlConnection;
        if (null == proxy) {
            urlConnection = (HttpURLConnection) new URL(targetUrl).openConnection();
        } else {
            // 如果有代理则通过代理下载
            urlConnection = (HttpURLConnection) new URL(targetUrl).openConnection(proxy);
        }
        // 把文件写到字节数组保存起来
        BufferedInputStream bis = new BufferedInputStream(urlConnection.getInputStream());
        ByteArrayOutputStream fos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = bis.read(buffer)) != -1) {
            fos.write(buffer, 0, len);
        }
        byte[] bytes = fos.toByteArray();
        bis.close();
        fos.close();
        urlConnection.disconnect();
        return bytes;
    }
    
    /**
     * 
     * 〈将流保存至本机或者图片服务器〉
     *
     * @param in
     * @param saveUrl
     * @throws IOException
     */
    public static void saveImgFromInputStream(InputStream in, String saveUrl) throws IOException {
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(saveUrl));
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = in.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        bos.close();
        in.close();
    }

    /**
     * 
     * 〈如果你已经将图片文件流InputStream读取出来放到一个字节数组〉
     * 〈那么根据这个字节数组也是可以转换成对应的图片流,并再次获取图片基本信息〉
     *
     * @param imgBytes
     * @return
     */
    public static ImageInfo getImageInfoFromInputStream(byte[] imgBytes) {
        ByteArrayInputStream in = new ByteArrayInputStream(imgBytes);
        ImageInfo image = getImageInfoFromInputStream(in);
        return image;
    }
    
    /**
     * 
     * 〈从图片文件流读取图片文件的基本信息〉
     *
     * @param inputStream
     * @return
     */
    public static ImageInfo getImageInfoFromInputStream(InputStream inputStream) {
        ImageInputStream imgStream = null;
        try {
            // 创建Image流
            imgStream = ImageIO.createImageInputStream(inputStream);
            Iterator<ImageReader> iter = ImageIO.getImageReaders(imgStream);
            if (!iter.hasNext()) {
                return null;
            }
            // 读取流中一帧就可以获取到高宽以及各式
            ImageReader reader = iter.next();
            reader.setInput(imgStream, true);
            int width = reader.getWidth(0);
            int height = reader.getHeight(0);
            String type = reader.getFormatName();
            ImageInfo bean = new ImageInfo();
            bean.setWidth(width);
            bean.setHeight(height);
            bean.setType(type);
            return bean;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                imgStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

/**
 * 
 * 〈一般下载图片都会有一些简单的业务检验,比如大小格式等〉
 * 〈因此定义一个图片类,来描述图片的基本属性〉
 *
 * @author yli
 */
class ImageInfo {
    // 图片大小
    private long     size   = 0;
    // 图片宽度
    private int      width  = 0;
    // 图片高度
    private int      height = 0;
    // 图片类型
    private String   type   = "jpg";
    // 符号要求的图片类型
    private String[] validTypes;

    /**
     * 
     * 〈定义一个简单方法描述该图片是否符合要求〉
     *
     * @param validImg
     * @return
     */
    public boolean isValidImg(ImageInfo validImg) {
        if (null == validImg) {
            return true;
        }
        return (this.getSize() <= validImg.getSize()) && (this.getWidth() <= validImg.getWidth())
                && (this.getHeight() <= validImg.getHeight()) && isValidType(validImg);

    }

    private boolean isValidType(ImageInfo validImg) {
        if (null == validImg.getValidTypes()) {
            return true;
        }
        boolean isValid = false;
        for (String validType : validImg.getValidTypes()) {
            if (type.equalsIgnoreCase(validType)) {
                isValid = true;
                break;
            }
        }
        return isValid;
    }

    @Override
    public String toString() {
        return String.format("{size:%s,width:%s,height:%s,type:%s,validType:%s}", size, width,
                height, type, validTypeToString());
    }

    private String validTypeToString() {
        if (null == validTypes) {
            return "";
        }
        StringBuffer sb = new StringBuffer("[");
        for (String type : validTypes) {
            sb.append(type).append(" ");
        }
        sb.append("]");
        return sb.toString();
    }

    public long getSize() {
        return size;
    }

    public void setSize(long size) {
        this.size = size;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String[] getValidTypes() {
        return validTypes;
    }

    public void setValidTypes(String... types) {
        this.validTypes = types;
    }
}


3.通过代理下载网络图片的一些常见问题

(1)打开HttpURLConnection报401错误,一般来说说你发起的请求方式被拒绝

比如你发起的是 POST 请求,可能对方只能接受 GET 请求,通过这种设置你可以试试

urlConnection.setRequestMethod("GET");  或者 urlConnection.setRequestMethod("POST");

(2)打开HttpURLConnection报503错误,可能是你用Java模拟的表单请求,被对方拒绝

那你可以尝试就像浏览器发起请求一样,来欺骗下对方,这样设置试试

urlConnection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");

(3)打开HttpURLConnection报403错误,可能是你仅仅只设置了代理的地址和端口,没设置密码,可以这样试试

String headerKey = "Proxy-Authorization";
String headerValue = "Basic " + new BASE64Encoder().encode("你的用户名:你的密码".getBytes());
urlConnection.setRequestProperty(headerKey, headerValue);

这样还不行的话,再试试另外一种方式,先定义一个密码类

public class BasicAuthenticator extends Authenticator {
    String userName;
    String password;

    public BasicAuthenticator(String userName, String password) {
        this.userName = userName;
        this.password = password;
    }

    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(userName, password.toCharArray());
    }
}


然后再创建完urlConnection之后,设置一下访问的用户名和密码

urlConnection = (HttpURLConnection) new URL(url).openConnection(proxy);
Authenticator.setDefault(new BasicAuthenticator(userName, password));


 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值