使用Dropbox Core API v2上传文件时文件大小异常缩减问题求助
解决Dropbox API v2弱网下连续上传数据库文件损坏的问题
看了你的问题和日志,核心问题出在弱网环境下快速连续并行上传同一个本地数据库文件——并发读取导致文件流读取不完整、弱网波动引发部分传输中断,最终出现上传的文件损坏。下面给你几个针对性的解决方案:
一、立即停止并行上传,改用串行任务队列
你现在用AsyncTaskCompat.executeParallel同时启动多个上传任务,这会导致多个线程同时读取同一个.db文件。弱网下上传耗时久,本地文件可能被数据库写入操作干扰,或者并发读取时出现流截断,最终上传到Dropbox的就是残缺数据。
调整方案:
- 把并行执行改成串行,用
AsyncTask.execute()代替executeParallel,或者用单线程ExecutorService管理任务,保证同一时间只有一个上传任务在运行。 - 增加上传防抖:如果用户操作会触发多次上传,在1-2秒内的重复请求直接忽略,只保留最后一次,避免不必要的重复上传。
示例代码(改用串行执行):
// 替换原来的AsyncTaskCompat.executeParallel new DropboxUploadFileTask(DropboxClientFactory.getClient(), new DropboxUploadFileTask.Callback() { @Override public void onUploadComplete(FileMetadata result) { // 回调逻辑不变 } @Override public void onError(Exception e) { // 错误处理不变 } }, context).execute(glDbName, "");
二、改用UploadSession分块上传(弱网环境首选)
uploadAndFinish是一次性上传整个文件,适合小文件和稳定网络;弱网下网络波动大,很容易出现上传中断或部分传输。Dropbox的UploadSession支持分块上传,即使中间断网也能断点续传,大幅提升稳定性。
核心实现步骤:
- 创建上传会话
- 分块上传文件内容
- 结束上传会话完成文件上传
示例代码片段:
@Override protected FileMetadata doInBackground(String... params) { String dbFileName = params[0]; File dbFile = mContext.getDatabasePath(dbFileName); String remoteFolderPath = params[1]; String remotePath = remoteFolderPath + "/" + dbFile.getName(); FileChannel channel = null; try { channel = new FileInputStream(dbFile).getChannel(); long fileSize = channel.size(); int chunkSize = 4 * 1024 * 1024; // 4MB分块,可根据需求调整 // 1. 创建上传会话 CreateSessionResult sessionResult = mDbxClient.files().uploadSessionStart() .uploadAndFinish(Channels.newInputStream(channel.position(0), 0)); String sessionId = sessionResult.getSessionId(); long uploaded = 0; while (uploaded < fileSize) { long remaining = fileSize - uploaded; long chunkLength = Math.min(remaining, chunkSize); // 2. 上传分块 mDbxClient.files().uploadSessionAppendV2(sessionId) .setOffset(uploaded) .uploadAndFinish(Channels.newInputStream(channel.position(uploaded), chunkLength)); uploaded += chunkLength; } // 3. 结束会话,完成上传 CommitInfo commitInfo = CommitInfo.newBuilder(remotePath) .withMode(WriteMode.OVERWRITE) .build(); return mDbxClient.files().uploadSessionFinish(sessionId, uploaded, commitInfo) .uploadAndFinish(); } catch (DbxException | IOException e) { mException = e; Log.e("BKSync", "分块上传失败", e); } finally { if (channel != null) { try { channel.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; }
三、增加文件完整性校验
上传完成后,对比本地文件和Dropbox文件的哈希值,确保上传内容完整:
- 计算本地
.db文件的哈希值(可使用MD5或SHA-256) - 上传完成后,通过Dropbox API获取文件的
content_hash(需按照Dropbox官方文档的算法计算本地对应哈希) - 如果哈希不一致,触发重试逻辑
四、优化错误处理与重试机制
从你的日志看,存在DNS解析失败(Unable to resolve host)的弱网典型错误,但当前代码未区分错误类型、也没有重试机制。可以针对网络类错误增加2-3次重试,避免一次失败就放弃。
示例重试逻辑:
int retryCount = 0; final int MAX_RETRY = 2; while (retryCount <= MAX_RETRY) { try { // 上传逻辑(串行上传或分块上传) break; } catch (NetworkIOException e) { retryCount++; if (retryCount > MAX_RETRY) { mException = e; break; } // 重试前等待1秒,给网络恢复时间 Thread.sleep(1000); } catch (Exception e) { mException = e; break; } }
总结:优先调整为串行上传,再结合分块上传,这两个措施基本能解决弱网下的文件损坏问题;配合完整性校验和重试机制,能进一步提升上传的可靠性。
内容的提问来源于stack exchange,提问作者varun
相关产品推荐
相关产品推荐

