S3:如何在不下载完整文件的情况下进行部分读取/查找?

S3: How to do a partial read / seek without downloading the complete file?

虽然它们类似于文件,但 Amazon S3 中的对象并不是真正的 "files",就像 S3 存储桶不是真正的目录一样。在 Unix 系统上,我可以使用 head 来预览文件的前几行,无论它有多大,但我不能在 S3 上这样做。那么如何在 S3 上进行部分读取?

S3 文件可能很大,但您不必为了读取前几个字节而获取整个文件。 S3 API 支持 HTTP Range: header (see RFC 2616),它采用字节范围参数。

只需将 Range: bytes=0-NN header 添加到您的 S3 请求,其中 NN 是请求读取的字节数,您将只获取这些字节而不是读取整个文件。现在,您可以预览留在 S3 存储桶中的 900 GB CSV 文件,而无需等待整个文件下载完毕。阅读 the full GET Object docs 亚马逊的开发者文档。

AWS .Net SDK 仅显示 fixed-ended 个范围是可能的(回复:public ByteRange(long start, long end))。如果我想从中间开始读到最后怎么办? Range: bytes=1000- 的 HTTP 范围对于 "start at 1000 and read to the end" 是完全可以接受的,我不相信他们在 .Net 库中允许这样做。

使用Python可以预览压缩文件的第一条记录。

使用 boto 连接。

#Connect:
s3 = boto.connect_s3()
bname='my_bucket'
self.bucket = s3.get_bucket(bname, validate=False)

从 gzip 压缩文件中读取前 20 行

#Read first 20 records
limit=20
k = Key(self.bucket)
k.key = 'my_file.gz'
k.open()
gzipped = GzipFile(None, 'rb', fileobj=k)
reader = csv.reader(io.TextIOWrapper(gzipped, newline="", encoding="utf-8"), delimiter='^')
for id,line in enumerate(reader):
    if id>=int(limit): break
    print(id, line)

所以它等同于以下 Unix 命令:

zcat my_file.gz|head -20

get_object api 有部分读取的 arg

s3 = boto3.client('s3')
resp = s3.get_object(Bucket=bucket, Key=key, Range='bytes={}-{}'.format(start_byte, stop_byte-1))
res = resp['Body'].read()