First, get the list of all files.
files = ['/path/to/foo.txt.gz.001', '/path/to/foo.txt.gz.002', '/path/to/foo.txt.gz.003']
Then iterate over each file and append to a result file.
with open('./result.gz', 'ab') as result: # append in binary mode
for f in files:
with open(f, 'rb') as tmpf: # open in binary mode also
result.write(tmpf.read())
Then extract is using zipfile lib. You could use tempfile to avoid handle with temporary zip file.
Answer from Mauro Baraldi on Stack OverflowFirst, get the list of all files.
files = ['/path/to/foo.txt.gz.001', '/path/to/foo.txt.gz.002', '/path/to/foo.txt.gz.003']
Then iterate over each file and append to a result file.
with open('./result.gz', 'ab') as result: # append in binary mode
for f in files:
with open(f, 'rb') as tmpf: # open in binary mode also
result.write(tmpf.read())
Then extract is using zipfile lib. You could use tempfile to avoid handle with temporary zip file.
First you must extract all the zip files sequentially:
import zipfile
paths = ["path_to_1", "path_to_2" ]
extract_paths = ["path_to_extract1", "path_to_extrac2"]
for i in range(0, paths):
zip_ref = zipfile.ZipFile(paths[i], 'r')
zip_ref.extractall(extract_paths[i])
zip_ref.close()
Next you can go to the extracted location and read() individual files with open into a string. Concatenate those strings and save to foo.txt.
zip - Unzip gz files within folders in a main folder using python - Stack Overflow
linux - How to unzip multiple gz files in python using multi threading? - Stack Overflow
How to unzip a massive amount of files using Windows Python 2.7?
Why over engineer? Simply gunzip -r a directory of zipped files:
gunzip -r ./directory_of_zipped_files/
EDIT: Sorry ... now noted that you said windows. This is a *nix solution.
More on reddit.comgzip - Unzipping multiple .gz files into single text file using Python - Stack Overflow
I believe that's because gzip never operates over directories, it acts as a compression algorithm unlike zip and tar where we could compress directories. python's implementation of gzip is to operate on files. However recursive traversal of a directory tree is easy if we look at the os.walk call.
(I haven't tested this)
def gunzip(file_path,output_path):
with gzip.open(file_path,"rb") as f_in, open(output_path,"wb") as f_out:
shutil.copyfileobj(f_in, f_out)
def recurse_and_gunzip(root):
walker = os.walk(root)
for root,dirs,files in walker:
for f in files:
if fnmatch.fnmatch(f,"*.gz"):
gunzip(f,f.replace(".gz",""))
It may not answer this specific question, but for those looking to extract a gzipped directory structure: that would be a job for shutil.unpack_archive.
For example:
import shutil
shutil.unpack_archive(
filename='path/to/archive.tar.gz', extract_dir='where/to/extract/to'
)
You can do this very easily with multiprocessing Pools:
import gzip
import multiprocessing
import shutil
filenames = [
'a.gz',
'b.gz',
'c.gz',
...
]
def uncompress(path):
with gzip.open(path, 'rb') as src, open(path.rstrip('.gz'), 'wb') as dest:
shutil.copyfileobj(src, dest)
with multiprocessing.Pool() as pool:
for _ in pool.imap_unordered(uncompress, filenames, chunksize=1):
pass
This code will spawn a few processes, and each process will extract one file at a time.
Here I've chosen chunksize=1, to avoid stalling processes if some files are bigger than average.
A large segment of of the wall clock time spent decompressing a file with gunzip or gzip -d will be from the I/O operations (reading and writing to disk). It might even be more than the time spent actually decompressing data. You can take advantage of this by having multiple gzip jobs going in the background. As some jobs are blocked on I/O, another job can actually run without having to wait in a queue.
You can speed up the decompressing of the entire file set by having multiple gunzip processes running in the background. Each serving a specific set of files.
You can whip up something easy in BASH. Split the file list into separate commands and use the & to start it as a background job. Then wait for each each job to finish.
I would recommend that you have between 2 to 2*N jobs going at once. Where N is the number of cores or logical processors on your computer. Experiment as appropriate to get the right number.
You can whip something up easy in BASH.
#!/bin/bash
argarray=( "$@" )
len=${#argarray[@]}
#declare 4 empty array sets
set1=()
set2=()
set3=()
set4=()
# enumerate over each argument passed to the script
# and round robin add it to one of the above arrays
i=0
while [
len ]
do
if [
len ]; then
set1+=( "${argarray[$i]}" )
((i++))
fi
if [
len ]; then
set2+=( "${argarray[$i]}" )
((i++))
fi
if [
len ]; then
set3+=( "${argarray[$i]}" )
((i++))
fi
if [
len ]; then
set4+=( "${argarray[$i]}" )
((i++))
fi
done
# for each array, start a background job
gzip -d ${set1[@]} &
gzip -d ${set2[@]} &
gzip -d ${set3[@]} &
gzip -d ${set4[@]} &
# wait for all jobs to finish
wait
In the above example, I picked 4 files per job and started two separate jobs. You can easily extend the script to have more jobs, more files per process, and to take the file names as command line parameters.
I have millions of zip files (.gz extension) that I need EXTRACTED. Each of the zip files has one .txt file in them and I need that .txt file to use in data analysis. Unzipping them manually would take weeks, does anyone have an easily modifiable script out there that they are willing to share? I have very little experience with Python. Thank you in advance.
Edit: should have said "Extract" instead of "unzip."
Why over engineer? Simply gunzip -r a directory of zipped files:
gunzip -r ./directory_of_zipped_files/
EDIT: Sorry ... now noted that you said windows. This is a *nix solution.
Can you install cygwin? If so, you may be able to just do something simple from the commandline using xargs and a commandline extractor.
Just shuffle f_out to the outside, so you open it before iterating over the input files and keep that one handle open.
from glob import glob
import gzip
with open('.../datafiles/202004_twitter/decompressed.txt', 'wb') as f_out:
for fname in glob('.../2020-04/*gz'):
with gzip.open(fname, 'rb') as f_in:
shutil.copyfileobj(f_in, f_out)
Use "wba" mode instead. a opens in append mode. w alone will erase the file upon opening.
Hi All,
I am a beginner with Python trying to solve a few problems with my daily workflow in a non-tech job. I recently wrote a script that I feel could use some improvement, but I am not knowledgeable enough to know how to make it more efficient.
Background: I sometimes need to download multiple large compressed .txt.gz files from our server and convert them into .csv before I offload them to other business units for review. Instead of extracting manually and pasting into Excel, I wanted to write a script to take care of it. Here is what I came up with after some YouTube and StackOverflow searching (the delimiter in these txt files is a '|' instead of the standard ',':
import csv
import shutil
import gzip
import os
src_dir = 'C:\\Users\\user\\Downloads\\'
dest_dir = 'C:\\Users\\user\\Desktop\\Python\\extractedgzs\\'
f_names = []
# get file names
for files in os.listdir(src_dir):
if files.endswith('.txt.gz'):
f_names.append(files)
#file found confirmation
print('found these files:')
print(f_names)
# unzip gz file to dest dir
for name in f_names:
with gzip.open(src_dir+name, 'rb') as f_in:
with open(dest_dir+name[0:-6], 'wb') as f_out:
shutil.copyfileobj(f_in, f_out)
# extracted file to .csv
with open(dest_dir+name[0:-6], 'r') as in_file:
stripped = (line.strip() for line in in_file)
lines = (line.split("|") for line in stripped if line)
with open(dest_dir+name[0:-6]+'csv', 'w', newline='') as out_file:
writer = csv.writer(out_file)
writer.writerows(lines)I understand that this code is rather rigid but that it is fine since I am the only person who will ever use it and it only needs to serve this one purpose.
The main issue I have with this is that I generate an text file that is used up by the splitter/csv writer for writing the csv. I was wondering if there is any way to eliminate this step, or at the very least automate deleting that file once all the csv's are written.
I appreciate any tips you can offer!
gzip only supports compressing a single file or stream. In your case, the extracted stream is a tar object, so you'd use Python's tarfile library to manipulate the extracted contents. This library actually knows how to cope with .tar.gz so you don't need to explicitly extract the gzip yourself.
Use Python's tarfile to get the contained files, and then Python's gzip again inside the loop to extract the xml.
You can use below command.
Go to the directory where your .gz file is and run command:
for f in *.gz ; do gunzip -c "$f" > /home/$USER/"${f%.*}" ; done
It will extract all file with original name and store it to current user home directory(/home/username). You can change it to somewhere else.
EDIT :
gunzip *.gz
This command also will work. But, by default, it replaces original file.
Option # 1 : unzip multiple files using single quote (short version)
gunzip '*.gz'
Note that *.gz word is put in between two single quote, so that shell will not recognize it as a wild card character.
Option # 2 : unzip multiple files using shell for loop (long version)
for g in *.gz; do gunzip $g; done
The Source
EDIT :
I have just tried :
gunzip -dk *.gz
and it worked.
-d to decompress and k to keep original files.