I am trying to zip the files from the list localpath_list in to one zip file `reports.zip.
It works as expected, but when I extract the reports.zip file, there are folders created inside it.
i.e all the .xls files are under files/sample/.
what I need is just the .xls files without any folder structure.
localpath_list = ["files/sample/sample1.xls", "files/sample/sample2.xls", "files/sample/sample3.xls"]
with zipfile.ZipFile(fr"downloads/reports.zip", 'w') as zipF:
for file in localpath_list:
zipF.write(file, compress_type=zipfile.ZIP_DEFLATED)
According to: [Python.Docs]: zipfile - ZipFile.write(filename, arcname=None, compress_type=None, compresslevel=None) (emphasis is mine):
Write the file named filename to the archive, giving it the archive name arcname (by default, this will be the same as filename, ...
So you should use:
zipF.write(file, arcname=os.path.basename(file), compress_type=zipfile.ZIP_DEFLATED)
If expanding the functionality (to include files from multiple folders) is in plan, you should pay attention to duplicate file base names (in different folders).
Related
There a technic of store ZIP archive concatenated with some other file (e. g. with EXE to store additional resources or with JPEG for steganography). Python's ZipFile supports such files (e. g. if you open ZipFile in "a" mode on non-ZIP file, it will append ZIP headers to the end). I would like to update such archive (possible add, update and delete files from ZIP archive).
Python's ZipFile doesn't support deleting and overriding of the files inside the archive, only appending, so the only way for me is completely recreate ZIP file with new contents. But I need to conserve the main file in which ZIP was embedded. If I just open it in "w" mode, the whole file has completed overridden.
I need a way how to remove a ZIP file from the end of an ordinary file. I'd prefer use only functions which are available in Python 3 standard library.
I found a solution:
min_header_offset = None
with ZipFile(output_filename, "r") as zip_file:
for info in zip_file.infolist():
if min_header_offset is None or info.header_offset < min_header_offset:
min_header_offset = info.header_offset
# Here also possible to save existing files if them needed for update
if min_header_offset is not None:
with open(output_filename, "r+b") as f:
f.truncate(min_header_offset)
# Somehow populate new archive contents
with ZipFile(args.output, "a") as zip_file:
for input_filename in input_filenames:
zip_file.write(input_filename)
It clears the archive, but don't touch anything what is going before the archive.
I'm trying to create a zip folder with a .txt file in it. But when I open test_20210616.zip, test is available as a folder and not as a .txt file.
with zipfile.ZipFile('/dbfs/Test/test_20210616.zip', 'w', allowZip64 = True) as z:
z.write('/dbfs/Test/','test.txt')
In the docs of zipfile the function ZipFile.write looks as follows
ZipFile.write(filename, arcname=None, compress_type=None, compresslevel=None)
Since you are calling it with z.write('/dbfs/Test/','test.txt') you are writing the folder /dbfs/Test/ into the zip file and giving it the name text.txt
Simply pass the whole path to the file as the first argument.
I want to create a zip file of some files somewhere on the disk in python. I successfully got the path to the folder and each file name so I did:
with zp(os.path.join(self.savePath, self.selectedIndex + ".zip"), "w") as zip:
for file in filesToZip:
zip.write(self.folderPath + file)
Everything works fine, but the zipfile that is output contains the entire folder structure leading up to the files. Is there a way to only zip the files and not the folders with it?
From the documentation:
ZipFile.write(filename, arcname=None, compress_type=None,
compresslevel=None)
Write the file named filename to the archive, giving it the archive
name arcname (by default, this will be the same as filename, but
without a drive letter and with leading path separators removed).
So, just specify an explicit arcname:
with zp(os.path.join(self.savePath, self.selectedIndex + ".zip"), "w") as zip:
for file in filesToZip:
zip.write(self.folderPath + file, arcname=file)
Maybe I' misunderstand the question but could someone explain to me why the answer is not:
zip.write(file, arcname=os.path.basename(file))
It works for me but, again, I might be missing something in the question...
Say you unzip a file called file123.zip with zipfile.ZipFile, which yields an unzipped file saved to a known path. However, this unzipped file has a completely random name. How do you determine this completely random filename? Or is there some way to control what the name of the unzipped file is?
I am trying to implement this in python.
By "random" I assume that you mean that the files are named arbitrarily.
You can use ZipFile.read() which unzips the file and returns its contents as a string of bytes. You can then write that string to a named file of your choice.
from zipfile import ZipFile
with ZipFile('file123.zip') as zf:
for i, name in enumerate(zf.namelist()):
with open('outfile_{}'.format(i), 'wb') as f:
f.write(zf.read(name))
This will write each file from the archive to a file named output_n in the current directory. The names of the files contained in the archive are obtained with ZipFile.namelist(). I've used enumerate() as a simple method of generating the file names, however, you could substitute that with whatever naming scheme you require.
If the filename is completely random you can first check for all filenames in a particular directory using os.listdir(). Now you know the filename and can do whatever you want with it :)
See this topic for more information.
I'm using python's zipfile module.
Having a zip file located in a path of:
/home/user/a/b/c/test.zip
And having another file created under /home/user/a/b/c/1.txt
I want to add this file to existing zip, I did:
zip = zipfile.ZipFile('/home/user/a/b/c/test.zip','a')
zip.write('/home/user/a/b/c/1.txt')
zip.close()`
And got all the subfolders appears in path when unzipping the file, how do I just enter the zip file without path's subfolders?
I tried also :
zip.write(os.path.basename('/home/user/a/b/c/1.txt'))
And got an error that file doesn't exist, although it does.
You got very close:
zip.write(path_to_file, os.path.basename(path_to_file))
should do the trick for you.
Explanation: The zip.write function accepts a second argument (the arcname) which is the filename to be stored in the zip archive, see the documentation for zipfile more details.
os.path.basename() strips off the directories in the path for you, so that the file will be stored in the archive under just it's name.
Note that if you only zip.write(os.path.basename(path_to_file)) it will look for the file in the current directory where it (as the error says) does not exist.
import zipfile
# Open a zip file at the given filepath. If it doesn't exist, create one.
# If the directory does not exist, it fails with FileNotFoundError
filepath = '/home/user/a/b/c/test.zip'
with zipfile.ZipFile(filepath, 'a') as zipf:
# Add a file located at the source_path to the destination within the zip
# file. It will overwrite existing files if the names collide, but it
# will give a warning
source_path = '/home/user/a/b/c/1.txt'
destination = 'foobar.txt'
zipf.write(source_path, destination)