Как вывести список файлов внутри tar в AWS S3, не загружая его? - PullRequest
4 голосов
/ 11 мая 2019

При поиске идей я нашел https://stackoverflow.com/a/54222447/264822 для zip-файлов, что я считаю очень умным решением.Но он опирается на zip-файлы, имеющие Central Directory - tar-файлы не.

Я думал, что смогу следовать тому же общему принципу и выставить файл S3 на tarfile через параметр fileobj:

import boto3
import io
import tarfile

class S3File(io.BytesIO):
    def __init__(self, bucket_name, key_name, s3client):
        super().__init__()
        self.bucket_name = bucket_name
        self.key_name = key_name
        self.s3client = s3client
        self.offset = 0

    def close(self):
        return

    def read(self, size):
        print('read: offset = {}, size = {}'.format(self.offset, size))
        start = self.offset
        end = self.offset + size - 1
        try:
            s3_object = self.s3client.get_object(Bucket=self.bucket_name, Key=self.key_name, Range="bytes=%d-%d" % (start, end))
        except:
            return bytearray()
        self.offset = self.offset + size
        result = s3_object['Body'].read()
        return result

    def seek(self, offset, whence=0):
        if whence == 0:
            print('seek: offset {} -> {}'.format(self.offset, offset))
            self.offset = offset

    def tell(self):
        return self.offset

s3file = S3File(bucket_name, file_name, s3client)
tarf = tarfile.open(fileobj=s3file)
names = tarf.getnames()
for name in names:
    print(name)

Это работает нормально, за исключением того, что вывод выглядит следующим образом:

read: offset = 0, size = 2
read: offset = 2, size = 8
read: offset = 10, size = 8192
read: offset = 8202, size = 1235
read: offset = 9437, size = 1563
read: offset = 11000, size = 3286
read: offset = 14286, size = 519
read: offset = 14805, size = 625
read: offset = 15430, size = 1128
read: offset = 16558, size = 519
read: offset = 17077, size = 573
read: offset = 17650, size = 620
(continued)

tarfile все равно просто читает весь файл, поэтому я ничего не получил,Есть ли способ заставить tarfile читать только те части файла, которые ему нужны?Единственная альтернатива, о которой я могу подумать, - это повторно реализовать синтаксический анализ файла tar, чтобы он:

  1. Считывает заголовок 512 байт и записывает его в буфер BytesIO.
  2. Получаетразмер следующего файла и записывает нули в буфер BytesIO.
  3. Пропускает файл до следующего заголовка.

Но это кажется слишком сложным.

1 Ответ

0 голосов
/ 11 мая 2019

Моя ошибка.Я на самом деле имею дело с файлами tar.gz, но я предположил, что zip и tar.gz похожи.Это не так - tar - это архивный файл, который затем сжимается в gzip, поэтому, чтобы прочитать tar, сначала нужно его распаковать.Моя идея извлечь биты из файла tar не будет работать.

Что работает:

s3_object = s3client.get_object(Bucket=bucket_name, Key=file_name)
wholefile = s3_object['Body'].read()
fileobj = io.BytesIO(wholefile)
tarf = tarfile.open(fileobj=fileobj)
names = tarf.getnames()
for name in names:
    print(name)

Я подозреваю, что оригинальный код будет работать для файла tar, но я неТому не придётся это попробовать.

...