华为云OBS批量下载工具

部署运行你感兴趣的模型镜像

之前开发中遇到数据迁移的需求,但是华为OBS对象存储不支持批到导出某个通的文件,于是自己用python写了这个工具,通过GUI界面简化了OBS文件下载流程,特别适合需要批量操作的技术人员使用。


一、工具核心功能亮点

  1. 可视化操作界面​:使用Tkinter构建的直观GUI
  2. 多线程下载​:后台线程处理避免界面卡顿
  3. 实时进度监控​:下载速度、当前文件、进度条三重反馈
  4. 智能路径处理​:自动根据华为云通路径创建本地目录结构
  5. 安全凭证管理​:Secret Key以掩码形式显示

三、使用到的关键库

库名称作用版本要求
tkinterGUI界面构建Python标准库
obs华为云OBS官方SDKpip install obs
requestsHTTP请求处理pip install requests
pathlib路径操作Python标准库

四、使用示例

  1. 填写AK/SK凭证
  2. 设置区域端点(默认西南区)
  3. 输入桶名称
  4. 选择桶内文件夹路径
  5. 保存到本地目录路径
  6. 点击"获取并下载"启动任务


 

总结

通过Python的Tkinter与华为OBS SDK结合,实现了:

  • ✅ 图形化批量下载操作
  • ✅ 实时进度反馈
  • ✅ 智能路径处理
  • ✅ 安全凭证管理

欢迎在评论区交流使用体验和改进建议!对于需要处理华为云OBS文件的技术人员,这个工具能极大提升工作效率。

附上完整源码,可自行编译运行。  
  
如需直接获取可执行文件,欢迎私信联系获取.exe安装包。  


六、完整源码

import os
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
import requests
import threading
import time
from pathlib import Path
from obs import ObsClient, Object


class ObsAutoDownloader:
    def __init__(self, master):
        self.master = master
        master.title("华为云OBS自动下载工具")
        master.geometry("900x700")

        # 初始化状态
        self.is_downloading = False
        self.obs_client = None
        self.file_list = []
        self.current_file = ""

        # 创建UI组件
        self.create_widgets()

    def create_widgets(self):
        """界面布局"""
        main_frame = ttk.Frame(self.master, padding=20)
        main_frame.pack(fill=tk.BOTH, expand=True)

        # 配置区域
        config_frame = ttk.LabelFrame(main_frame, text="OBS配置")
        config_frame.pack(fill=tk.X, pady=5)

        # 凭证输入
        ttk.Label(config_frame, text="Access Key:").grid(row=0, column=0, sticky=tk.W)
        self.ak_entry = ttk.Entry(config_frame)
        self.ak_entry.grid(row=0, column=1, padx=5, pady=2)

        ttk.Label(config_frame, text="Secret Key:").grid(row=0, column=2, sticky=tk.W)
        self.sk_entry = ttk.Entry(config_frame, show="*")
        self.sk_entry.grid(row=0, column=3, padx=5, pady=2)

        # 区域和桶配置
        ttk.Label(config_frame, text="区域端点:").grid(row=1, column=0, sticky=tk.W)
        self.endpoint_entry = ttk.Entry(config_frame)
        self.endpoint_entry.grid(row=1, column=1, padx=5, pady=2)
        self.endpoint_entry.insert(0, "obs.cn-southwest-2.myhuaweicloud.com")

        ttk.Label(config_frame, text="桶名称:").grid(row=1, column=2, sticky=tk.W)
        self.bucket_entry = ttk.Entry(config_frame)
        self.bucket_entry.grid(row=1, column=3, padx=5, pady=2)

        ttk.Label(config_frame, text="文件夹路径:").grid(row=2, column=0, sticky=tk.W)
        self.prefix_entry = ttk.Entry(config_frame)
        self.prefix_entry.grid(row=2, column=1, columnspan=3, sticky=tk.EW, padx=5, pady=2)
        self.prefix_entry.insert(0, "")

        # 保存路径
        ttk.Label(config_frame, text="保存目录:").grid(row=3, column=0, sticky=tk.W)
        self.save_path = tk.StringVar()
        ttk.Entry(config_frame, textvariable=self.save_path, width=40).grid(row=3, column=1, padx=5)
        ttk.Button(config_frame, text="浏览", command=self.choose_directory).grid(row=3, column=2)

        # 进度区域
        progress_frame = ttk.LabelFrame(main_frame, text="进度")
        progress_frame.pack(fill=tk.X, pady=5)

        self.progress_bar = ttk.Progressbar(progress_frame, mode='determinate')
        self.progress_bar.pack(fill=tk.X, padx=10, pady=5)

        info_frame = ttk.Frame(progress_frame)
        info_frame.pack(fill=tk.X, padx=10)
        ttk.Label(info_frame, text="当前文件:").pack(side=tk.LEFT)
        self.current_file_label = ttk.Label(info_frame, text="等待开始...")
        self.current_file_label.pack(side=tk.LEFT, padx=10)

        ttk.Label(info_frame, text="速度:").pack(side=tk.LEFT)
        self.speed_label = ttk.Label(info_frame, text="0.00 KB/s")
        self.speed_label.pack(side=tk.LEFT, padx=10)

        # 控制按钮
        btn_frame = ttk.Frame(main_frame)
        btn_frame.pack(pady=5)
        self.start_btn = ttk.Button(btn_frame, text="获取并下载", command=self.start_process)
        self.start_btn.pack(side=tk.LEFT, padx=5)
        self.stop_btn = ttk.Button(btn_frame, text="停止", state=tk.DISABLED, command=self.stop_process)
        self.stop_btn.pack(side=tk.LEFT, padx=5)

        # 日志区域
        log_frame = ttk.LabelFrame(main_frame, text="操作日志")
        log_frame.pack(fill=tk.BOTH, expand=True)
        self.log_text = scrolledtext.ScrolledText(log_frame, height=12)
        self.log_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

    def choose_directory(self):
        path = filedialog.askdirectory()
        if path:
            self.save_path.set(path)

    def log(self, message):
        self.log_text.insert(tk.END, f"[{time.strftime('%H:%M:%S')}] {message}\n")
        self.log_text.see(tk.END)

    def validate_config(self):
        """验证配置有效性"""
        required_fields = {
            "AK": self.ak_entry.get().strip(),
            "SK": self.sk_entry.get().strip(),
            "Endpoint": self.endpoint_entry.get().strip(),
            "Bucket": self.bucket_entry.get().strip(),
            "SavePath": self.save_path.get()
        }

        for field, value in required_fields.items():
            if not value:
                messagebox.showerror("错误", f"{field} 不能为空")
                return False

        if not os.path.exists(required_fields["SavePath"]):
            try:
                os.makedirs(required_fields["SavePath"])
            except:
                messagebox.showerror("错误", "无法创建保存目录")
                return False

        return True

    def start_process(self):
        """启动整个流程"""
        if not self.validate_config():
            return

        self.start_btn.config(state=tk.DISABLED)
        self.stop_btn.config(state=tk.NORMAL)
        self.is_downloading = True

        threading.Thread(target=self.full_process, daemon=True).start()

    def full_process(self):
        """完整处理流程"""
        try:
            # 初始化OBS客户端
            self.obs_client = ObsClient(
                access_key_id=self.ak_entry.get().strip(),
                secret_access_key=self.sk_entry.get().strip(),
                server=self.endpoint_entry.get().strip()
            )

            # 获取文件列表
            self.log("正在获取文件列表...")
            self.file_list = self.list_obs_files()
            if not self.file_list:
                self.log("目标文件夹为空")
                return

            self.log(f"找到 {len(self.file_list)} 个文件")

            # 开始下载
            self.download_all_files()

        except Exception as e:
            self.log(f"操作失败: {str(e)}")
        finally:
            self.is_downloading = False
            self.master.after(0, lambda: self.stop_btn.config(state=tk.DISABLED))
            self.master.after(0, lambda: self.start_btn.config(state=tk.NORMAL))

    def list_obs_files(self):
        """获取OBS文件列表"""
        bucket = self.bucket_entry.get().strip()
        prefix = self.prefix_entry.get().strip().rstrip('/') + '/'
        file_list = []
        marker = None

        try:
            while True:
                resp = self.obs_client.listObjects(bucket, prefix=prefix, marker=marker)
                if resp.status < 300:
                    # 过滤文件夹标记对象
                    valid_files = [
                        obj.key for obj in resp.body.contents
                        if not (obj.key.endswith('/') and obj.size == 0)
                    ]
                    file_list.extend(valid_files)

                    if resp.body.is_truncated:
                        marker = resp.body.next_marker
                    else:
                        break
                else:
                    raise Exception(f"列表获取失败: {resp.errorCode}")

            return file_list

        except Exception as e:
            self.log(f"获取文件列表失败: {str(e)}")
            return []

    def download_all_files(self):
        """下载所有文件"""
        total = len(self.file_list)
        success_count = 0
        start_time = time.time()

        for idx, file_key in enumerate(self.file_list, 1):
            if not self.is_downloading:
                break

            self.current_file = file_key
            self.master.after(0, lambda: self.current_file_label.config(
                text=f"{idx}/{total} {os.path.basename(file_key)}"))

            try:
                # 下载文件
                local_path = os.path.join(self.save_path.get(), file_key)
                os.makedirs(os.path.dirname(local_path), exist_ok=True)

                resp = self.obs_client.getObject(
                    self.bucket_entry.get().strip(),
                    file_key,
                    downloadPath=local_path
                )

                if resp.status < 300:
                    success_count += 1
                    self.log(f"下载成功: {file_key}")
                else:
                    self.log(f"下载失败[{resp.status}]: {file_key}")

                # 更新进度
                progress = (idx / total) * 100
                self.master.after(0, lambda: self.progress_bar.configure(value=progress))

                # 计算速度
                time_used = time.time() - start_time
                speed = (idx * 1024) / time_used  # 假设平均每个文件1KB
                self.master.after(0, lambda: self.speed_label.config(text=f"{speed:.2f} 文件/秒"))

            except Exception as e:
                self.log(f"下载异常 {file_key}: {str(e)}")

        self.log(f"下载完成!成功 {success_count}/{total} 个文件")

    def stop_process(self):
        """停止处理"""
        self.is_downloading = False
        self.log("操作已停止")
        if self.obs_client:
            self.obs_client.close()


if __name__ == "__main__":
    root = tk.Tk()
    app = ObsAutoDownloader(root)
    root.mainloop()

 

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

### 如何获取和使用华为云 OBS 桶的 AK 和 SK #### 获取访问密钥(AK 和 SK) 为了获得华为云 OBS 桶所需的访问密钥(Access Key ID, 简称 AK)以及秘密密钥(Secret Access Key, 简称 SK),需通过华为云控制台完成相应设置。具体流程是从华为云官方网站登录账号并进入控制面板,按照指引找到安全凭证部分来创建新的访问密钥组合[^1]。 一旦成功生成了一组 AK/SK 对,则应妥善保存这些信息,因为它们将在后续与 OBS 进行交互时作为身份验证依据被广泛应用于各种场景之中,比如上传文件、下载资源或是执行其他管理任务之前都需要利用此认证机制确保操作的安全性和合法性。 #### 使用访问密钥(AK 和 SK) 当准备就绪之后,可以借助多种方式运用所取得的 AK 及其对应的 SK 来实现对 OBS 存储空间的操作: - **命令行工具**:对于希望通过脚本自动化处理大量数据的情况而言,可以通过安装 `obsutil` 工具来进行批量传输工作。初始化配置过程中会提示输入 AK 和 SK 用于建立连接[^2]。 - **编程接口调用**:如果倾向于开发自定义应用程序的话,则可以选择适合项目的 SDK 库之一,并依照官方文档指导实例化客户端对象时传入必要的参数——即上述提到过的 AK 和 SK 值。例如,在 Windows 平台上采用 Java 编程语言的情况下,可通过如下代码片段展示如何正确地构建一个能够正常工作的 ObsClient 实例[^4]: ```java import com.obs.services.ObsClient; public class Example { public static void main(String[] args) throws Exception { String ak = "your-access-key-id"; String sk = "your-secret-access-key"; String endpoint = "https://your-endpoint"; // 创建ObsClient实例 ObsClient obsClient = new ObsClient(ak, sk, endpoint); // 接下来可以根据需求编写更多逻辑... } } ``` 需要注意的是,在实际部署环境中应当采取适当措施保护好敏感资料不被泄露出去,同时定期更换密钥以增强安全性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值