बिना कॉपी किए एक-दूसरे को बड़ी-बड़ी फाइलें दें


41

प्रत्येक 10G में डिस्क पर 5 विशाल फाइलें (file1, file2, .. file5) होती हैं और डिस्क पर बहुत कम खाली जगह बची होती हैं और मुझे इन सभी फाइलों को एक में मिलाना होता है। मूल फ़ाइलों को रखने की कोई आवश्यकता नहीं है, केवल अंतिम एक है।

सामान्य संगति catफ़ाइलों के लिए अनुक्रम के साथ चल रही है file2.. file5:

cat file2 >> file1 ; rm file2

दुर्भाग्य से इस तरह से मेरे पास कम से कम 10G मुक्त स्थान की आवश्यकता नहीं है। क्या वास्तविक नकल के बिना फ़ाइलों को सुरक्षित रखने का एक तरीका है लेकिन किसी भी तरह फाइलसिस्टम को बताएं कि file1 मूल file1 के अंत में समाप्त नहीं होता है और file2 पर जारी रहता है?

ps। फाइलसिस्टम ext4 है अगर यह मायने रखता है।


2
मुझे एक समाधान देखने में दिलचस्पी होगी, लेकिन मुझे संदेह है कि यह सीधे फाइलसिस्टम के साथ खिलवाड़ किए बिना संभव नहीं है।
केविन

1
आपको एक ही भौतिक फ़ाइल की आवश्यकता क्यों है जो इतनी बड़ी है? मैं पूछ रहा हूं क्योंकि शायद आप समवर्ती से बच सकते हैं - जो, वर्तमान उत्तर दिखाने के रूप में, बहुत परेशान है।
लियोरी

6
@rush: तब यह उत्तर मदद कर सकता है: serverfault.com/a/487692/16081
liori

1
डिवाइस-मैपर के लिए वैकल्पिक, कम कुशल, लेकिन लागू करने में आसान और एक विभाजन योग्य डिवाइस में परिणाम और एक दूरस्थ मशीन से इस्तेमाल किया जा सकता है "मल्टी" मोड का उपयोग करना है nbd-server
स्टीफन चेज़लस

1
वे हमेशा मुझे बेवकूफ कहते हैं जब मैं बताता हूं कि मुझे लगता है कि यह अच्छा होना चाहिए।
n611x007

जवाबों:


19

AFAIK यह (दुर्भाग्य से) शुरू से एक फ़ाइल को छोटा करना संभव नहीं है (यह मानक टूल के लिए सही हो सकता है लेकिन यहां syscall स्तर के लिए देखें )। लेकिन कुछ जटिलता जोड़ने के साथ आप सामान्य ट्रंकेशन (विरल फाइलों के साथ) का उपयोग कर सकते हैं: आप बीच में सभी डेटा लिखे बिना लक्ष्य फ़ाइल के अंत तक लिख सकते हैं।

चलिए पहले मान लेते हैं कि दोनों फाइलें बिल्कुल 5GiB (5120 MiB) हैं और आप एक बार में 100 MiB स्थानांतरित करना चाहते हैं। आप एक लूप निष्पादित करते हैं जिसमें शामिल हैं

  1. स्रोत फ़ाइल के अंत से लक्ष्य फ़ाइल के अंत में एक ब्लॉक की प्रतिलिपि बनाना (खपत डिस्क स्थान को बढ़ाना)
  2. स्रोत फ़ाइल को एक ब्लॉक से काटकर (डिस्क स्थान खाली करना)

    for((i=5119;i>=0;i--)); do
      dd if=sourcefile of=targetfile bs=1M skip="$i" seek="$i" count=1
      dd if=/dev/zero of=sourcefile bs=1M count=0 seek="$i"
    done
    

लेकिन इसे पहले छोटे परीक्षण फाइलों के साथ आज़माएं, कृपया ...

संभवतः फाइलें न तो समान आकार की हैं और न ही ब्लॉक आकार के कई गुना हैं। उस स्थिति में ऑफसेट की गणना अधिक जटिल हो जाती है। seek_bytesऔर skip_bytesतब उपयोग किया जाना चाहिए।

यदि यह वह तरीका है जो आप जाना चाहते हैं लेकिन विवरण के लिए मदद चाहिए तो फिर से पूछें।

चेतावनी

ddब्लॉक आकार के आधार पर परिणामी फ़ाइल एक विखंडन दुःस्वप्न होगी।


ऐसा लगता है कि यह फ़ाइलों को संक्षिप्त करने का सबसे स्वीकार्य तरीका है। सलाह के लिए धन्यवाद।
भीड़

3
अगर कोई विरल फ़ाइल समर्थन नहीं है, तो आप ब्लॉक-वार दूसरी फ़ाइल को उल्टा कर सकते हैं और फिर अंतिम ब्लॉक को हटा सकते हैं और इसे दूसरी फ़ाइल में जोड़ सकते हैं
शाफ़्ट फ्रीक

1
मैंने स्वयं इसकी कोशिश नहीं की है (हालाँकि मैं इसके बारे में हूँ), लेकिन seann.herdejurgen.com/resume/samag.com/html/v09/i08/a9_l1.htm एक पर्ल स्क्रिप्ट है जो इस एल्गोरिथम को लागू करने का दावा करती है।
zwol

16

फ़ाइलों को एक फ़ाइल में एक साथ रखने के बजाय, शायद किसी एकल फ़ाइल को नामांकित पाइप के साथ अनुकरण करें, यदि आपका प्रोग्राम कई फ़ाइलों को संभाल नहीं सकता है।

mkfifo /tmp/file
cat file* >/tmp/file &
blahblah /tmp/file
rm /tmp/file

जैसा कि ड्यूक का सुझाव है, लॉसेटअप / डीमेटेटअप भी काम कर सकता है। एक त्वरित प्रयोग; मैंने 'file1..file4' बनाया और थोड़े प्रयास से, किया:

for i in file*;do losetup -f ~/$i;done

numchunks=3
for i in `seq 0 $numchunks`; do
        sizeinsectors=$((`ls -l file$i | awk '{print $5}'`/512))
        startsector=$(($i*$sizeinsectors))
        echo "$startsector $sizeinsectors linear /dev/loop$i 0"
done | dmsetup create joined

फिर, / dev / dm-0 में सामग्री के रूप में आपकी फ़ाइल के साथ एक वर्चुअल ब्लॉक डिवाइस है।

मैंने इसे अच्छी तरह से परखा नहीं है।

एक अन्य संपादन: फ़ाइल का आकार 512 तक समान रूप से विभाज्य होना चाहिए या आप कुछ डेटा खो देंगे। अगर यह है, तो आप अच्छे हैं। मैं देख रहा हूँ कि वह भी नीचे उल्लेख किया है।


इस फाइल को एक बार पढ़ना बहुत अच्छा लगता है, दुर्भाग्य से इसमें पंद्रह पिछड़े / आगे कूदने की क्षमता नहीं है, है ना?
भीड़

7
@rush बेहतर विकल्प हो सकता है कि प्रत्येक फ़ाइल पर एक लूप डिवाइस रखें और उन्हें dmsetupएक वर्चुअल ब्लॉक डिवाइस के माध्यम से संयोजित करें (जो सामान्य काम करने की अनुमति देता है, लेकिन न तो अपग्रेड और न ही ट्रंकट)। यदि पहली फ़ाइल का आकार 512 से अधिक नहीं है, तो आपको अपूर्ण अंतिम क्षेत्र और दूसरी फ़ाइल से पहले बाइट्स (512 में राशि) को तीसरी फ़ाइल में कॉपी करना चाहिए। दूसरी फाइल के लिए लूप डिवाइस की जरूरत होगी --offset
हौके लैजिंग

सुरुचिपूर्ण समाधान। +1 भी ल्यूक लैगिंग का सुझाव है जो समस्या को हल करने का एक तरीका सुझाते हैं यदि पहली फ़ाइल (एस) का आकार 512 से अधिक नहीं है
ओलिवियर दुलक

9

आपको कुछ लिखना होगा जो उन बंच में डेटा कॉपी करता है जो आपके पास जितनी खाली जगह है उतने ही बड़े हैं। कुछ इस तरह से इसे काम करना चाहिए:

  • से डेटा का एक ब्लॉक पढ़ें file2( pread()सही स्थान पर पढ़ने से पहले मांग करके )।
  • को ब्लॉक में जोड़ें file1
  • fcntl(F_FREESP)अंतरिक्ष से निपटने के लिए उपयोग करें file2
  • दोहराना

1
मुझे पता है ... लेकिन मैं किसी भी तरह से सोच नहीं सकता था जिसमें कोड लिखना शामिल नहीं था, और मुझे लगा कि मैंने जो लिखा था वह बेहतर था कि कुछ भी नहीं लिखना। मैं अंत से शुरू करने के अपने चतुर चाल के बारे में नहीं सोचा था!
सेलडा

तुम्हारा भी, अंत से शुरू किए बिना काम नहीं करेगा, यह होगा?
हौके लैजिंग

नहीं, यह शुरुआत से काम करता है fcntl(F_FREESP)जिसके कारण फ़ाइल के दिए गए बाइट रेंज से जुड़े स्थान को मुक्त करता है (यह इसे विरल बनाता है)।
सेलडा

यह बहुत मजेदार है। लेकिन एक बहुत ही नई सुविधा लगती है। मेरे fcntlमैन पेज (2012-04-15) में इसका उल्लेख नहीं है ।
हौके लागिंग

4
@HaLLaging F_FREESP सोलारिस है। लिनक्स पर (2.6.38 से), यह Syscall का FALLOC_FL_PUNCH_HOLE ध्वज है fallocate। उस से util-linuxएक उपयोगिता उपयोगिता के नए संस्करणों के लिए एक इंटरफ़ेस है।
स्टीफन चेजलस

0

मुझे पता है कि यह आपके द्वारा पूछे जाने वाले काम से अधिक है, लेकिन यह आपकी समस्या का ध्यान रखेगा (और थोड़ा विखंडन या शीर्ष लेख के साथ):

#step 1
mount /path/to/... /the/new/fs #mount a new filesystem (from NFS? or an external usb disk?)

और फिर

#step 2:
cat file* > /the/new/fs/fullfile

या, यदि आपको लगता है कि संपीड़न में मदद मिलेगी:

#step 2 (alternate):
cat file* | gzip -c - > /the/new/fs/fullfile.gz

तब (और केवल तब), अंत में

#step 3:
rm file*
mv /the/new/fs/fullfile  .   #of fullfile.gz if you compressed it

दुर्भाग्य से बाहरी USB डिस्क को भौतिक पहुंच की आवश्यकता होती है और nfs को अतिरिक्त हार्डवेयर की आवश्यकता होती है और मेरे पास इसका कुछ भी नहीं है। कोई बात नहीं धन्यवाद। =)
भीड़

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