سؤال

لدي ملف مضغوط الذي يحتوي على بنية الدليل التالي:

dir1\dir2\dir3a
dir1\dir2\dir3b

أحاول فك الضغط و الحفاظ على بنية الدليل ومع ذلك أحصل على الخطأ:

IOError: [Errno 2] No such file or directory: 'C:\\\projects\\\testFolder\\\subdir\\\unzip.exe'

حيث testFolder هو dir1 أعلاه subdir هو dir2.

هل هناك طريقة سريعة حيويي الملف و الحفاظ على بنية الدليل?

هل كانت مفيدة؟

المحلول

والمقتطف وطرق extractall كبيرة إذا كنت على بيثون 2.6. لا بد لي من استخدام بايثون 2.5 في الوقت الحالي، لذلك أنا فقط بحاجة إلى إنشاء الدلائل إذا لم تكن موجودة. يمكنك الحصول على قائمة من الدلائل مع أسلوب namelist(). فإن الدلائل تنتهي دائما مع مائل (حتى على ويندوز) منها مثلا.

import os, zipfile

z = zipfile.ZipFile('myfile.zip')
for f in z.namelist():
    if f.endswith('/'):
        os.makedirs(f)

وربما كنت لا تريد أن تفعل ذلك بالضبط من هذا القبيل (أي، كنت ربما تريد استخراج محتويات ملف مضغوط كما كنت تكرار عبر قائمة بأسماء)، ولكن يمكنك الحصول على الفكرة.

نصائح أخرى

لا الثقة استخراج() أو extractall().

هذه الأساليب عمياء استخراج الملفات إلى مسارات معينة في أسماء الملفات.ولكن الرمز البريدي الملفات يمكن أن يكون أي شيء على الإطلاق ، بما في ذلك خطرا سلاسل مثل "x/../../../etc/passwd".استخراج هذه الملفات هل يمكن أن يكون مجرد الشبهة الملقم الخاص بك بأكمله.

ربما ينبغي أن يكون هذا يعتبر الإبلاغ عنها ثغرة أمنية في بايثون zipfile وحدة ، ولكن أي عدد من الرمز البريدي dearchivers أظهرت نفس السلوك في الماضي.إلى المقالة ملف مضغوط مع بنية المجلد بأمان تحتاج في العمق التحقق من كل مسار الملف.

حاولت هذا و يمكن أن تتكاثر.على extractall طريقة ، كما اقترح إجابات أخرى, لا لا حل مشكلة.يبدو أن هذا الخلل في zipfile وحدة لي (ربما ويندوز فقط), إلا أنا سوء الفهم كيف zipfiles مهيكلة.

testa\
testa\testb\
testa\testb\test.log
> test.zip

>>> from zipfile import ZipFile
>>> zipTest = ZipFile("C:\\...\\test.zip")
>>> zipTest.extractall("C:\\...\\")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "...\zipfile.py", line 940, in extractall
  File "...\zipfile.py", line 928, in extract
  File "...\zipfile.py", line 965, in _extract_member
IOError: [Errno 2] No such file or directory: 'C:\\...\\testa\\testb\\test.log'

إذا كنت تفعل printdir(), أنا الحصول على هذا (العمود الأول):

>>> zipTest.printdir()
File Name
testa/testb/
testa/testb/test.log

إذا كنت في محاولة استخراج أول دخول مثل هذا:

>>> zipTest.extract("testa/testb/")
'C:\\...\\testa\\testb'

على القرص, هذه النتائج في إنشاء مجلد testa, ، الملف testb في الداخل.هذا هو على ما يبدو السبب اللاحقة محاولة استخراج test.log فشل; testa\testb هو ملف وليس مجلد.

تحرير #1:إذا كنت استخراج مجرد ملف ، ثم يعمل:

>>> zipTest.extract("testa/testb/test.log")
'C:\\...\\testa\\testb\\test.log'

تحرير #2:جيف كود هو الطريق للذهاب ، من خلال تكرار namelist;إذا كان دليل إنشاء الدليل.وإلا استخراج الملف.

وأنا أعلم أنه قد يكون قليلا في وقت متأخر أن أقول هذا ولكن جيف هو الصحيح. انها بسيطة مثل:

import os
from zipfile import ZipFile as zip

def extractAll(zipName):
    z = zip(zipName)
    for f in z.namelist():
        if f.endswith('/'):
            os.makedirs(f)
        else:
            z.extract(f)

if __name__ == '__main__':
    zipList = ['one.zip', 'two.zip', 'three.zip']
    for zip in zipList:
        extractAll(zipName)

وهناك طريقة سهلة جدا إذا كنت تستخدم بايثون 2.6: في extractall الأسلوب.

ولكن، منذ يتم تنفيذ وحدة zipfile تماما في بيثون دون أي ملحقات C، ربما يمكنك نسخه من تثبيت 2.6 و استخدامه مع نسخة قديمة من بيثون. قد تجد هذا أسهل من الاضطرار إلى reimplement وظيفة نفسك. ومع ذلك، فإن وظيفة نفسها قصيرة جدا:

def extractall(self, path=None, members=None, pwd=None):
    """Extract all members from the archive to the current working
       directory. `path' specifies a different directory to extract to.
       `members' is optional and must be a subset of the list returned
       by namelist().
    """
    if members is None:
        members = self.namelist()

    for zipinfo in members:
        self.extract(zipinfo, path, pwd)

ويبدو أنك تحاول تشغيل بفك لاستخراج البريدي.

وسيكون من الأفضل لاستخدام الثعبان zipfile حدة، وبالتالي القيام استخراج في بيثون.

import zipfile

def extract(zipfilepath, extractiondir):
    zip = zipfile.ZipFile(zipfilepath)
    zip.extractall(path=extractiondir)

تصفية قائمة بأسماء استبعاد المجلدات

وكل ما عليك القيام به هو تصفية إدخالات namelist() تنتهي مع / ويتم حل المشكلة:

  z.extractall(dest, filter(lambda f: not f.endswith('/'), z.namelist()))

ومنتديات الشاعر تركي الميزاني!

إذا مثلي، لديك لاستخراج أرشيف مضغوط الكامل مع إطلاق بيثون كبار السن (في حالتي، 2.4) وهنا ما خطرت لي (على أساس الإجابة جيف):

import zipfile
import os

def unzip(source_file_path, destination_dir):
    destination_dir += '/'
    z = zipfile.ZipFile(source_file_path, 'r')
    for file in z.namelist():
        outfile_path = destination_dir + file
        if file.endswith('/'):
            os.makedirs(outfile_path)
        else:
            outfile = open(outfile_path, 'wb')
            outfile.write(z.read(file))
            outfile.close()
    z.close()

لاحظ أن الملفات المضغوطة يمكن أن يكون إدخالات الدلائل وكذلك الملفات. عند إنشاء المحفوظات مع الأمر zip، وتمرير خيار -D لتعطيل إضافة إدخالات الدليل صراحة إلى الأرشيف. عند تشغيل بيثون 2.6 في طريقة ZipFile.extractall عبر إدخال دليل، على ما يبدو لإنشاء <م> ملف في مكانها. منذ مقالات أرشيف ليست بالضرورة في النظام، وهذا يسبب ZipFile.extractall إلى فشل في كثير من الأحيان، كما أنه يحاول إنشاء ملف في دليل فرعي من ملف. إذا كنت قد حصلت على الأرشيف الذي تريد استخدامه مع وحدة بيثون، ببساطة استخراجها وإعادة الرمز البريدي وذلك مع خيار -D. وهنا قليلا قصاصة أنا أستعمل لبعض الوقت لتفعل بالضبط ما يلي:

P=`pwd` && 
Z=`mktemp -d -t zip` && 
pushd $Z && 
unzip $P/<busted>.zip && 
zip -r -D $P/<new>.zip . && 
popd && 
rm -rf $Z

واستبدال <busted>.zip و<new>.zip مع أسماء حقيقية بالنسبة إلى الدليل الحالي. ثم مجرد نسخ كل شيء ولصقه في قذيفة الأوامر، وأنه سيتم إنشاء أرشيف جديد هذا هو على استعداد لموسيقى الروك مع بيثون 2.6. هناك <م> هو أمر zip التي من شأنها إزالة هذه إدخالات الدليل دون حيويي لكن IIRC أنه تصرف بشكل غريب في بيئات قذيفة أو تكوينات البريدي مختلفة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top