android文件下载与保存

时间:2021-03-08 07:04:59

在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。那么现在把整个头显示出来看看它到底长什么样子:

android文件下载与保存

上面这个小图就是在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();
}
}

通过这个代码,我们就把响应头和文件内容全部显示到TextView中了。这个函数的handler使用来通知UI更新的,在MainActivity中有一个Hanler处理消息:

        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中。

效果如下:

android文件下载与保存

那么既然已经读到了文件的文件的内容,那下面就把这个文件保存起来。

保存文件

那么要把文件保存到哪里呢?

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看看这个文件内容是不是完整

至此,下载与保存文件就做完了,下载比上传还要简单一点吧。