功能:从服务器端下载一个文件到客户端的SD卡上
首先需要两个权限在AndroidManifest.xml中application前加入网络权限以及SD卡操作权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
然后是对SD操作代码
package com.example.down;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.os.Environment;
import android.util.Log;
public class SDFile {
private String SDPATH;
public String getSDPATH() {
return SDPATH;
}
public SDFile() {
// 得到当前外部存储设备的目录
// /SDCARD
SDPATH = Environment.getExternalStorageDirectory() + "/";
Log.d("SD", SDPATH);
}
/**
* 在SD卡上创建文件
*
* @throws IOException
*/
public File creatSDFile(String fileName) throws IOException {
File file = new File(SDPATH + fileName);
file.createNewFile();
return file;
}
/**
* 在SD卡删除文件
*
* @throws IOException
*/
public void deleteSDFile(String fileName) throws IOException {
File file = new File(SDPATH + fileName);
file.delete();
}
/**
* 删除SD卡重复文件
*
* @throws IOException
*/
public void sameNameFile(String fileName) throws IOException {
File file = new File(SDPATH + fileName);
if(file.exists()){
file.delete();
}
}
/**
* 在SD卡上创建目录
*
* @param dirName
*/
public File creatSDDir(String dirName) {
File dir = new File(SDPATH + dirName);
dir.mkdir();
return dir;
}
/**
* 判断SD卡上的文件夹是否存在
*/
public boolean isFileExist(String fileName) {
File file = new File(SDPATH + fileName);
return file.exists();
}
/**
* 将一个InputStream里面的数据写入到SD卡中
*/
public File writeToSD(String path, String fileName,
InputStream input) {
File file = null;
int length = 0;
OutputStream output = null;
try {
creatSDDir(path);
file = creatSDFile(path + fileName);
output = new FileOutputStream(file);
byte buffer[] = new byte[1024*4];
// 判断长度,切保证有值
while ((length = input.read(buffer, 0, buffer.length)) != -1) {
output.write(buffer, 0, length);
}
output.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
output.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return file;
}
}
最后编写与服务器交互部分的代码(下载代码)
package com.example.down;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class DownFile {
private URL url = null;
SDFile sdFile = new SDFile();
/**
* 下载主代码
* @param urlStr 服务器路径
* @param path 存储路径
* @param fileName 文件名
* @return 1:下载成功 0:下载失败
*/
public int downfile(String urlStr, String path, String fileName) {
String sdPath = path + fileName;
try {
sdFile.sameNameFile(sdPath);
try {
InputStream input = null;
input = getInputStream(urlStr);
//将InputStream里面的数据写入到SD卡中
File resultFile = sdFile.writeToSD(path, fileName,
input);
if (resultFile == null) {
return 0;
} else {
return 1;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return 0;
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
return 0;
}
}
// 由于得到一个InputStream对象是所有文件处理前必须的操作,所以将这个操作封装成了一个方法
public InputStream getInputStream(String urlStr) throws IOException {
InputStream is = null;
try {
url = new URL(urlStr);
HttpURLConnection urlConn = (HttpURLConnection) url
.openConnection();
urlConn.connect();
is = urlConn.getInputStream();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return is;
}
}
最后在前端调用下载主方法即可(注意,下载代码最好不要写在主线程里面,容易造成阻塞)
package com.example.down;
import java.util.Timer;
import java.util.TimerTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends Activity {
private Button bt = null;
DownFile httpDownLoader = new DownFile();
Timer timer = new Timer();
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
if (msg.what == 1) {
int result = httpDownLoader
.downfile(
"http://10.10.11.64:9000/TestServer/test.txt",
"assets/", "test.xml");
if (result == 0) {
Toast.makeText(MainActivity.this, "下载失败",
Toast.LENGTH_SHORT).show();
} else if (result == 1) {
Toast.makeText(MainActivity.this, "下载成功!",
Toast.LENGTH_SHORT).show();
}
}
super.handleMessage(msg);
}
};
TimerTask task = new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
Message msg = new Message();
msg.what = 1;
handler.sendMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt = (Button) findViewById(R.id.bt);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
timer.schedule(task, 1000);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
学习过程中遇到的问题需要注意:
主线程是UI线程,耗时的操作不要放在主线程中做,提到线程中去执行。另外发送这个anr的日志只能分析当前系统的CPU占用率,还可以去data/anr的目录下把trace.txt这个文件拷贝出来,在该文件中会写了产生anr的函数堆栈可以帮助分析 。
服务器端的文件需要放在webRoot下。