文档首页/ 对象存储服务 OBS/ SDK参考/ Java/ 常见问题(Java SDK)/ SDK是否支持批量上传、下载或复制对象?(Java SDK)
更新时间:2026-06-30 GMT+08:00
分享

SDK是否支持批量上传、下载或复制对象?(Java SDK)

SDK暂未提供专门的批量上传、下载或复制对象接口,但您可以通过组合现有接口自行封装实现,请参考如下步骤操作:

  1. 列举出所有待上传、下载或者复制的对象。可参考列举对象章节,列举需上传、下载或复制的对象。
  2. 对列举出的对象调用单个对象的上传(上传对象)、下载(下载对象)或复制(复制对象)接口。

以批量上传对象为例,示例代码如下:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import com.obs.services.ObsClient;
import com.obs.services.exception.ObsException;
import com.obs.services.model.ObsObject;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class BatchUpload001 {
    private List<File> fileList = new ArrayList<>();
    public static void main(String[] args) {
        // 您可以通过环境变量获取访问密钥AK/SK,也可以使用其他外部引入方式传入。如果使用硬编码可能会存在泄露风险。
        // 您可以登录访问管理控制台获取访问密钥AK/SK
        String ak = System.getenv("ACCESS_KEY_ID");
        String sk = System.getenv("SECRET_ACCESS_KEY_ID");
        // 【可选】如果使用临时AK/SK和SecurityToken访问OBS,同样建议您尽量避免使用硬编码,以降低信息泄露风险。
        // 您可以通过环境变量获取访问密钥AK/SK/SecurityToken,也可以使用其他外部引入方式传入。
        // String securityToken = System.getenv("SECURITY_TOKEN");
        // endpoint填写桶所在的endpoint, 此处以华北-北京四为例,其他地区请按实际情况填写。
        String endPoint = "https://obs.cn-north-4.myhuaweicloud.com";
        // 您可以通过环境变量获取endPoint,也可以使用其他外部引入方式传入。
        //String endPoint = System.getenv("ENDPOINT");
        
        // 创建ObsClient实例
        // 使用永久AK/SK初始化客户端
        ObsClient obsClient = new ObsClient(ak, sk, endPoint);
        // 使用临时AK/SK和SecurityToken初始化客户端
        // ObsClient obsClient = new ObsClient(ak, sk, securityToken, endPoint);
        try {
            String bucketName = "examplebucket";
            // 定义桶内对象的前缀
            String objectPre = "object/";
            // 待上传的文件夹
            String localDirPath = "localfile";

            // 扫描文件夹下所有文件和空目录
            File localDir = new File(localDirPath);
            if (!localDir.exists() || !localDir.isDirectory()) {
                System.out.println("本地文件夹不存在: " + localDirPath);
                return;
            }

            BatchUpload001 uploader = new BatchUpload001();
            uploader.listFiles(localDir);

            if (uploader.fileList.isEmpty()) {
                System.out.println("未找到待上传的文件");
                return;
            }

            System.out.println("待上传对象数量: " + uploader.fileList.size());

            // 初始化线程池
            int threadCount = 20;
            ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
            CountDownLatch latch = new CountDownLatch(uploader.fileList.size());
            AtomicInteger successCount = new AtomicInteger(0);
            AtomicInteger failCount = new AtomicInteger(0);

            // 执行并发上传
            for (File f : uploader.fileList) {
                executorService.execute(() -> {
                    try {
                        String relativePath = f.getPath().substring(localDirPath.length() + 1);
                        // 将Windows路径分隔符替换为OBS对象键的分隔符
                        String remoteObjectKey = objectPre + relativePath.replace("\\", "/");

                        if (f.isDirectory()) {
                            // 如果是空文件夹,则在桶内创建对应的空文件夹对象
                            remoteObjectKey += "/";
                            obsClient.putObject(bucketName, remoteObjectKey, new ByteArrayInputStream(new byte[0]));
                        } else {
                            obsClient.putObject(bucketName, remoteObjectKey, f);
                        }
                        successCount.incrementAndGet();
                        System.out.println("上传成功: " + remoteObjectKey);
                    } catch (ObsException e) {
                        failCount.incrementAndGet();
                        System.out.println("上传失败: " + f.getPath()
                                + ", HTTP Code: " + e.getResponseCode()
                                + ", Error Code: " + e.getErrorCode()
                                + ", Error Message: " + e.getErrorMessage());
                    } catch (Exception e) {
                        failCount.incrementAndGet();
                        System.out.println("上传失败: " + f.getPath() + ", " + e.getMessage());
                    } finally {
                        latch.countDown();
                    }
                });
            }

            // 等待上传完成
            executorService.shutdown();
            latch.await(30, TimeUnit.MINUTES);

            System.out.println("上传完成, 成功: " + successCount.get() + ", 失败: " + failCount.get());
        } catch (ObsException e) {
            System.out.println("创建ObsClient失败");
            System.out.println("HTTP Code: " + e.getResponseCode());
            System.out.println("Error Code: " + e.getErrorCode());
            System.out.println("Error Message: " + e.getErrorMessage());
        } catch (Exception e) {
            System.out.println("上传异常: " + e.getMessage());
            e.printStackTrace();
        }
    }

    // 递归扫描文件夹下所有文件和空目录
    private void listFiles(File file) {
        File[] children = file.listFiles();
        if (children == null) {
            return;
        }
        if (children.length == 0) {
            // 空文件夹也需要上传,将其添加到列表中
            fileList.add(file);
            return;
        }
        for (File f : children) {
            if (f.isDirectory()) {
                listFiles(f);
            } else if (f.isFile()) {
                fileList.add(f);
            }
        }
    }
}

您可以使用多线程并发执行上传/下载/复制操作,以提高效率。

相关文档