У меня есть файл tar, в котором есть несколько файлов. Мне нужно написать скрипт Python, который будет читать содержимое файлов и подсчитывать общее количество символов, включая общее количество букв, пробелов, символов новой строки и т. д., без распаковки tar-файла.
чтение содержимого tar-файла без его распаковки в скрипте python
Ответы (4)
вы можете использовать getmembers()
>>> import tarfile
>>> tar = tarfile.open("test.tar")
>>> tar.getmembers()
После этого вы можете использовать extractfile()
для извлечения членов как файлового объекта. Просто пример
import tarfile,os
import sys
os.chdir("/tmp/foo")
tar = tarfile.open("test.tar")
for member in tar.getmembers():
f=tar.extractfile(member)
content=f.read()
print "%s has %d newlines" %(member, content.count("\n"))
print "%s has %d spaces" % (member,content.count(" "))
print "%s has %d characters" % (member, len(content))
sys.exit()
tar.close()
С файловым объектом f
в приведенном выше примере вы можете использовать read()
, readlines()
и т. д.
'r|'
.
- person devsnd; 21.05.2012
tar.members = []
. Дополнительная информация здесь: bit.ly/JKXrg6
- person devsnd; 21.05.2012
tar.getmembers()
вызываться несколько раз, если поместить его в цикл for member in tar.getmembers()
?
- person Haifeng Zhang; 04.03.2015
extractfile
не предоставляет атрибут encoding
, если вам нужен текстовый поток, вы можете сделать f = codecs.getreader("utf-8")(f)
.
- person Thomas Ahle; 18.07.2019
вам нужно использовать модуль tarfile. В частности, вы используете экземпляр класса TarFile для доступа к файлу, а затем получаете доступ к именам с помощью TarFile.getnames().
| getnames(self)
| Return the members of the archive as a list of their names. It has
| the same order as the list returned by getmembers().
Если вместо этого вы хотите прочитать контент, используйте этот метод
| extractfile(self, member)
| Extract a member from the archive as a file object. `member' may be
| a filename or a TarInfo object. If `member' is a regular file, a
| file-like object is returned. If `member' is a link, a file-like
| object is constructed from the link's target. If `member' is none of
| the above, None is returned.
| The file-like object is read-only and provides the following
| methods: read(), readline(), readlines(), seek() and tell()
Ранее в этом посте был показан пример dict(zip(()) объединения имен членов и списков членов вместе, это глупо и приводит к чрезмерному чтению архива, чтобы добиться того же, мы можем использовать понимание словаря:
index = {i.name: i for i in my_tarfile.getmembers()}
Дополнительная информация о том, как использовать tarfile
Извлечь элемент tarfile
#!/usr/bin/env python3
import tarfile
my_tarfile = tarfile.open('/path/to/mytarfile.tar')
print(my_tarfile.extractfile('./path/to/file.png').read())
Индексировать tar-файл
#!/usr/bin/env python3
import tarfile
import pprint
my_tarfile = tarfile.open('/path/to/mytarfile.tar')
index = my_tarfile.getnames() # a list of strings, each members name
# or
# index = {i.name: i for i in my_tarfile.getmembers()}
pprint.pprint(index)
Индексировать, читать, динамически добавлять tar-файл
#!/usr/bin/env python3
import tarfile
import base64
import textwrap
import random
# note, indexing a tar file requires reading it completely once
# if we want to do anything after indexing it, it must be a file
# that can be seeked (not a stream), so here we open a file we
# can seek
my_tarfile = tarfile.open('/path/to/mytar.tar')
# tarfile.getmembers is similar to os.stat kind of, it will
# give you the member names (i.name) as well as TarInfo attributes:
#
# chksum,devmajor,devminor,gid,gname,linkname,linkpath,
# mode,mtime,name,offset,offset_data,path,pax_headers,
# size,sparse,tarfile,type,uid,uname
#
# here we use a dictionary comprehension to index all TarInfo
# members by the member name
index = {i.name: i for i in my_tarfile.getmembers()}
print(index.keys())
# pick your member
# note: if you can pick your member before indexing the tar file,
# you don't need to index it to read that file, you can directly
# my_tarfile.extractfile(name)
# or my_tarfile.getmember(name)
# pick your filename from the index dynamically
my_file_name = random.choice(index.keys())
my_file_tarinfo = index[my_file_name]
my_file_size = my_file_tarinfo.size
my_file_buf = my_tarfile.extractfile(
my_file_name
# or my_file_tarinfo
)
print('file_name: {}'.format(my_file_name))
print('file_size: {}'.format(my_file_size))
print('----- BEGIN FILE BASE64 -----'
print(
textwrap.fill(
base64.b64encode(
my_file_buf.read()
).decode(),
72
)
)
print('----- END FILE BASE64 -----'
tarfile с повторяющимися членами
в случае, если у нас есть tar, который был создан странно, в этом примере, добавляя много версий одного и того же файла в один и тот же tar-архив, мы можем работать с этим осторожно, я аннотировал, какие члены содержат какой текст, скажем, мы нужен четвертый (индекс 3) участник, захватите флаг\n
tar -tf mybadtar.tar
mymember.txt # "version 1\n"
mymember.txt # "version 1\n"
mymember.txt # "version 2\n"
mymember.txt # "capturetheflag\n"
mymember.txt # "version 3\n"
#!/usr/bin/env python3
import tarfile
my_tarfile = tarfile.open('mybadtar.tar')
# >>> my_tarfile.getnames()
# ['mymember.txt', 'mymember.txt', 'mymember.txt', 'mymember.txt', 'mymember.txt']
# if we use extracfile on a name, we get the last entry, I'm not sure how python is smart enough to do this, it must read the entire tar file and buffer every valid member and return the last one
# >>> my_tarfile.extractfile('mymember.txt').read()
# b'version 3\n'
# >>> my_tarfile.extractfile(my_tarfile.getmembers()[3]).read()
# b'capturetheflag\n'
В качестве альтернативы мы можем перебрать файл tar #!/usr/bin/env python3
import tarfile
my_tarfile = tarfile.open('mybadtar.tar')
# note, if we do anything to the tarfile object that will
# cause a full read, the tarfile.next() method will return none,
# so call next in a loop as the first thing you do if you want to
# iterate
while True:
my_member = my_tarfile.next()
if not my_member:
break
print((my_member.offset, mytarfile.extractfile(my_member).read,))
# (0, b'version 1\n')
# (1024, b'version 1\n')
# (2048, b'version 2\n')
# (3072, b'capturetheflag\n')
# (4096, b'version 3\n')
myArchive.extractfile('my/member/name.png')
напрямую
- person ThorSummoner; 31.01.2021
вы можете использовать tarfile.list() например:
filename = "abc.tar.bz2"
with open( filename , mode='r:bz2') as f1:
print(f1.list())
после получения этих данных. вы можете манипулировать этим выводом или записывать его в файл и делать все, что вам нужно.