关于Java/Kotlin下载图片,图片打开不能显示问题探究
图片下载其实是个很简单的功能,通过IO流从在线地址获取流,之后将流输出到文件即可完成下载功能,但是,最近我发现某个网站中的图片下载成功,但是打开却是无法打开,这让我迷惑,百度上根本就没有人说清楚
今天,通过研究和朋友的讨论,终于是找到了答案,至于答案是什么,请耐心往下阅读~
问题出现
测试的图片地址为http://www.xbiquge.la/files/article/image/10/10489/10489s.jpg
下载图片代码Java版:
URL url = new URL("http://www.xbiquge.la/files/article/image/10/10489/10489s.jpg");
URLConnection connection=url.openConnection();//打开链接
InputStream inputStream = connection.getInputStream();
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(new File("e:\\test.jpg")));
int c;
byte[] temp = new byte[1024 * 2];//提供个缓冲区
while ((c = bufferedInputStream.read(temp)) != -1) {
bufferedOutputStream.write(temp,0,c);//读多少,写多少
}
bufferedOutputStream.close();
inputStream.close();
下载代码Kotlin版:
val file =File("e:\\test.jpg")
val openConnection = URL("http://www.xbiquge.la/files/article/image/10/10489/10489s.jpg").openConnection()
val bytes = openConnection.getInputStream().readBytes()
file.writeBytes(bytes)
我们通过上面的对比,明显可以看到Kotlin的代码比Java的要简洁不少
上面的代码都是没错,把图片下载下来,打开如下图显示

之后用浏览器打开,用另存为保存图片,图片是可以正常打开的
用迅雷测试,也是打不开,问题似乎找不到原因了
不甘心认输的我,去搜索了一下,添加了各种请求头,但还是无效,似乎到了死胡同了
原因
没办法,只好去向学习群里的大佬们请教了
“哎,这个图片还可以解压,里面有图片!”群里名为夜雨的网友说道。
?!我将图片的扩展名改为了zip,之后解压,果不其然发现了可以正常打开的图片

我们知道了下载下来的文件是个压缩包,这样问题也是得到了解决方法,但是,为什么会这样呢?
刚好和python的大佬聊到了这个问题,他试了一下,python可以正确获得到图片,为什么java就不行?经过讨论,从请求头发现了原因,如下图

原来是因为网站在响应的时候返回的是GZIP压缩过的文件流,而采用此方式的话可以减少用户浏览网页的等待时间
python和浏览器都是内置了自动解压缩的功能,所以,这就是为什么浏览器可以查看图片,python也可以得到正确图片的原因
解决方法
针对gzip文件流
这里我们只需要使用GZIPInputStream包装一下InputStream,之后再输出即可,这里我只贴kotlin版的代码,Java的话参考一下来改吧
val file =File("e:\\test.jpg")
val openConnection = URL("http://www.xbiquge.la/files/article/image/10/10489/10489s.jpg").openConnection()
val bytes = GZIPInputStream(openConnection.getInputStream()).readBytes()
file.writeBytes(bytes)
通用下载图片方法
由于我们所要下载的图片,可能服务器返回的是未压缩的图片,如果我们继续使用上面的方法就会报错
所以我们需要加个判断,判断输入流是否为压缩过的
这里我就直接封装成一个方法了
fun downloadImage(url: String, file: File): File {
val openConnection = URL(url).openConnection()
//防止某些网站跳转到验证界面
openConnection.addRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36")
//如果图片是采用gzip压缩
val bytes = if (openConnection.contentEncoding == "gzip") {
GZIPInputStream(openConnection.getInputStream()).readBytes()
} else {
openConnection.getInputStream().readBytes()
}
file.writeBytes(bytes)
return file
}
参考
How to check if InputStream is Gzipped? stackflow
关于Java/Kotlin下载图片,图片打开不能显示问题探究的更多相关文章
- Java和Android Http连接程序:使用java.net.URL 下载服务器图片到客户端
Java和Android Http连接程序:使用java.net.URL 下载服务器图片到客户端 本博客前面博文中利用org.apache.http包中API进行Android客户端HTTP连接的例子 ...
- Java使用URL类下载的图片不完整
问题 今天在使用URL类来下载网站中的图片的时候,出现了一个问题:下载的图片不完整,并且每次下载的图片大小也不是都相同,反正就是不完整. 问题代码如下: package cn.ganlixin.tes ...
- 批量下载网站图片的Python实用小工具
定位 本文适合于熟悉Python编程且对互联网高清图片饶有兴趣的筒鞋.读完本文后,将学会如何使用Python库批量并发地抓取网页和下载图片资源.只要懂得如何安装Python库以及运行Python程序, ...
- java画图程序_图片用字母画出来_源码发布_版本二
在上一个版本:java画图程序_图片用字母画出来_源码发布 基础上,增加了图片同比例缩放,使得大像素图片可以很好地显示画在Notepad++中. 项目结构: 运行效果1: 原图:http://imag ...
- java画图程序_图片用字母画出来_源码发布
在之前写了一篇blog:java画图程序_图片用字母画出来 主要是把一些调试的截图发布出来,现在程序调试我认为可以了(当然,你如果还想调试的话,也可以下载源码自己调试). 就把源码发布出来. 项目结构 ...
- Python爬虫下载美女图片(不同网站不同方法)
声明:以下代码,Python版本3.6完美运行 一.思路介绍 不同的图片网站设有不同的反爬虫机制,根据具体网站采取对应的方法 1. 浏览器浏览分析地址变化规律 2. Python测试类获取网页内容,从 ...
- 批量下载网站图片的Python实用小工具(下)
引子 在 批量下载网站图片的Python实用小工具 一文中,讲解了开发一个Python小工具来实现网站图片的并发批量拉取.不过那个工具仅限于特定网站的特定规则,本文将基于其代码实现,开发一个更加通用的 ...
- 【Python】【Nodejs】下载单张图片到本地,Python和Nodejs的比较
Python版本: # 下载单张图片到本地,看用时多少 import urllib.request import datetime starttime = datetime.datetime.now( ...
- 织梦dedecms 无法下载远程图片 fsockopen函数被禁用的解决方法
在linux服务器上fsockopen()函数被无情的禁用了(这其实是出于安全考虑,可以理解),下载远程图片的功能就没有办法使用了.找了一些资料之后,找到了解决方法,就是用stream_socket_ ...
随机推荐
- WordPress使用PHPMailer发送gmail邮件
wordpress使用phpmailer发送gmail邮件 0.保证用于gmail账号已经开启imap服务,且你能正常访问到gmail的smtp服务.(需要climb over the wall) 1 ...
- Filder配置及使用教程
https://www.cnblogs.com/woaixuexi9999/p/9247705.html
- ORM基础1
1.增删改查 .models.类.object.all() 获取所有对象->select * from 表 2.models.类.object.get(id=1) 获取id为1的对象->s ...
- 【实战】使用 Kettle 工具将 mysql 数据增量导入到 MongoDB 中
最近有一个将 mysql 数据导入到 MongoDB 中的需求,打算使用 Kettle 工具实现.本文章记录了数据导入从0到1的过程,最终实现了每秒钟快速导入约 1200 条数据.一起来看吧~ 一.K ...
- 客户端TNSPING通 连接出现ORA-12514错误
ORA-12514: TNS: 监听程序当前无法识别连接描述符中请求的服务,这是一个经常遇到的问题,可以按照以下步骤一步步解决 1.使用tnsping检测 tnsping可判断出以下两点(1)判断网络 ...
- python类型-字典
字典是python语言中唯一的映射类型,映射对象里哈希值(键,key)和指向的对象(值,value)是一对多的关系.一个字典对象是可变的,是一个容器类型,可存储任意个数的python对象,其中也可以包 ...
- [集训]FWT基础练习题
题意 给出n个长度为20的二进制数和数字k,每次询问给出一个二进制数,问从n个数中挑k个数(不能重复)的按位或能包含询问的组合有多少个.数字均小于等于5E5,1s. 思考 强行算出2^20个答案,再O ...
- [HAOI2015]树上操作(树链剖分)
[HAOI2015]树上操作(luogu) Description 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种: 操作 1 :把某个节点 x 的点权增 ...
- SpringBoot任务篇Ⅴ --- 异步任务、定时任务、邮件任务
Java的任务在项目中需要用到的地方很多,比如,每月月末的财务报表给财务部门,定时给领导发个邮件短信等等.这时候我们就需要用到任务了,任务调度本身涉及到多线程并发.运行时间规则制定和解析.场景保持与恢 ...
- django中navie time 和 aware time的使用和转换
在django中有关时间被分为navie time 和 aware time两种,前者指的是不带时区标记的时间格式,后者被认为是带有时区标记的时间格式.在django框架的setting.py文件中 ...