38

How can I read and save the contents of 7z. I use Python 2.7.9, I can extract or Archive like this, but I can't read contents in python, I only listing the file's contents in CMD

import subprocess
import os

source = 'filename.7z'
directory = 'C:\Directory'
pw = '123456'
subprocess.call(r'"C:\Program Files (x86)\7-Zip\7z.exe" x '+source +' -o'+directory+' -p'+pw)
snakecharmerb
  • 47,570
  • 11
  • 100
  • 153
Ken Kem
  • 635
  • 1
  • 6
  • 13
  • possible duplicate of [Python - how to compress with 7zip instead of zip, code changing](http://stackoverflow.com/questions/11466572/python-how-to-compress-with-7zip-instead-of-zip-code-changing) – John Zwinck Sep 26 '15 at 13:59

7 Answers7

23

If you can use python 3, there is a useful library, py7zr, which supports 7zip archive compression, decompression, encryption and decryption.

import py7zr
with py7zr.SevenZipFile('sample.7z', mode='r') as z:
    z.extractall()
Zhou Hongbo
  • 1,297
  • 13
  • 25
7

I ended up in this situation where I was forced to use 7z, and also needed to know exactly which files were extracted from each zip archive. To deal with this, you can check the output of the call to 7z and look for the filenames. Here's what the output of 7z looks like:

$ 7z l sample.zip

7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=utf8,Utf16=on,HugeFiles=on,64 bits,8 CPUs x64)

Scanning the drive for archives:
1 file, 472 bytes (1 KiB)

Listing archive: sample.zip

--
Path = sample.zip
Type = zip
Physical Size = 472

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2018-12-01 17:09:59 .....            0            0  sample1.txt
2018-12-01 17:10:01 .....            0            0  sample2.txt
2018-12-01 17:10:03 .....            0            0  sample3.txt
------------------- ----- ------------ ------------  ------------------------
2018-12-01 17:10:03                  0            0  3 files

and how to parse that output with python:

import subprocess

def find_header(split_line):
    return 'Name' in split_line and 'Date' in split_line

def all_hyphens(line):
    return set(line) == set('-')

def parse_lines(lines):
    found_header = False
    found_first_hyphens = False
    files = []
    for line in lines:

        # After the header is a row of hyphens
        # and the data ends with a row of hyphens
        if found_header:
            is_hyphen = all_hyphens(''.join(line.split()))

            if not found_first_hyphens:
                found_first_hyphens = True
                # now the data starts
                continue

            # Finding a second row of hyphens means we're done
            if found_first_hyphens and is_hyphen:
                return files

        split_line = line.split()

        # Check for the column headers
        if find_header(split_line):
            found_header=True
            continue

        if found_header and found_first_hyphens:
            files.append(split_line[-1])
            continue

    raise ValueError("We parsed this zipfile without finding a second row of hyphens")



byte_result=subprocess.check_output('7z l sample.zip', shell=True)
str_result = byte_result.decode('utf-8')
line_result = str_result.splitlines()
files = parse_lines(line_result)
Kyle Heuton
  • 9,318
  • 4
  • 40
  • 52
  • 5
    Note this whole code can be reduced to `[l.split()[-1] for l in str_result.rsplit("\n\n",1)[-1].splitlines()[2:-2]]`. – bfontaine Oct 05 '19 at 14:08
6

You can use either libarchive or pylzma. If you can upgrade to python3.3+ you can use lzma, which is in the standard library.

mr nick
  • 554
  • 2
  • 9
  • 2
    I alway use python 2.7.9, I don't know 3.3+ has standard library for 7z, so thank you so much – Ken Kem Sep 26 '15 at 14:52
  • 60
    Note that lzma doesn’t work with 7z *archives*, only single files. – bfontaine Apr 22 '16 at 09:42
  • 17
    So lzma is not the right library and I just wasted time to make it work. Downvote. – shinzou Dec 23 '17 at 13:01
  • 3
    `libarchive` will not work on **Windows** by default. It will fail installing with this error: `Library can not be loaded: Could not find module 'libarchive.so'.`... You have to compile libarchive.dll yourself and add it - as well as several other .dlls it relies upon - to some folder recognized by your system PATH. – user136036 Jan 15 '20 at 23:09
3

you can Use pyunpack and patool library

!pip install pyunpack
!pip install patool
from pyunpack import Archive
Archive('7z file source').extractall('destination')

refer

https://pypi.org/project/patool/
https://pypi.org/project/pyunpack/

Farhang Amaji
  • 742
  • 11
  • 24
Ruman Khan
  • 61
  • 4
1

Shelling out and calling 7z will extract files and then you can open() those files.

If you want to look inside a 7z archive directly within Python, then you'll need to use a library. Here's one: https://pypi.python.org/pypi/libarchive - I can't vouch for it as I said - I'm not a Python user - but using a 3rd party library is usually pretty easy in all languages.

Generally, 7z Support seems limited. If you can use alternative formats (zip/gzip) then I think you'll find the range of Python libraries (and example code) is more comprehensive.

Hope that helps.

PoolloverNathan
  • 148
  • 2
  • 11
EyePeaSea
  • 185
  • 9
  • In practice using 7z is very useful via the subprocess module, you really have to test the 7zip command from the command line individually. and rely on the documentation to structure the command correctly. Once you understand how to form the 7z command line command, you are ready to build your subprocess command in Python. – cdabel Oct 14 '19 at 20:01
0

Here is how I get the list of all files in test.7z with Python:

from subprocess import Popen, PIPE
proc = Popen([r"C:\Program Files\7-Zip\7z.exe", "l", "-ba", "-slt", "test.7z"], stdout=PIPE)
files = [l.split('Path = ')[1] for l in proc.stdout.read().decode().splitlines() if l.startswith('Path = ')]

following the method from List zip file's contents using 7zip command line with non-verbose machine-friendly output.

This is a useful solution in the case you don't want to install another dependency package.

Basj
  • 41,386
  • 99
  • 383
  • 673
0

Extract all the .7z files in a directory by doing this.

First, install

!pip install patool
!pip install pyunpack

And then

import os
from pyunpack import Archive

path = "path_to_file"
file_type = '.7z'

for filename in os.listdir(path=path):
    if filename.endswith(file_type):
        print(filename)
        print(f"{path}/{filename}")
        Archive(f"{path}/{filename}").extractall(f"{path}")```