关于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_ ...
随机推荐
- 2次方的期望dp
某一天WJMZBMR在打osu~~~但是他太弱逼了,有些地方完全靠运气:( 我们来简化一下这个游戏的规则 有n次点击要做,成功了就是o,失败了就是x,分数是按comb计算的,连续a个com ...
- NPOI导出Excel生成多个sheet
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
- C# 二分法的解读
注:一定是有序的数组,才可以使用这种算法,如果数组没有排序则先进行排序后再调用此方法. 1.二分法是做什么的呢? 当然是查找数组中的数据了,开个玩笑,哈哈哈. 2.为啥要用这种方式呢? 二分顾名思义, ...
- 匈牙利算法(Kuhn-Munkres)算法
这个算法有点难度,一般比较标准的描述网页上也有相关的描述,我在这里就简单的用十分通俗的语言给大家入个门 主要可以结合https://blog.csdn.net/zsfcg/article/detail ...
- 8.JavaSE之变量、常量、作用域
变量variable: 变量是什么:就是内存中开辟的可以变化的量! Java是一种强类型语言,每个变量都必须声明其类型. Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型,作用域 ...
- 设计模式(Java语言)- 工厂方法模式
前言 在介绍工厂方法模式之前,我们需要知道这个设计模式是什么,解决了什么样的问题?在上一篇博客 设计模式(Java语言)- 简单工厂模式 介绍了简单工厂模式,然后总结了简单工厂模式的缺点: 1.当新增 ...
- 2020年十大OA办公系统排行榜
最近几年办公信息化的不断发展,走向千家万户(企业),从刚开始的大型公司,政府企业到现在中小企业的加入,市场更加的庞大,产业前进很好,在协同办公这片市场中,有哪些公司独领风骚? 泛微OA:(www. ...
- Docker windows 容器启动失败 network not found
前几天由于重启了服务器,docker配置的网络出了些问题导致在docker容器中安装的mysql识别用户权限时发生错误.(从宿主机A以user身份 登入到容器B中安装的Mysql时,用户竟然不是use ...
- Shell命令整理
Shell命令 一.认识Shell 在Linux系统中,Shell充当着用户与Linux内核的桥梁,俗称壳保护着Linux内核,同时也负责完成用户与内核之间的交互. 当用户需要与内核交互时,将命令传递 ...
- c#数字图像处理(十三)图像开运算与闭运算
图像开运算与闭运算定义 二值图像开运算的数学表达式为: g(x, y)=open[f(x, y ), B]=dilate{erode[f(x, y),B],B} 二值图像的开运算事实上就是先作腐蚀运算 ...