कैसे एक समान सीमा के साथ कई अभिलेखागार में समान आकार की फ़ाइलों को टारगेट करें


11

मैं उबंटू 16.04 पर हूं।

मेरे पास बहुत सारी पाठ फ़ाइलों के साथ एक फ़ोल्डर है (लगभग 12k)। मुझे उन सभी को एक वेबसाइट पर अपलोड करने की आवश्यकता है जो अपलोड को स्वीकार .tar.gzकरता है और फिर उन्हें स्वचालित रूप से डिकम्प्रेस करता है , लेकिन प्रति फ़ाइल 10MB (10000KB) की सीमा होती है (इसलिए विशेष रूप से प्रत्येक फ़ाइल को अपने आप विघटित होना पड़ता है)। अगर मैं tar.gzइन सभी फ़ाइलों के परिणामस्वरूप फ़ाइल 72MB के बारे में है।

जो मैं करना चाहता हूं, वह आठ .tar.gzफाइलें बनाना है , प्रत्येक आकार / आयाम (सख्ती से) 10000KB से छोटा है।

वैकल्पिक रूप से, कोई यह मान सकता है कि ऊपर की सभी फाइलों में लगभग समान आयाम हैं, इसलिए मैं .tar.gzप्रत्येक के समान या उससे कम मात्रा वाली आठ फाइलें बनाना चाहूंगा ।

मैं इन दोनों कार्यों में से कोई कैसे कर सकता हूं?

मैं एक समाधान के साथ पूरी तरह से ठीक हूं जिसमें GUI, CLI या स्क्रिप्टिंग शामिल है। मैं यहां गति की तलाश में नहीं हूं, मुझे बस इसकी जरूरत है।


संभवतः आपके पास 12k फाइलें उनके नाम में पैटर्न या बार-बार वर्ण होंगे। आप संभवतः tarउन सभी फ़ाइलों को जोड़कर एक निश्चित पैटर्न के साथ शुरू कर सकते हैं जब तक कि आप उन सभी को नहीं करते। यह आसानी से लिपिबद्ध किया जा सकता है, लेकिन इसकी गारंटी नहीं है कि आकार 9 एमबी से कम होगा, जैसा कि आपकी आवश्यकता है। हालाँकि, आप मैन्युअल रूप से उन फ़ाइलों के आकार को समायोजित कर सकते हैं जो उन्हें आगे विभाजित करके बहुत बड़ी हैं।
जुआन एंटोनियो

जवाबों:


9

पूरी तरह से चिथड़े और एक त्वरित, किसी न किसी स्केच के रूप में यह है, लेकिन 3000 फाइलों के साथ एक निर्देशिका पर परीक्षण किया गया है, नीचे दी गई स्क्रिप्ट ने बहुत तेज़ गति से किया:

#!/usr/bin/env python3
import subprocess
import os
import sys

splitinto = 2

dr = sys.argv[1]
os.chdir(dr)

files = os.listdir(dr)
n_files = len(files)
size = n_files // splitinto

def compress(tar, files):
    command = ["tar", "-zcvf", "tarfile" + str(tar) + ".tar.gz", "-T", "-", "--null"]
    proc = subprocess.Popen(command, stdin=subprocess.PIPE)
    with proc:
        proc.stdin.write(b'\0'.join(map(str.encode, files)))
        proc.stdin.write(b'\0')
    if proc.returncode:
        sys.exit(proc.returncode)

sub = []; tar = 1
for f in files:
    sub.append(f)
    if len(sub) == size:
        compress(tar, sub)
        sub = []; tar += 1

if sub:
    # taking care of left
    compress(tar, sub)

कैसे इस्तेमाल करे

  • इसे एक खाली फ़ाइल में सहेजें compress_split.py
  • सिर अनुभाग में, संपीड़ित करने के लिए फ़ाइलों की संख्या निर्धारित करें। व्यवहार में, शेष कुछ "बाएं ओवर" की देखभाल करने के लिए हमेशा एक और होगा।
  • इसे अपनी फ़ाइलों के साथ निर्देशिका में तर्क के रूप में चलाएं:

    python3 /path/tocompress_split.py /directory/with/files/tocompress

क्रमांकित .tar.gzफ़ाइलें उसी निर्देशिका में बनाई जाएंगी जहाँ फ़ाइलें हैं।

व्याख्या

लिपी:

  • निर्देशिका में सभी फ़ाइलों को सूचीबद्ध करता है
  • टीडी फ़ाइल में पथ की जानकारी जोड़ने से रोकने के लिए निर्देशिका में सीडी
  • फ़ाइल सूची के माध्यम से पढ़ता है, उन्हें सेट डिवीजन द्वारा समूहीकृत करता है
  • उप समूह (ओं) को गिने फ़ाइलों में संपीड़ित करता है

संपादित करें

स्वचालित रूप से mb में आकार के अनुसार विखंडू बनाएं

अधिक परिष्कृत एक (दूसरे) तर्क के रूप में विखंडू के अधिकतम आकार (एमबी में) का उपयोग करना है। नीचे दी गई लिपि में, चंक जैसे ही दहलीज तक पहुँचता है (गुजरता है) एक संपीड़ित फ़ाइल में लिखा जाता है।

चूंकि स्क्रिप्ट चौकों से अधिक होती है, इसलिए यह सीमा से अधिक है, यह तभी काम करेगा जब (सभी) फ़ाइलों का आकार चंक आकार से काफी छोटा हो।

लिपी:

#!/usr/bin/env python3
import subprocess
import os
import sys

dr = sys.argv[1]
chunksize = float(sys.argv[2])
os.chdir(dr)

files = os.listdir(dr)
n_files = len(files)

def compress(tar, files):
    command = ["tar", "-zcvf", "tarfile" + str(tar) + ".tar.gz", "-T", "-", "--null"]
    proc = subprocess.Popen(command, stdin=subprocess.PIPE)
    with proc:
        proc.stdin.write(b'\0'.join(map(str.encode, files)))
        proc.stdin.write(b'\0')
    if proc.returncode:
        sys.exit(proc.returncode)

sub = []; tar = 1; subsize = 0
for f in files:
    sub.append(f)
    subsize = subsize + (os.path.getsize(f)/1000000)
    if subsize >= chunksize:
        compress(tar, sub)
        sub = []; tar += 1; subsize = 0

if sub:
    # taking care of left
    compress(tar, sub)

चलाने के लिए:

python3 /path/tocompress_split.py /directory/with/files/tocompress chunksize

... जहां तारकोल टार कमांड के लिए इनपुट का आकार है ।

इस में, @DavidFoerster द्वारा सुझाए गए सुधार शामिल हैं। बहुत बहुत धन्यवाद !


@ dadexix86 आपका स्वागत है!
जैकब व्लिजम

मैंने शेल इनविटेशन से छुटकारा पाया और सीधे एक तर्क सूची का उपयोग किया। फिर भी, बड़े तर्क सूची समस्याग्रस्त हो सकते हैं और मैं tarमानक इनपुट स्ट्रीम पर फ़ाइल सूची प्रदान करके आगे मंगलाचरण को बेहतर बनाने का प्रयास करूंगा ।
डेविड फ़ॉर्स्टर

हाय @DavidFoerster, मुझे आपकी अंतर्दृष्टि पर भरोसा है, लेकिन फायदा क्या है?
जैकब व्लिजम

अधिकांश रनटाइम वातावरण में एक कमांड के तर्क स्ट्रिंग्स की कुल लंबाई पर एक नरम (नरम और कठोर) सीमा होती है, जो हजारों फाइलों पर काम करते समय आप जल्दी पहुंचेंगे। यही कारण है कि tarआप एक उपयुक्त विकल्प के साथ मानक इनपुट पर फ़ाइलों को जोड़ने (या निकालने) को निर्दिष्ट करने की अनुमति देते हैं।
डेविड फ़ॉस्टर 14

@DavidFoerster एक मुद्दा है, हालांकि दूसरा कोई भी नहीं चलता है। वास्तव में दोनों में से कोई भी नहीं करता ...
याकूब Vlijm

6

एक शुद्ध खोल दृष्टिकोण:

files=(*); 
num=$((${#files[@]}/8));
k=1
for ((i=0; i<${#files[@]}; i+=$num)); do 
    tar cvzf files$k.tgz -- "${files[@]:$i:$num}"
    ((k++))
done

व्याख्या

  • files=(*): सरणी में फ़ाइलों की सूची (यदि कोई मौजूद है, तो निर्देशिकाओं को भी बदल दें, files=(*.txt)केवल txtविस्तार के साथ केवल एक चीज पाने के लिए बदलें )$files
  • num=$((${#files[@]}/8));: ${#files[@]}सरणी में तत्वों की संख्या है $files$(( ))बैश के (सीमित) गणित करने का तरीका है। तो, यह कमांड $num8 से विभाजित फाइलों की संख्या पर सेट होता है।
  • k=1 : टारबॉल को नाम देने के लिए सिर्फ एक काउंटर।
  • for ((i=0; i<${#files[@]}; i+=$num)); do: सरणी के मूल्यों पर पुनरावृति। (सरणी का पहला तत्व) और द्वारा संवर्धित $iपर आरंभीकृत किया 0गया है $num। यह तब तक जारी रहता है जब तक हम सभी तत्वों (फाइलों) से नहीं गुजर जाते।
  • tar cvzf files$i.tgz -- ${files[@]:$i:$num}: बैश में, आप एक सरणी टुकड़ा (एक सरणी का हिस्सा) का उपयोग कर प्राप्त कर सकते हैं ${array[@]:start:length}, इसलिए ${array[@]:2:3}दूसरे से शुरू होने वाले तीन तत्वों को वापस कर देंगे। यहां, हम एक ऐसा स्लाइस ले रहे हैं जो वर्तमान मूल्य पर शुरू होता है $iऔर $numलंबे समय तक तत्व है। यदि --आपके किसी भी फ़ाइल नाम के साथ शुरू हो सकता है, तो इसकी आवश्यकता है -
  • ((k++)) : वेतन वृद्धि $k

अच्छा! पहली बार मैंने बैश एरे इंडेक्स रेंज का व्यावहारिक उपयोग देखा है।
जो

बहुत साफ और रसीला। मेरे लिए, पायथन समाधानों की तुलना में अधिक समझने योग्य है, हालांकि दोनों बहुत अच्छे हैं। आश्चर्य है कि वे सभी प्रदर्शन में तुलना कैसे करते हैं?
डोकलास्वर नागर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.