跳转到主要内容

gs-wrap 用于封装Google Cloud Storage API,以实现多线程数据操作,包括复制、读取、写入和散列。

项目描述

gs-wrap

MIT License PyPI - version PyPI - Python Version Documentation Status

gs-wrap 封装了 Google Cloud Storage API,用于多线程数据操作,包括复制、读取、写入和散列。

最初,我们使用了我们的 gsutilwrap,它是gsutil命令行接口的一个薄包装,用于简化与Google Cloud Storage相关的部署和备份任务。然而,gsutilwrap 在将许多对象复制到不同目的地时速度过慢。

因此,我们开发了 gs-wrap 来加速这些操作,同时保持它在其他操作上的速度与 gsutilwrap 相当或更快。

虽然由谷歌提供的 google-cloud-storage 库具有高级功能和良好的性能,但其使用案例和行为与 gsutil 不同。由于我们希望使用 gsutil 的简洁性和使用模式,我们创建了 gs-wrap,它将 google-cloud-storage 封装在核心中,并设置了与 gsutil 相似的行为。

gs-wrap 并非第一个封装谷歌云存储 API 的 Python 库。 cloud-storage-client 采用类似的方法,旨在管理亚马逊的 S3 和谷歌云存储。其部分内容也基于 google-cloud-storage,但该库的行为与 gsutil 不同,这使得它难以作为 gsutilwrap 的替代品使用。此外,该库没有提供所有需要的操作,例如复制到多个目的地、读取、写入和散列。

gs-wrap 的主要优势是能够将许多对象从许多不同的路径复制到多个目的地,同时模仿 gsutil 接口。有关 gs-wrapgsutilwrap 之间的性能直接比较,请参阅 性能比较部分

使用方法

您需要创建一个谷歌云存储桶才能使用此客户端库。请按照 官方谷歌云存储文档 进行操作,了解如何创建存储桶。

连接到您的谷歌云存储桶

首先需要创建一个用于与谷歌云存储 API 交互的客户端。此客户端内部使用来自 google-cloud-storageStorage Client

可以向客户端传递一个参数

代表客户端操作的谷歌云存储 项目。当创建内部客户端时,它将被传递。如果没有传递,将回退到从本地认证的 谷歌云 SDK 环境中推断出的默认值。每个项目需要一个单独的客户端。不支持在不同项目之间的操作。

import gswrap

client = gswrap.Client() # project is optional

列出您存储桶中的对象

client.ls(gcs_url="gs://your-bucket/your-dir", recursive=False)
# gs://your-bucket/your-dir/your-subdir1/
# gs://your-bucket/your-dir/your-subdir2/
# gs://your-bucket/your-dir/file1

client.ls(gcs_url="gs://your-bucket/your-dir", recursive=True)
# gs://your-bucket/your-dir/your-subdir1/file1
# gs://your-bucket/your-dir/your-subdir1/file2
# gs://your-bucket/your-dir/your-subdir2/file1
# gs://your-bucket/your-dir/file1

在谷歌云存储中复制对象

如果源和目标 URL 都是来自同一提供者的云 URL,则 gsutil 将数据“在云中”复制(即不下载到并从您运行 gs-wrap 的机器上传)。

在谷歌云存储中复制文件

# your-bucket before:
# gs://your-bucket/file1
client.cp(src="gs://your-bucket/file1",
          dst="gs://your-bucket/your-dir/",
          recursive=True)
# your-bucket after:
# gs://your-bucket/file1
# gs://your-bucket/your-dir/file1

# your-backup-bucket before:
# "empty"
client.cp(src="gs://your-bucket/file1",
          dst="gs://your-backup-bucket/backup-file1",
          recursive=False)
# your-backup-bucket after:
# gs://your-backup-bucket/backup-file1

在谷歌云存储中复制目录

# your-bucket before:
# "empty"
client.cp(src="gs://your-bucket/some-dir/",
dst="gs://your-bucket/another-dir/", recursive=False)
# google.api_core.exceptions.GoogleAPIError: No URLs matched

# your-bucket before:
# gs://your-bucket/some-dir/file1
# gs://your-bucket/some-dir/dir1/file11

# Destination URL without slash
client.cp(src="gs://your-bucket/some-dir/",
dst="gs://your-bucket/another-dir", recursive=True)
# your-bucket after:
# gs://your-bucket/another-dir/file1
# gs://your-bucket/another-dir/dir1/file11

# Destination URL with slash
client.cp(src="gs://your-bucket/some-dir/",
dst="gs://your-bucket/another-dir/", recursive=True)
# your-bucket after:
# gs://your-bucket/another-dir/some-dir/file1
# gs://your-bucket/another-dir/some-dir/dir1/file11

# Choose to copy multi-threaded. (default=False)
client.cp(src="gs://your-bucket/some-dir/",
dst="gs://your-bucket/another-dir", recursive=True, multithreaded=True)
# your-bucket after:
# gs://your-bucket/another-dir/file1
# gs://your-bucket/another-dir/dir1/file11

将对象上传到谷歌云存储

# Your local directory:
# /home/user/storage/file1
# /home/user/storage/file2
# your-bucket before:
# "empty"

client.cp(src="/home/user/storage/",
          dst="gs://your-bucket/local/",
          recursive=True)
# your-bucket after:
# gs://your-bucket/local/storage/file1
# gs://your-bucket/local/storage/file2

从Google Cloud Storage下载对象

import os
# Current your-bucket:
# gs://your-bucket/file1

client.cp(
    src="gs://your-bucket/file1",
    dst="/home/user/storage/file1")

# Your local directory:
# /home/user/storage/file1

带有参数的复制、下载和上传

# Parameter: no_clobber example:
import os

# File content before: "hello"
os.stat("/home/user/storage/file1").st_mtime # 1537947563

client.cp(
    src="gs://your-bucket/file1",
    dst="/home/user/storage/file1",
    no_clobber=True)

# no_clobber option stops from overwriting.
# File content after: "hello"
os.stat("/home/user/storage/file1").st_mtime # 1537947563

client.cp(
    src="gs://your-bucket/file1",
    dst="/home/user/storage/file1",
    no_clobber=False)

# File content after: "hello world"
os.stat("/home/user/storage/file1").st_mtime # 1540889799

# Parameter: recursive and multi-threaded example:
# Your local directory:
# /home/user/storage/file1
# ...
# /home/user/storage/file1000
# your-bucket before:
# "empty"

# Execute normal recursive copy in multiple threads.
client.cp(src="/home/user/storage/",
          dst="gs://your-bucket/local/",
          recursive=True, multithreaded=True)
# your-bucket after:
# gs://your-bucket/local/storage/file1
# ...
# gs://your-bucket/local/storage/file1000

# Parameter: preserve_posix example:
# Your file before:
# /home/user/storage/file1
# e.g. file_mtime: 1547653413 equivalent to 2019-01-16 16:43:33

client.cp(src="/home/user/storage/file1",
          dst="gs://your-backup-bucket/file1",
          preserve_posix=False)
# your-backup-bucket after:
# gs://your-backup-bucket/file1 e.g. "no metadata file_mtime"

# Preserve the POSIX attributes. POSIX attributes are the metadata of a file.
client.cp(src="/home/user/storage/file1",
          dst="gs://your-backup-bucket/file1",
          preserve_posix=True)
# your-backup-bucket after:
# gs://your-backup-bucket/file1 e.g. file_mtime: 2019-01-16 16:43:33

在一个调用中执行多个复制操作

sources_destinations = [
    # Copy on Google Cloud Storage
    ('gs://your-bucket/your-dir/file',
     'gs://your-bucket/backup-dir/file'),

    # Copy from gcs to local
    ('gs://your-bucket/your-dir/file',
     pathlib.Path('/home/user/storage/backup-file')),

    # Copy from local to gcs
    (pathlib.Path('/home/user/storage/new-file'),
     'gs://your-bucket/your-dir/new-file'),

    # Copy locally
    (pathlib.Path('/home/user/storage/file'),
     pathlib.Path('/home/user/storage/new-file'))]

client.cp_many_to_many(srcs_dsts=sources_destinations)

从Google Cloud Storage中删除文件

# your-bucket before:
# gs://your-bucket/file
client.rm(url="gs://your-bucket/file")
# your-bucket after:
# "empty"

# your-bucket before:
# gs://your-bucket/file1
# gs://your-bucket/your-dir/file2
# gs://your-bucket/your-dir/sub-dir/file3
client.rm(url="gs://your-bucket/your-dir", recursive=True)
# your-bucket after:
# gs://your-bucket/file1

在Google Cloud Storage中读写文件

client.write_text(url="gs://your-bucket/file",
                  text="Hello, I'm text",
                  encoding='utf-8')

client.read_text(url="gs://your-bucket/file",
                 encoding='utf-8')
# Hello I'm text

client.write_bytes(url="gs://your-bucket/data",
                   data="I'm important data".encode('utf-8'))

data = client.read_bytes(url="gs://your-bucket/data")
data.decode('utf-8')
# I'm important data

复制文件的os.stat()或blob的元数据

file = pathlib.Path('/home/user/storage/file')
file.touch()
print(file.stat())
# os.stat_result(st_mode=33204, st_ino=19022665, st_dev=64769, st_nlink=1,
# st_uid=1000, st_gid=1000, st_size=0, st_atime=1544015997,
# st_mtime=1544015997, st_ctime=1544015997)

# Upload does not preserve POSIX attributes.
client.cp(src=pathlib.Path('/home/user/storage/file'),
          dst="gs://your-bucket/file")

stats = client.stat(url="gs://your-bucket/file")
stats.creation_time  # 2018-11-21 13:27:46.255000+00:00
stats.update_time  # 2018-11-21 13:27:46.255000+00:00
stats.content_length  # 1024 [bytes]
stats.storage_class  # REGIONAL
stats.file_atime  # None
stats.file_mtime  # None
stats.posix_uid  # None
stats.posix_gid  # None
stats.posix_mode  # None
stats.md5  # b'1B2M2Y8AsgTpgAmY7PhCfg=='
stats.crc32c  # b'AAAAAA=='

# Upload with preserve_posix also copy POSIX attributes to blob.
# POSIX attributes are the metadata of a file.
# It also works for downloading.

client.cp(src=pathlib.Path('/home/user/storage/file'),
            dst="gs://your-bucket/file", preserve_posix=True)

stats = client.stat(url="gs://your-bucket/file")
stats.creation_time  # 2018-11-21 13:27:46.255000+00:00
stats.update_time  # 2018-11-21 13:27:46.255000+00:00
stats.content_length  # 1024 [bytes]
stats.storage_class  # REGIONAL
stats.file_atime  # 2018-11-21 13:27:46
stats.file_mtime  # 2018-11-21 13:27:46
stats.posix_uid  # 1000
stats.posix_gid  # 1000
stats.posix_mode  # 777
stats.md5  # b'1B2M2Y8AsgTpgAmY7PhCfg=='
stats.crc32c  # b'AAAAAA=='

检查复制的文件是否正确

# Check modification time when copied with preserve_posix.
client.same_modtime(path='/home/user/storage/file',
                    url='gs://your-bucket/file')

# Check md5 hash to ensure content equality.
client.same_md5(path='/home/user/storage/file', url='gs://your-bucket/file')

# Retrieve hex digests of MD5 checksums for multiple URLs.
urls = ['gs://your-bucket/file1', 'gs://your-bucket/file2']
client.md5_hexdigests(urls=urls, multithreaded=False)

文档

文档可在readthedocs上找到。

设置

为了使用此库,您需要完成以下步骤

  1. 选择或创建一个云平台项目。

  2. 为您的项目启用计费。

  3. 启用Google Cloud Storage API。

  4. 使用Google Cloud SDK设置身份验证。

安装

  • 使用pip安装gs-wrap

pip3 install gs-wrap

开发

  • 检查存储库。

  • 在存储库根目录中创建虚拟环境

python3 -m venv venv3
  • 激活虚拟环境

source venv3/bin/activate
  • 安装开发依赖项

pip3 install -e .[dev]

我们使用tox进行测试和打包发行版。假设已经激活了虚拟环境并且已经安装了开发依赖项,请运行

tox

预提交检查

我们提供了一组预提交检查,用于检查代码格式和语法。

具体来说,我们使用

从已激活的虚拟环境并安装了开发依赖项的地方本地运行预提交检查

./precommit.py
  • 预提交脚本还可以自动格式化代码

./precommit.py  --overwrite

基准测试

假设已经激活了虚拟环境,已经安装了开发依赖项,并且PYTHONPATH已设置为项目目录,请使用以下命令运行基准测试

./benchmark/main.py *NAME OF YOUR GCS BUCKET*

以下是我们的基准测试结果

基准测试列表10000个文件

测试

时间

加速

gswrap

3.22秒

-

gsutilwrap

3.98秒

1.24倍

基准测试上传10000个文件

测试

时间

加速

gswrap

45.12秒

-

gsutilwrap

34.85秒

0.77倍

基准测试上传多对多500个文件

测试

时间

加速

gswrap

2.14秒

-

gsutilwrap

65.2秒

30.49倍

基准测试下载10000个文件

测试

时间

加速

gswrap

43.92秒

-

gsutilwrap

43.01秒

0.98倍

基准下载多对多500个文件

测试

时间

加速

gswrap

5.85秒

-

gsutilwrap

62.93秒

10.76倍

远程复制1000个文件的基准

测试

时间

加速

gswrap

5.09秒

-

gsutilwrap

4.47秒

0.88倍

远程多对多复制500个文件的基准

测试

时间

加速

gswrap

6.55秒

-

gsutilwrap

62.76秒

9.57倍

基准删除1000个文件

测试

时间

加速

gswrap

3.16秒

-

gsutilwrap

3.66秒

1.16倍

基准读取100个文件

测试

时间

加速

gswrap

16.56秒

-

gsutilwrap

64.73秒

3.91倍

基准写入30个文件

测试

时间

加速

gswrap

2.67秒

-

gsutilwrap

32.55秒

12.17倍

基准统计100个文件

测试

时间

加速

gswrap

6.39秒

-

gsutilwrap

48.15秒

7.53倍

我们所有的基准测试结果都可以在这里找到:这里

版本控制

我们遵循语义版本控制。版本号X.Y.Z表示

  • X是主版本(不向后兼容),

  • Y是次版本(向后兼容),

  • Z是补丁版本(向后兼容的bug修复)。

项目详情


下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。

源代码分发

gs-wrap-1.0.5.tar.gz (25.5 KB 查看哈希值)

上传时间 源代码

由以下支持