You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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支持分块上传,即使中间断网也能断点续传,大幅提升稳定性。

核心实现步骤:

  1. 创建上传会话
  2. 分块上传文件内容
  3. 结束上传会话完成文件上传

示例代码片段:

@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文件的哈希值,确保上传内容完整:

  1. 计算本地.db文件的哈希值(可使用MD5或SHA-256)
  2. 上传完成后,通过Dropbox API获取文件的content_hash(需按照Dropbox官方文档的算法计算本地对应哈希)
  3. 如果哈希不一致,触发重试逻辑

四、优化错误处理与重试机制

从你的日志看,存在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:45:33