在android网络编程学习与实战之旅一中,实现了把一个或者多个文件上传的自己搭建的服务器中,那么这一节,显而易见的内容当然是怎么把文件下载下来。这里依旧使用java.net包中的HttpUrlConnection来实现。关于下载后的文件,可以有两种处理方式,一种是把它保存下来,另一种是把它显示出来,比如图片文字等可以下载后直接显示出来。
为了更具直观性的学习Android文件下载,这里首先尝试把一个txt格式的文件下载下来显示在TextView中。
那么,我想到的第一个问题是:我怎么获得下载文件的文件名?因为我要保存它,我得知道它的名字。
响应头里面有有文件名的信息吗?
首先声明一下,这里要下载的文件在自己搭建的apache更目录下的pic目录下,是一个hello.txt文件,它的URL是这样的:
http://192.168.0.103:8088/pic/hello.txt
为了解决这两个问题,这里首先读出响应头,也就是使用:
Map<String, List<String>> map = httpURLConnection.getHeaderFields();这个函数就是用来获取响应头的,它返回一个Map,key是一个字符串,values是一个List。那么现在把整个头显示出来看看它到底长什么样子:
上面这个小图就是在TextView中显示出来的响应头的信息,只要获得了它的响应头的这个Map,显示应该就没什么问题了吧,所以这里就不贴代码了,最后这个方法我会一并贴出来。
仔细找来找去,也没有找到任何关于filaname的信息,那怎么办呢?因为设置请求url的时候,里面已经包含了filename,所以暂时从它里面提取出来吧,大家谁有好办法欢迎留言。提取的代码很简单:
int location =requesl.lastIndexOf('/'); String filename = requesl.substring(location+1);这里的requesl就是url的字符串。
获取文件的内容就是读HttpUrlConnection下getInputStream这个流了,具体怎么读代码中有注释,现在把这个方法完整的贴出来:
public static void doDownLoadFile(Handler handler){ final String requesl = "http://192.168.0.103:8088/pic/hello.txt"; URL url = null; HttpURLConnection httpURLConnection = null; try { url = new URL(requesl); //1 提取url中的文件名 int location =requesl.lastIndexOf('/'); String filename = requesl.substring(location+1); //2.打开连接 httpURLConnection = (HttpURLConnection) url.openConnection(); //3 获得相应头 Map<String, List<String>> map = httpURLConnection.getHeaderFields(); Set<String> keySet = map.keySet(); StringBuilder builder = new StringBuilder(); builder.append("filename : "+filename+"\n"); List<String> values ; if (keySet != null){ for (String s:keySet ) { builder.append(s+":"); values = map.get(s); for (String ss:values ) { builder.append(ss); } builder.append("\n"); } } //4. 获得读入流 InputStream in = httpURLConnection.getInputStream(); //4.1获得文件长度 int length = Integer.valueOf(map.get("Content-Length").get(0)); byte []bbb = new byte[length]; //读出文件 in.read(bbb); String ssss = new String(bbb); builder.append(ssss); //通知UI更新 Message message = new Message(); Bundle bundle= new Bundle(); bundle.putString("name",builder.toString()); message.setData(bundle); handler.sendMessage(message); //关闭流 in.close(); httpURLConnection.disconnect(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
handler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { Log.d("hello",msg.getData().getString("name")); textView.setText(msg.getData().getString("name")); return true; } });在消息处理函数中获取Message中的数据,把它显示在TextView中。
效果如下:
那么既然已经读到了文件的文件的内容,那下面就把这个文件保存起来。
那么要把文件保存到哪里呢?
assets目录下肯定是不行的,因为它是只读的,SD卡貌似是个不错的选择,但是不是所有的手机都有SD卡。那这里就简单的保存在应用程序默认的文件目录下面吧。
public static void doSaveFileInDefaultFileDir(Context context,String filename,byte[] bb){ //1.首先判断文件是否存在,存在就什么都不做,不存在就保存它 File file = new File(context.getFilesDir(),filename); if(!file.exists()){ try { file.createNewFile(); FileOutputStream fout = new FileOutputStream(file); fout.write(bb); fout.close(); } catch (IOException e) { e.printStackTrace(); } } }
这就是我们的保存文件的函数,它非常简单,首先判断文件是否存在,不存在就创建一个。注意,创建的时候使用的是
context.getFilesDir(),它会获得/data/data/包名/files路劲,这个目录是应用程序私有的目录,应用程序又读写权限。
然后我们获取到这个文件的输出流,把我们从网络上读到的数据写入流中,最后关闭流就可以了。
注意:为了使用context.getFilesDir()函数,这里给这个函数加了一个Context的参数,那么在前面doDownLoadFile方法中也需要
加入这个参数声明。在调用doDownLoadFile方法的地方也不要忘了添加这个参数。
最后,使用adb shell命令进入手机看看文件是不是保存成功了。我这里使用的是android模拟器,它可以获得root权限:
1.adb shell
2.su
3.cd /data/data/com.konka.networktest/files
4.ls 就会发现这个文件已经存在了。
5.cat hello.txt看看这个文件内容是不是完整
至此,下载与保存文件就做完了,下载比上传还要简单一点吧。