OSS androidjava 断点续传传,不知道怎么上传文件写入内存,没有被回收掉

3431人阅读
OSS存储服务
详细介绍请查看官方sdk文档:
参考手机端:加入用户体验改进计划
实际就是抓取系统logcat[包括异常],通过该日志回传给开发者,参照用户使用日志对系统的作出有效的改进。
触发点:广播
该功能涉及到1.监听系统捕捉日志
2.把日志上传到服务器
具体做法:
【一】Oss的存储【IntentService】
     准备:OSSAndroid SDK
     提示:文中的ID指的是AccessKey
ID,KEY指的是AccessKey Secret
1.解压后在libs目录下得到jar包,目前包括aliyun-oss-sdk-android-2.2.0.jar、okhttp-    
&&&&& 3.2.0.jar、okio-1.6.0.jar
2.将以上3个jar包导入工程的libs目录
3.引入lib后在
   AndroidManifest.xml文件中配置这些权限
&!--广播请求的权限--&
&uses-permission android:name=&android.permission.RECEIVE_BOOT_COMPLETED& /&
&uses-permission
android:name=&android.permission.INTERNET&/&
&uses-permission android:name=&android.permission.ACCESS_NETWORK_STATE&/&
&uses-permission android:name=&android.permission.ACCESS_WIFI_STATE&/&
&uses-permission android:name=&android.permission.WRITE_EXTERNAL_STORAGE&/&
&uses-permission android:name=&android.permission.READ_EXTERNAL_STORAGE&/&
4.初始化OSSClient【来自SDK】
在IntentService中的onCreate()
初始化主要完成Endpoint设置、鉴权方式设置、Client参数设置。其中,鉴权方式包含明文设置模式、自签名模式、STS鉴权模式。鉴权细节详见后面的`访问控制`章节。
String endpoint = &http://oss-cn-&;
// 明文设置secret的方式建议只在测试时使用,更多鉴权模式请参考后面的`访问控制`章节
OSSCredentialProvider credentialProvider = new OSSPlainTextAKSKCredentialProvider(&&accessKeyId&&, &&accessKeySecret&&);
OSS oss = new OSSClient(getApplicationContext(), endpoint, credentialProvider);
以及需要创建断点记录文件夹
//断点数据保存的位置
Environment.getExternalStorageDirectory().getAbsolutePath() + &/oss_record/&;
File recordDir = new File(recordDirectory);
// 要保证目录存在,如果不存在则主动创建
if (!recordDir.exists()) {
recordDir.mkdirs();
5.初始化之后就可以通过OSS上传文件,这里上传采用的分片上传。也就是说在上传过程中如果遇到网络突然中断了,oss会作相对应的记录保存上传的进度。当下一次重新上传该文件的时候直接从上次保存的进度开始
在onHandleIntent(Intentintent)中除了接收intent传递过来的path外还需要判断断点记录,如果存在首先把上一次的上传完毕后再处理当前的
至于上传具体细节请看SDKorDEMO中
还需要在清单文件中:注册
&!--服务--&
&service android:name=&.myService&&&/service&
说明: 为何采用IntentService【一般采用它来下载,上传也不例外啦】
    IntentService是Service类的子类,用来处理异步请求。客户端可以通过startService(Intent)方法传递请求给IntentService。IntentService在onCreate()函数中通过HandlerThread单独开启一个线程来处理所有Intent请求对象(通过startService的方式发送过来的)所对应的任务,这样以免事务处理阻塞主线程。执行完所一个Intent请求对象所对应的工作之后,如果没有新的Intent请求达到,则自动停止Service;否则执行下一个Intent请求所对应的任务。
  IntentService在处理事务时,还是采用的Handler方式,创建一个名叫ServiceHandler的内部Handler,并把它直接绑定到HandlerThread所对应的子线程。&ServiceHandler把处理一个intent所对应的事务都封装到叫做onHandleIntent的虚函数;因此我们直接实现虚函数onHandleIntent,再在里面根据Intent的不同进行不同的事务处理就可以了。
6.扩展模块就是文件的下载:
  由于实际开发中暂时不考虑该问题,所以该模块暂未实现.
  如有需求参考上传功能 ossSDK中也提供了该接口 :
  //创建保存的文件路径
finalFile f1 = new File(filepath + name);
if(!f1.exists()) {
f1.delete();
。。。。。。。。.
//初始化oss
  。。。。。。。。
//构造下载文件请求
GetObjectRequestget = new GetObjectRequest(&fly&,&yao&span style=&display: width: 0 height: 0& id=&transmark&&&/span&/test.txt&);
OSSAsyncTasktask = oss.asyncGetObject(get, new    OSSCompletedCallback&GetObjectRequest,GetObjectResult&() {
publicvoid onSuccess(GetObjectRequest request, GetObjectResult result) {
//请求成功
//Log.d(&Content-Length&, && +getResult.getContentLength());
InputStreaminputStream = result.getObjectContent();
    //通过outputStream直接输出文件【保存到本地】
OutputStreamos =
   //byte[1024]这个长度主要看文件大小来定
byte[]buffer = new byte[1024];
os= new FileOutputStream(f1);
while((len = inputStream.read(buffer)) != -1) {
//处理下载的数据
os.write(buffer,0, len);
}catch (IOException e) {
e.printStackTrace();
if(inputStream!=null) {
inputStream.close();
}catch (IOException e) {
e.printStackTrace();
if(os!=null);
os.close();
}catch (IOException e) {
e.printStackTrace();
publicvoid onFailure(GetObjectRequest request, ClientExceptionclientExcepion, ServiceException serviceException) {
//请求异常
if(clientExcepion != null) {
//本地异常如网络异常等
clientExcepion.printStackTrace();
if(serviceException != null) {
//服务异常
Log.e(&ErrorCode&,serviceException.getErrorCode());
Log.e(&RequestId&,serviceException.getRequestId());
Log.e(&HostId&,serviceException.getHostId());
Log.e(&RawMessage&,serviceException.getRawMessage());
::其他的一些逻辑问题暂时不作判断。
【二】广播接收者
1.主要是接收处理logcat广播,启动服务。
2.注册:&!--广播--&静态注册:需要实时等待接收广播
&receiver android:name=&.myReceiver& android:exported=&true&&
&intent-filter&
&!--接收开机发送的广播--&
&action    android:name=&android.intent.action.BOOT_COMPLETED&&&/action&
&/intent-filter&
&intent-filter&
&action android:name=&fly.upload.logcat&&&/action&
&/intent-filter&
&intent-filter&
&action android:name=&fly.upload.logcat.isok&&&/action&
&/intent-filter&
&/receiver&
2.扩展模块:网络的监听,文件的监听
       网络监听:当没有网络的时候不开启服务,直接保存记录,发现有有网络的时候自动启动服务
       文件监听:监听本地断点文件记录有没有发生变化
【三】UI
   声明:(这个不是必须的)
   正常情况下个人认为在车机设置里添加
   这一项会比较人性化。
   应为考虑到上传可能需要使用用户的流量,在用户不知情下有必要提醒用户
   可以设置该功能默认是启动的。
   也就是说默认情况下是在监听用户使用情况。
   如果用户不开启该功能则不在上传日志文件。
                  
【oss附加功能】
1.在oss初始化化的时候还可以:
设置网络参数
也可以在初始化的时候设置详细的ClientConfiguration:
String endpoint = &http://oss-cn-&;// 明文设置secret的方式建议只在测试时使用,更多鉴权模式请参考后面的访问控制章节OSSCredentialProvider credentialProvider = new OSSPlainTextAKSKCredentialProvider(&&accessKeyId&&, &&accessKeySecret&&);
ClientConfiguration conf = new ClientConfiguration();
conf.setConnectionTimeout(15 * 1000); // 连接超时,默认15秒conf.setSocketTimeout(15 * 1000); // socket超时,默认15秒conf.setMaxConcurrentRequest(5); // 最大并发请求书,默认5个conf.setMaxErrorRetry(2); // 失败后最大重试次数,默认2次OSS oss = new OSSClient(getApplicationContext(), endpoint, credentialProvider, conf);
STS鉴权模式
OSS可以通过阿里云STS服务,临时进行授权访问。阿里云STS(Security
Token Service) 是为云计算用户提供临时访问令牌的Web服务。通过STS,您可以为第三方应用或联邦用户(用户身份由您自己管理)颁发一个自定义时效和权限的访问凭证,App端称为FederationToken。第三方应用或联邦用户可以使用该访问凭证直接调用阿里云产品API,或者使用阿里云产品提供的SDK来访问云产品API。
您不需要透露您的长期密钥(AccessKey)给第三方应用,只需要生成一个访问令牌并将令牌交给第三方应用即可。这个令牌的访问权限及有效期限都可以由您自定义。
您不需要关心权限撤销问题,访问令牌过期后就自动失效。
以APP应用为例,交互流程如下图:
方案的详细描述如下:
App用户登录。App用户身份是客户自己管理。客户可以自定义身份管理系统,也可以使用外部Web账号或OpenID。对于每个有效的App用户来说,AppServer可以确切地定义出每个App用户的最小访问权限。
AppServer请求STS服务获取一个安全令牌(SecurityToken)。在调用STS之前,AppServer需要确定App用户的最小访问权限(用Policy语法描述)以及授权的过期时间。然后通过调用STS的AssumeRole(扮演角色)接口来获取安全令牌。角色管理与使用相关内容请参考《RAM使用指南》中的。
STS返回给AppServer一个有效的访问凭证,App端称为FederationToken,包括一个安全令牌(SecurityToken)、临时访问密钥(AccessKeyId,AccessKeySecret)以及过期时间。
AppServer将FederationToken返回给ClientApp。ClientApp可以缓存这个凭证。当凭证失效时,ClientApp需要向AppServer申请新的有效访问凭证。比如,访问凭证有效期为1小时,那么ClientApp可以每30分钟向AppServer请求更新访问凭证。
ClientApp使用本地缓存的FederationToken去请求AliyunService
API。云服务会感知STS访问凭证,并会依赖STS服务来验证访问凭证,并正确响应用户请求。
【工作总结】
   从服务器上传下载文件这类型的开发,分2类把。
   第一类是第三方服务器【比如:阿里云,mbon等等】这些都有相对应的SDK 所有使用起来也挺方便 都为开发者提供了相对完整的框架 接口。开发者只需要申请对应的账号,获得相对应的key秘钥,把第三方的SDK引入到工程等,接着就是调用接口对数据库的增删改查了
   第二类就是自己搭建的本地服务器
MainActivity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
switchListener();
* 主要是对Switch控件的监听
* 事件的状态对应服务,广播的开启
* @author yao
* @time 16-7-12 下午5:34
private void switchListener() {
Switch aSwitch = (Switch) findViewById(R.id.switch1);
aSwitch.setChecked(false);
if (myApplication.SWITCH_ON.equals(SPUtils.readData(myApplication.SPUTILS_NAME,myApplication.SPUTILS_KEY))) {
aSwitch.setChecked(true);
aSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
Toast.makeText(MainActivity.this,myApplication.SWITCH_POINT, Toast.LENGTH_SHORT).show();
SPUtils.writeData(myApplication.SPUTILS_NAME,myApplication.SPUTILS_KEY, myApplication.SWITCH_ON);
initReceiver();
SPUtils.writeData(myApplication.SPUTILS_NAME,myApplication.SPUTILS_KEY, myApplication.SWITCH_OFF);
destoryReceiver();
* @author yao
* @time 16-7-12 下午6:53
private void destoryReceiver() {
Intent mintent = new Intent();
mintent.setAction(&fly.upload.logcat.isok&);
sendBroadcast(mintent);
*启动广播【开机状态】【触发事件】
* @author yao
* @time 16-7-12 下午5:37
* 需要传递文件路径 才能上传服务器
private void initReceiver() {
Log.d(&123321&, &initReceiver: 启动广播&);
Intent intent = new Intent();
intent.putExtra(&path&, &null&);
intent.setAction(&fly.upload.logcat&);
this.sendBroadcast(intent);
&android.support.v7.widget.CardView
android:elevation=&10dp&
android:layout_margin=&20dp&
android:layout_width=&match_parent&
android:layout_height=&56dp&&
android:layout_marginTop=&10dp&
android:layout_marginLeft=&20dp&
android:gravity=&center|left&
android:layout_width=&match_parent&
android:layout_height=&38dp&
android:text=&加入用户体验改进计划&
android:id=&@+id/switch1&
android:layout_gravity=&right& /&
&/android.support.v7.widget.CardView&
android:gravity=&center_horizontal&
android:textSize=&16sp&
android:text=&说明:这是一个 上传服务\n
通过广播和服务把文件提交到服务器中\n
广播地址:fly.upload.logcat\n
并且需要传文件路径\n
intent.setAction(‘fly.upload.logcat’);\n
intent.putExtra(key,value);\n
sendBroadcast(intent);\n&
android:layout_width=&match_parent&
android:layout_height=&wrap_content& /&
public void onReceive(Context context, Intent intent) {
Intent mintent = new Intent(context, myService.class);
if ((&ON&.equals(SPUtils.readData(&CONFIG&,&LOGIN&)))&&intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
//开机启动服务
mintent.putExtra(&path&, &&);
context.startService(mintent);
if ((&ON&.equals(SPUtils.readData(&CONFIG&,&LOGIN&)))&&intent.getAction().equals(&fly.upload.logcat&)) {
String path = intent.getExtras().getString(&path&);
if (!path.equals(&null&)) {
mintent.putExtra(&path&, path);
context.startService(mintent);
public class myService extends IntentService{
private OSS oss;
private String recordDirectory;
private String action;
public myService() {super(&myService&);}
public IBinder onBind(Intent intent) {return super.onBind(intent);}
//初始化oss工作
public void onCreate() {init();super.onCreate();}
* 注意点:
* 这里采用明文模式
* 实际中不可以采用
private void init() {
String endpoint = &http://oss-cn-&;
// 明文设置AccessKeyId/AccessKeySecret的方式建议只在测试时使用
OSSCredentialProvider credentialProvider = new OSSPlainTextAKSKCredentialProvider(&jSSSSS65SSSSS51&, &SSSSDADASDSDSDSDASDDt&);
oss = new OSSClient(getApplicationContext(), endpoint, credentialProvider);
//断点数据保存的位置
recordDirectory = Environment.getExternalStorageDirectory().getAbsolutePath() + &/oss_record/&;
File recordDir = new File(recordDirectory);
// 要保证目录存在,如果不存在则主动创建
if (!recordDir.exists()) {
recordDir.mkdirs();
protected void onHandleIntent(Intent intent) {
//Intent是从Activity发过来的,携带识别参数,根据参数不同执行不同的任务
action = intent.getExtras().getString(&path&);
String s = SPUtils.readData(&PATH&, &OLD&);
//判断上一次是否存在没有上传完毕的数据,如果存在着首先上传,否则直接上传本次数据
if (!&&.equals(s)) {
upLoad(s);
upLoad(action);
//上传服务
private void upLoad(final String path) {
// 创建断点上传请求,参数中给出断点记录文件的保存位置,需是一个文件夹的绝对路径 具体看sdk
ResumableUploadRequest request = new ResumableUploadRequest(&fly&, &fly/&+path, path, recordDirectory);
// 设置上传过程回调
request.setProgressCallback(new OSSProgressCallback&ResumableUploadRequest&() {
public void onProgress(ResumableUploadRequest request, long currentSize, long totalSize) {
//因为没有涉及到ui 这里不处理
Log.d(&123321&, &onProgress: &+currentSize);
OSSAsyncTask resumableTask = oss.asyncResumableUpload(request, new OSSCompletedCallback&ResumableUploadRequest, ResumableUploadResult&() {
public void onSuccess(ResumableUploadRequest request, ResumableUploadResult result) {
//成功后重置记录
if (path.equals(SPUtils.readData(&PATH&, &OLD&))) {
Intent mintent = new Intent();
mintent.setAction(&fly.upload.logcat&);
mintent.putExtra(&path&, action);
sendBroadcast(mintent);
SPUtils.writeData(&PATH&, &OLD&, &&);
public void onFailure(ResumableUploadRequest request, ClientException clientExcepion, ServiceException serviceException) {
// 请求异常
if (clientExcepion != null) {
// 本地异常如网络异常等
clientExcepion.printStackTrace();
if (serviceException != null) {
// 服务异常
Log.e(&ErrorCode&, serviceException.getErrorCode());
Log.e(&RequestId&, serviceException.getRequestId());
Log.e(&HostId&, serviceException.getHostId());
Log.e(&RawMessage&, serviceException.getRawMessage());
//失败后保存摘要,等待下次开机上传
SPUtils.writeData(&PATH&, &OLD&, path);
public void onDestroy() {
recordDirectory =
super.onDestroy();
工具类:(需要的可以复制保存哦)public class SPUtils {
/** 上下文 */
public static Context context;
public static void setContext(Context context) {
SPUtils.context = context;
* 写入首选项文件(.xml)
* @param filename
* @param key
* @param value
public static void writeData(String filename,String key,String value){
//实例化SharedPreferences对象,参数1是存储文件的名称,参数2是文件的打开方式,当文件不存在时,直接创建,如果存在,则直接使用
SharedPreferences mySharePreferences =
context.getSharedPreferences(filename, Context.MODE_PRIVATE);
//实例化SharedPreferences.Editor对象
SharedPreferences.Editor editor =mySharePreferences.edit();
//用putString的方法保存数据
editor.putString(key, value);
//提交数据
* 从首选项中读取值
* @param filename
* @param key
public static String readData(String filename,String key){
//实例化SharedPreferences对象
SharedPreferences mySharePerferences =
context.getSharedPreferences(filename, Context.MODE_PRIVATE);
//用getString获取值
String name =mySharePerferences.getString(key, &&);
return name;
* 获取全部的键值对
* @param filename
public static Map&String, ?& getAll(String filename)
SharedPreferences sp =
context.getSharedPreferences(filename,Context.MODE_PRIVATE);
return sp.getAll();
* 查询某个key是否已经存在
* @param filename
* @param key
public static boolean contains(String filename, String key)
SharedPreferences sp =
context.getSharedPreferences(filename,Context.MODE_PRIVATE);
return sp.contains(key);
* 移除某个值
* @param filename
* @param key
public static void remove(String filename, String key)
SharedPreferences sp = context.getSharedPreferences(filename,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.remove(key);
APPLICATION:public class myApplication extends Application {
public static final String SWITCH_ON = &ON&;
public static final String SWITCH_OFF = &OFF&;
public static final String SPUTILS_NAME = &CONFIG&;
public static final String SPUTILS_KEY = &LOGIN&;
public static final String SWITCH_POINT = &感谢&;
//文件路径名称
private final String LOGCAT_DIR = &logcat_flyaudio&;
//内置路径
private final String PATH_HOME = &/storage/emulated/0&;
//外置路径
private final String PATH_OTHER = &/storage/sdcard1&;*/
//内置SDcard卡的路径
public static final String SDCARD_PATH = Environment.getExternalStorageDirectory().getAbsolutePath()
+ File.separator;
public void onCreate() {
super.onCreate();
SPUtils.setContext(this);
}清单文件::::::::::::::::::::::::::::::::::::::::::::::::::::::&!--广播请求的权限--&
&uses-permission android:name=&android.permission.RECEIVE_BOOT_COMPLETED& /&
&uses-permission android:name=&android.permission.CALL_PHONE&/&
&uses-permission android:name=&android.permission.RECEIVE_BOOT_COMPLETED& /&
&uses-permission android:name=&android.permission.INTERNET&/&
&uses-permission android:name=&android.permission.ACCESS_NETWORK_STATE&/&
&uses-permission android:name=&android.permission.ACCESS_WIFI_STATE&/&
&uses-permission android:name=&android.permission.WRITE_EXTERNAL_STORAGE&/&
&uses-permission android:name=&android.permission.READ_EXTERNAL_STORAGE&/&
&application
android:name=&.myApplication&
android:allowBackup=&true&
android:icon=&@mipmap/ic_launcher&
android:label=&@string/app_name&
android:supportsRtl=&true&
android:theme=&@style/AppTheme&&
&activity android:name=&.MainActivity& android:launchMode=&singleTask&&
&intent-filter&
&action android:name=&android.intent.action.MAIN& /&
&category android:name=&android.intent.category.LAUNCHER& /&
&/intent-filter&
&/activity&
&!--广播--&
&receiver android:name=&.myReceiver& android:exported=&true&&
&intent-filter&
&!--接收开机发送的广播--&
&action android:name=&android.intent.action.BOOT_COMPLETED&&&/action&
&/intent-filter&
&intent-filter&
&!--接收开机发送的广播--&
&action android:name=&fly.upload.logcat&&&/action&
&/intent-filter&
&intent-filter&
&!--接收开机发送的广播--&
&action android:name=&fly.upload.logcat.isok&&&/action&
&/intent-filter&
&/receiver&
&!--服务--&
&service android:name=&.myService&&&/service&
&/application&
&&相关文章推荐
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:29287次
排名:千里之外
原创:60篇
(1)(1)(2)(1)(1)(9)(1)(9)(2)(1)(19)(27)1214人阅读
android项目实用(13)
在android开发过程中,文件上传非常常见。但是文件的断点续传就很少见了。因为android都是通过http协议请求服务器的,http本身不支持文件的断点上传。但是http支持文件的断点下载,可以通过http文件断点下载的原理来实现文件的断点上传,文件的断点下载比较简单,主要步骤如下
(1)开启服务,通过服务后台下载文件
(2)conn.getContentLength();获取要下载文件的长度,建立对应大小的文件
(3) 通过range字段来设置我们要下载的文件的开始字节和结束字节。http.setRequestProperty(“Range”, “bytes=” +
startPos + “-”
+ endPos) //注意格式中间加“-”
(4)通过sqllite保存我们下载的进度,以便在重新开始任务的时候断点下载
(5)通过广播将下载的进度回调到主线程,更新进度条
(6)利用RandomAccessFile的seek方法,跳过已下载的字节数来将下载的字节写入文件
通过这六步就可以实现简单的断点续传,当然单线程下载性能比较差。在最后的优化过程中还要加入多线程下载来提高我们的下载效率。ok文件的断线下载就说到这里,这不是我们要谈论的重点,接下来才是核心内容。
文件的上传对于android来说是非常耗时的操作,因此不能再主线程中进行。还是要利用服务来完成。但是上传的时候并没有range字段来传入我们要上传的开始字节和结束字节。这应该怎样做呢,这就要求对于文件上传,我们的服务器要做出相应的改变了。在上传文件的时候,将文件的大小的名称和大小作为参数上传到服务器,这样服务器就记录了要上传的文件大小。在上传过程中服务端要对已上传的字节数进行记录。在断点时,移动端不用记录文件的已上传的大小,而是首先去请求服务器得到已上传的字节数,移动端做的只是跳过相应的字节数来读取文件即可。在这里有必要说一下android通过http请求时如何与服务器交互的。移动端得到与服务器响应的链接后,通过流来进行数据的传递,在移动端读取文件的时候,并没有全部缓存到流中,而是在android端做了缓存,而android的内存有限,在上传大文件时就会内存溢出。在往流里面写入数据的时候,服务器也不能及时得到流内的数据,而是当移动端提交以后服务器才能做出response,移动端就是依据response判断文件上传是否成功。这样就会出现一个问题,android要实时提交文件,负责内存溢出导致程勋崩溃。在上传文件时必须先对文件校验,以免文件重复上传。对于重复上传的文件,服务端只要将以上传的文件与用户关联就可以了。文件的校验当然是md5校验了,md5校验也是耗时操作,因此也要多线程处理。在进度条的更新上还是使用广播来更新就可以了,当然也可以用handler来更新进度条。这个全凭个人喜好。这样文件的断点上传思路就有了。
(1)开启服务,通过服务后台检验文件和上传文件
(2)在检验文件的response中得到文件的已上传字节数
(3) 利用RandomAccessFile的seek方法,跳过已上传的字节数来读取文件
(4)多文件上传时通过sqllite保存文件的状态,对于已上传的文件将状态值设置为已上传或者在数据库删除
(5)通过广播将下载的进度回调到主线程,更新进度条
下面是文件断点上传的主要代码
public void onClick(View v) {
switch (v.getId()) {
case R.id.tv_shangchuan:
//开始上传时将选中的文件路径通过intent传给服务
list_filePath.clear()
//将文件的路径传入service
int file_count = map_check_file.size()
L.i("-----count"+file_count)
if(file_count==0){
T.showShort(this,"空文件夹不能上传")
loading_dialog1.show()
for(Map.Entry&String, File& entry: map_check_file.entrySet()){
File value = entry.getValue()
list_filePath.add(value.getAbsolutePath())
Intent intent_service = new Intent()
intent_service.setAction(MainActivity.ACTION_START)
intent_service.setPackage(getPackageName())
intent_service.putExtra("file_list", (Serializable) list_filePath)
getApplication().startService(intent_service)
case R.id.tv_lixian:
if (map_check_file.size() != 0) {
for (Map.Entry&String, File& entry : map_check_file.entrySet()) {
//将未上传的文件加入数据库
fileDaoImp.insertData(entry.getValue().getAbsolutePath())
Fragment fragmentById = manager.findFragmentById(R.id.fl_director_activity)
FileFragment fileFragment = (FileFragment) fragmentById
if (fileFragment != null) {
sendMessageToFragment(fileFragment)
T.showShort(this, "已加入离线")
rl_director_bottom.setVisibility(View.GONE)
T.showShort(this,"空文件夹不能加入离线")
因为在项目中有离线功能,就一并贴出来吧,离线的实现也较为简单。就是当用户点击离线的时候,将离线文件的路径进入数据库,然后通过广播判断该网络状态,当wifi条件下,读取数据库中未下载文件然后开启服务下载。
服务的代码如下:
public class DownLoadService extends Service implements APICallBack {
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
downLoadTask = new DownLoadTask(DownLoadService.this);
downLoadTask.download();
public static final String RECEIVI = "UPDATEPROGRESS";
private DownLoadTask downLoadTask = null;
FileDaoImp fileDaoImp = new FileDaoImp(DownLoadService.this);
boolean isFirst = true;
List&String& list_file_path = new ArrayList&&();
public IBinder onBind(Intent intent) {
return null;
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
if (MainActivity.ACTION_START.equals(intent.getAction())) {
downLoadTask.isPause = false;
String loading_shangchuan = intent.getStringExtra("loading_shangchuan");
if (loading_shangchuan != null && loading_shangchuan.equals("loading_shangchuan")) {
isFirst = false;
new InitThread().start();
return super.onStartCommand(intent, flags, startId);
list_file_path = (List&String&) intent.getSerializableExtra("file_list");
isFirst = true;
Log.i("main", "--------list---Service--------------" + list_file_path.size());
new InitThread().start();
} else if (MainActivity.ACTION_STOP.equals(intent.getAction())) {
if (downLoadTask != null) {
downLoadTask.isPause = true;
downLoadTask = null;
} else if (MainActivity.ACTION_CANCEL.equals(intent.getAction())) {
downLoadTask.isPause = true;
downLoadTask = null;
fileDaoImp.deletDateFileTask();
fileDaoImp.deleteFileUrl();
return super.onStartCommand(intent, flags, startId);
class InitThread extends Thread {
public void run() {
if (isFirst) {
for (int i = 0; i & list_file_path.size(); i++) {
File file = new File(list_file_path.get(i));
FileInfo fileInfo2 = null;
if (!file.isDirectory()) {
fileInfo2 = new FileInfo(2, file.getAbsolutePath(), file.getName(), file.length(), 0, MD5Util.getFileMD5String(file));
fileDaoImp.insertFileUrl(fileInfo2.getUrl(), fileInfo2.getLength(), fileInfo2.getMd5(), fileInfo2.getFileName());
} catch (IOException e) {
e.printStackTrace();
handler.obtainMessage(1).sendToTarget();
//文件上传线程,将文件按照5M分片上传。下面也给出了android如何不再本地缓存的方法。
public class DownLoadTask {
private Context context
private FileDaoImp fileDaoImp
public static boolean isPause = false
private long file_sum = 0
String isExistUrl = "http://123.56.15.30:8080/upload/isExistFile"
String actionUrl = "http://123.56.15.30:8080/upload/uploadFile"
private int finishedLength
public DownLoadTask(Context context) {
this.context = context
fileDaoImp = new FileDaoImp(context)
public void download() {
new DownThread().start()
class DownThread extends Thread {
private double load_lenth = 0
String end = "\r\n"
String twoHyphens = "--"
String boundary = "*****"
public void run() {
//未上传的文件
List&FileInfo& list = fileDaoImp.queryFileByState()
Log.i("main", "--------list--数据库---------------" + list.size())
int sum_filelength = (int) fileDaoImp.getLengthByState(0)
if (list.size() == 0) {
Intent intent = new Intent()
intent.setAction(DownLoadService.RECEIVI)
int nSplitter_length = 1024 * 1024 * 5
for (int i = 0
int file_length = (int) list.get(i).getLength()
int count = file_length / nSplitter_length + 1
L.i("-------------------md5------------" + list.get(i).getMd5())
L.i("------------------fileName------------" + list.get(i).getFileName())
//---------------------验证文件--------------------------------------------------
URL realurl = null
InputStream in = null
HttpURLConnection conn = null
realurl = new URL(isExistUrl)
conn = (HttpURLConnection) realurl.openConnection()
conn.setRequestProperty("accept", "*/*")
conn.setRequestProperty("connection", "Keep-Alive")
conn.setRequestProperty("user-agent",
"Mozilla/4.0 ( MSIE 6.0; Windows NT 5.1;SV1)")
conn.setRequestMethod("POST")
conn.setChunkedStreamingMode(1024 * 1024 * 10)
//无穷大超时
conn.setReadTimeout(0)
conn.setConnectTimeout(0)
conn.setDoInput(true)
conn.setDoOutput(true)
PrintWriter pw = new PrintWriter(conn.getOutputStream())
pw.print("userId=" + AppUtils.getUserName(context) + "&md5=" + list.get(i).getMd5()
+ "&did=" + getDid() + "&name=" + list.get(i).getFileName() + "&size=" + list.get(i).getLength())
Log.i("main", "-------------userId---------" + AppUtils.getUserName(context))
Log.i("main", "-------------md5---------" + list.get(i).getMd5())
Log.i("main", "-------------did---------" + getDid())
Log.i("main", "-------------name---------" + list.get(i).getFileName())
Log.i("main","-------------size---------"+list.get(i).getLength())
pw.flush()
pw.close()
in = conn.getInputStream()
StringBuffer stringBuffer = new StringBuffer()
while ((ch = in.read()) != -1) {
stringBuffer.append((char) ch)
String json = stringBuffer.toString()
JSONObject jsonObject = new JSONObject(json)
boolean isSuccess = jsonObject.optBoolean("success")
if (isSuccess) {
int lengths = jsonObject.optJSONObject("info").optJSONObject("file").optInt("length")
finishedLength = lengths
if (finishedLength == list.get(i).getLength()) {
fileDaoImp.deleteFilebyMd5(list.get(i).getMd5())
fileDaoImp.deleteFilebyPath(list.get(i).getUrl())
if (i == list.size() - 1) {
intent.putExtra("progress", (load_lenth * 100 / ((double) sum_filelength)))
intent.putExtra("state", "success")
context.sendBroadcast(intent)
Log.i("main", "-----length_finished------" + finishedLength)
} catch (Exception eio) {
Log.i("main", "-----Exception------" + eio.toString())
//---------------------上传文件--------------------------------------------------
for (int j = 0
File file = new File(list.get(i).getUrl())
URL url = new URL(actionUrl)
HttpURLConnection con = (HttpURLConnection) url.openConnection()
con.setChunkedStreamingMode(1024 * 1024 * 10)
//无穷大超时
con.setReadTimeout(0)
con.setConnectTimeout(0)
con.setDoInput(true)
con.setDoOutput(true)
con.setUseCaches(false)
con.setRequestMethod("POST")
con.setRequestProperty("Connection", "Keep-Alive")
con.setRequestProperty("Charset", "UTF-8")
con.setRequestProperty("Content-Type",
"multipart/form-boundary=" + boundary)
DataOutputStream ds = new DataOutputStream(con.getOutputStream())
//添加参数
StringBuffer sb = new StringBuffer()
Map&String, String& params_map = new HashMap&&()
params_map.put("nSplitter", "3")
params_map.put("md5", list.get(i).getMd5())
params_map.put("dId", getDid())
params_map.put("userId", AppUtils.getUserName(context))
params_map.put("name", file.getName())
params_map.put("from", finishedLength + "")
Log.i("main", "-------------userId----上传-----" + AppUtils.getUserName(context))
if (finishedLength + nSplitter_length & file_length) {
params_map.put("to", file_length + "")
params_map.put("to", (finishedLength + nSplitter_length) + "")
params_map.put("size", list.get(i).getLength() + "")
//添加参数
for (Map.Entry&String, String& entries : params_map.entrySet()) {
sb.append(twoHyphens).append(boundary).append(end)
sb.append("Content-Disposition: form- name=" + entries.getKey() + end)
sb.append("Content-Type: text/ charset=UTF-8" + end)
sb.append("Content-Transfer-Encoding: 8bit" + end)
sb.append(end)
sb.append(entries.getValue())
Log.i("main", "-----------params----------" + entries.getValue())
sb.append(end)
ds.writeBytes(sb.toString())
//添加文件
ds.writeBytes(twoHyphens + boundary + end)
ds.writeBytes("Content-Disposition: form- "
+ "name=\"file" + "\";filename=\"" + file.getName() + "\"" + end)
ds.writeBytes(end)
int bufferSize = 1024
byte[] buffer = new byte[bufferSize]
int length = -1
long time = System.currentTimeMillis()
file_sum = file.length()
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r")
randomAccessFile.seek(finishedLength)
load_lenth = finishedLength
double current_lenth = load_lenth
while ((length = randomAccessFile.read(buffer)) != -1) {
ds.write(buffer, 0, length)
load_lenth += length
if (load_lenth - current_lenth & nSplitter_length) {
current_lenth = load_lenth
if (System.currentTimeMillis() - time & 500) {
time = System.currentTimeMillis()
//使用广播发送上传百分比
intent.putExtra("progress", (load_lenth * 100 / ((double) file_sum)))
intent.putExtra("progress", (load_lenth * 100 / ((double) sum_filelength)))
context.sendBroadcast(intent)
if (isPause) {
//将文件的进度修改
ds.writeBytes(end)
randomAccessFile.close()
ds.flush()
ds.writeBytes(twoHyphens + boundary + twoHyphens + end)
InputStream is = con.getInputStream()
StringBuffer b = new StringBuffer()
while ((ch = is.read()) != -1) {
b.append((char) ch)
String json = b.toString()
JSONObject jsonObject = new JSONObject(json)
boolean isSuccess = jsonObject.optBoolean("success")
if (isSuccess) {
int lengths = jsonObject.optJSONObject("info").optJSONObject("file0").optInt("length")
if (lengths == list.get(i).getLength()) {
Log.i("main", "----文件上传-lengths------" + lengths)
//更新进度
fileDaoImp.upDateProgress(list.get(i).getMd5(), lengths)
ds.close()
con.disconnect()
ds.writeBytes(end)
randomAccessFile.close()
ds.flush()
ds.writeBytes(twoHyphens + boundary + twoHyphens + end)
InputStream is = con.getInputStream()
StringBuffer b = new StringBuffer()
while ((ch = is.read()) != -1) {
b.append((char) ch)
String json = b.toString()
JSONObject jsonObject = new JSONObject(json)
boolean isSuccess = jsonObject.optBoolean("success")
Log.i("main", "----文件分片------" + json)
if (isSuccess) {
int lengths = jsonObject.optJSONObject("info").optJSONObject("file0").optInt("length")
finishedLength = lengths
if (lengths == list.get(i).getLength()) {
boolean b1 = fileDaoImp.deleteFilebyMd5(list.get(i).getMd5())
//删除离线文件
boolean b2 = fileDaoImp.deleteFilebyPath(list.get(i).getUrl())
Log.i("main", "----文件上传-成功------" + lengths)
//当最后一个文件
if (i == list.size() - 1) {
intent.putExtra("progress", (load_lenth * 100 / ((double) sum_filelength)))
intent.putExtra("state", "success")
context.sendBroadcast(intent)
ds.close()
con.disconnect()
Log.i("main", "--------end----------")
} catch (Exception e) {
Log.i("main", "---------e------------" + e.toString())
//数据库管理代码:
public class FileDaoImp implements
private DbHelper dbHelper = null;
public FileDaoImp(Context context){
dbHelper = new DbHelper(context);
public void insertFileUrl(String url,long length,String md5,String file_name) {
SQLiteDatabase db
= dbHelper.getReadableDatabase();
db.execSQL("insert into file_info(fileUrl,file_state,file_length,file_md5," +
"file_progress,file_name)values(?,?,?,?,?,?)",new Object[]{url,0,length,md5,0,file_name
db.close();
public boolean deleteFilebyMd5(String md5) {
SQLiteDatabase db
= dbHelper.getReadableDatabase();
int file_info = db.delete("file_info", "file_md5=?", new String[]{md5});
db.close();
if(file_info&0){
return true;
return false;
public void deleteFileUrl() {
SQLiteDatabase db
= dbHelper.getReadableDatabase();
db.execSQL("delete from file_info");
db.close();
boolean deletDateFileTask( ) {
SQLiteDatabase db
= dbHelper.getReadableDatabase();
int shebei_info = db.delete("fileTask", null, null);
db.execSQL(" update sqlite_sequence set seq=0 where name='fileTask'");
return false;
public List&String& queryFileUrl() {
List&String& list = new ArrayList&&();
SQLiteDatabase db
= dbHelper.getWritableDatabase();
Cursor cursor = db.rawQuery("select * from file_info", null);
while (cursor.moveToNext()){
String url = cursor.getString(cursor.getColumnIndex("fileUrl"));
list.add(url);
cursor.close();
db.close();
public List&FileInfo&
queryFileByState() {
List&FileInfo& list_fileInfo = new ArrayList&&();
SQLiteDatabase db
= dbHelper.getWritableDatabase();
Cursor cursor = db.rawQuery("select * from file_info where file_state = 0", null);
while (cursor.moveToNext()){
String url = cursor.getString(cursor.getColumnIndex("fileUrl"));
file_length = cursor.getInt(cursor.getColumnIndex("file_length"));
String file_md5 = cursor.getString(cursor.getColumnIndex("file_md5"));
String file_name = cursor.getString(cursor.getColumnIndex("file_name"));
FileInfo fileInfo = new FileInfo();
fileInfo.setUrl(url);
fileInfo.setMd5(file_md5);
fileInfo.setLength(file_length);
fileInfo.setFileName(file_name);
list_fileInfo.add(fileInfo);
cursor.close();
db.close();
return list_fileI
public void updateFile(String md5) {
SQLiteDatabase db
= dbHelper.getReadableDatabase();
db.execSQL("update
file_info set file_state = ? where file_md5 = ?",new Object[]{
db.close();
public long getLengthByState(int state) {
long length = 0;
SQLiteDatabase db
= dbHelper.getReadableDatabase();
Cursor cursor = db.rawQuery("select * from file_info where file_state = ?", new String[]{state+""});
while (cursor.moveToNext()){
String url = cursor.getString(cursor.getColumnIndex("fileUrl"));
length+=new File(url).length();
cursor.close();
db.close();
L.i("----------length--------"+length);
public void upDateProgress(String md5,int progress) {
SQLiteDatabase db
= dbHelper.getReadableDatabase();
db.execSQL("update
file_info set file_progress = ? where file_md5 = ?",new Object[]{
progress,md5
db.close();
public int getFileFinishedProgress(String md5) {
length = 0;
SQLiteDatabase db
= dbHelper.getReadableDatabase();
Cursor cursor = db.rawQuery("select * from file_info where file_md5 =?", new String[]{md5});
while (cursor.moveToNext()){
length = cursor.getInt(cursor.getColumnIndex("file_progress"));
cursor.close();
db.close();
Log.i("main","------------fileProgress-------"+length);
public int getFileSumLength(String file_length) {
boolean insertData( String values) {
SQLiteDatabase db
= dbHelper.getReadableDatabase();
ContentValues contentValues
= new ContentValues();
contentValues.put("filepath",values);
long shebei_info = db.insert("fileTask", null, contentValues);
contentValues.clear();
if (shebei_info & 0) {
Log.i("main","---------shebei_info-----------------");
return true;
return false;
boolean deletelian_Date( ) {
SQLiteDatabase db
= dbHelper.getReadableDatabase();
int shebei_info = db.delete("fileTask", null, null);
db.execSQL(" update sqlite_sequence set seq=0 where name='fileTask'");
return false;
List&String& query_lianxian_data( ) {
SQLiteDatabase db
= dbHelper.getReadableDatabase();
List&String& list_db = new ArrayList&&();
Cursor cursor = db.rawQuery("select * from fileTask", null);
if (cursor != null) {
String columns[] = cursor.getColumnNames();
while (cursor.moveToNext()) {
String file_path = cursor.getString(cursor.getColumnIndex(columns[1]));
list_db.add(file_path);
cursor.close();
public boolean deleteFilebyPath(String path) {
SQLiteDatabase db
= dbHelper.getReadableDatabase();
int file_info = db.delete("fileTask", "filepath=?", new String[]{path});
db.close();
if(file_info&0){
return true;
return false;
通过这几步就可以实现文件的断点上传了,但是由于时间的原因,项目中并没有加入多线程上传。其实多线程上传的原理也很简单,类似文件的分片上传。在这里就不说了。文件的断点上传是实现了,但是性能上面还是有很多欠缺。只能慢慢改善了。
&&相关文章推荐
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:11042次
排名:千里之外
原创:34篇
(1)(1)(6)(7)(1)(2)(3)(2)(4)(1)(2)(3)(1)

我要回帖

更多关于 阿里 oss 断点续传 的文章

 

随机推荐