2012-07-06 10 views
9

मैं खुद के लिए एक सरल फ़ोल्डर समन्वयन बैकअप उपकरण बना रही हूँ और File.Copy का उपयोग कर काफी अवरोध का सामना किया। मेरे सिस्टम में ~ 44,000 छोटी फाइलों (विंडोज़ मेल फ़ोल्डर्स) के किसी फ़ोल्डर को कॉपी करने के परीक्षणों का परीक्षण करते हुए, मैंने पाया कि फ़ाइल.कॉपी का उपयोग कमांड लाइन का उपयोग करने से 3x धीमी थी और उसी फाइल/फ़ोल्डरों की प्रतिलिपि बनाने के लिए xcopy चल रहा था। फाइलों की प्रतिलिपि बनाने के लिए मेरे सी # संस्करण में 16+ मिनट लगते हैं, जबकि एक्सकॉपी केवल 5 मिनट लेता है। मैंने इस विषय पर मदद की तलाश करने की कोशिश की है, लेकिन मुझे लगता है कि लोग नेटवर्क पर बड़ी फ़ाइलों की धीमी फ़ाइल प्रतिलिपि के बारे में शिकायत करते हैं। यह न तो एक बड़ी फाइल समस्या है और न ही नेटवर्क कॉपी करने की समस्या है।.net File.Copy बहुत धीमी गति से जब कई छोटे फ़ाइलों की प्रतिलिपि (नेटवर्क पर नहीं)

मुझे interesting article about a better File.Copy replacement मिला, लेकिन पोस्ट किए गए कोड में कुछ त्रुटियां हैं जो ढेर के साथ समस्याएं पैदा करती हैं और मैं उनके कोड में समस्याओं को ठीक करने के लिए पर्याप्त जानकारी के पास कहीं भी नहीं हूं।

क्या फ़ाइल को कॉपी करने के लिए कोई सामान्य या आसान तरीका है। कुछ और तेज़ी से?

उत्तर

4

आईओ ऑपरेशंस को धीमा करने वाली चीजों में से एक रोटेशनल डिस्क पर सबसे अधिक डिस्क हेड को ले जा रहा है।

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

एक बात यह है कि एक्सकॉपी कॉपी (अर्थात् दोनों मामलों में कमांड) से काफी बेहतर है, यह है कि XCopy उन फ़ाइलों को गंतव्य पर लिखने से पहले फ़ाइलों के समूह में पढ़ता है।

आप एक ही डिस्क पर फ़ाइलों को कॉपी कर रहे हैं, एक बड़े बफर आवंटन ही बार में कई फाइलों में पढ़ने की कोशिश तो उन फ़ाइलों को लिखने के एक बार बफर भरा हुआ है)।

आप एक डिस्क से पढ़ रहे हैं और एक और डिस्क के लिए लिख रहे हैं, तो अन्य डिस्क पर लिखने के लिए स्रोत डिस्क और एक अलग थ्रेड से पढ़ने के लिए एक धागा शुरू की कोशिश करो।

+0

अच्छी जानकारी के लिए धन्यवाद! मैं विशेष रूप से एक्सकॉपी करने के बारे में बताए गए पढ़ने/लिखने को बफर करने की कोशिश करने में रूचि रखता था। मैंने 50 एमबी बफर के साथ कुछ परीक्षण किए और पाया कि मुझे मेरी प्रतिलिपि 14 मिनट 40 सेकंड तक मिल गई है। तो एक अद्भुत सुधार नहीं, लेकिन बेहतर है। XCopy के समय के पीछे अभी भी lightyears। मैं देखता हूं कि पढ़ना/लिखना थ्रेडिंग अगली मदद करता है ... – Guavaman

+0

दरअसल, मुझे लगता है कि मेरी फ़ाइलस्ट्रीम आधारित बफर्ड कॉपी सिस्टम फ़ाइल गुणों (विशेषताओं, निर्माण समय इत्यादि) की प्रतिलिपि नहीं बना रहा था, मुझे 16 मिनट बाद वापस आ गया है। उन्हें वापस जोड़ने के बाद, प्रतिलिपि समय वापस फाइल.कॉपी के साथ था, केवल मैंने 50 एमबी मेमोरी को बफर करने के लिए खो दिया है। :( – Guavaman

0

मुझे इस स्तर पर कोई अच्छा अनुभव नहीं है। आप अपने xcopy comand युक्त बैच फ़ाइल चलाने की कोशिश क्यों नहीं करते? इस पोस्ट की जाँच करें: विचार करने के लिए Executing Batch File in C#

8

एक बात आपके प्रति एक यूजर इंटरफेस है कि नकल के दौरान अद्यतन करता है या नहीं है। यदि ऐसा है, तो सुनिश्चित करें कि आपकी प्रति एक अलग थ्रेड पर चल रही है, या दोनों यूआई प्रतिलिपि के दौरान जमा हो जाएंगे, और यूआई को अपडेट करने के लिए अवरुद्ध कॉल करके कॉपी को धीमा कर दिया जाएगा।

मैंने एक समान कार्यक्रम लिखा है और मेरे अनुभव में, मेरा कोड विंडोज एक्सप्लोरर कॉपी से तेज़ी से भाग गया है (कमांड प्रॉम्प्ट से xcopy के बारे में सुनिश्चित नहीं है)।

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

चीजों को गति देने का एक और तरीका है कार्य प्राप्त करने के बजाय संख्यात्मक कार्यों का उपयोग करना (उदाहरण के लिए GetFiles के बजाय)। जब ये सूची समाप्त हो जाती है तो ये कार्य सब कुछ वापस करने की प्रतीक्षा करने के बजाय जल्द से जल्द परिणाम लौटने लगते हैं। वे एक संख्यात्मक वापस लौटते हैं, इसलिए आप परिणाम पर केवल foreach कॉल कर सकते हैं: foreach (System.IO.Directory.EnumerateDirectories(path)) में स्ट्रिंग फ़ाइल।मेरे कार्यक्रम के लिए यह गति में एक उल्लेखनीय अंतर भी बना, और आपके जैसे मामलों में और भी सहायक होगा जहां आप कई फाइलों वाली निर्देशिकाओं से निपट रहे हैं।

+3

+1। विशेष रूप से आलसी गणना का उपयोग करने के लिए। –

+0

मेरे पास पृष्ठभूमि थ्रेड पर मेरा इंटरफ़ेस है। प्रदर्शन को कम करने के सुझावों के लिए धन्यवाद। दुर्भाग्यवश, यह वास्तव में मेरी प्रतिलिपि के समय में कोई समस्या नहीं है। यूआई अपडेट पूरी तरह से अक्षम है, प्रतिलिपि समय पहले जैसा ही है। मैं देखता हूं कि एन्युमरेटफाइल का उपयोग करने में मदद करता है। – Guavaman

+0

बस आईनेमरेबल्स का उपयोग करने के नतीजे मिले। यह फ़ाइल प्रतिलिपि बनाने में मदद नहीं करता है, शायद इसलिए कि मैं जा रहा हूं फ़ाइलों की प्रतिलिपि बनाने वाले फ़ोल्डर द्वारा फ़ोल्डर, इसलिए अधिकांश समय में GetFiles को करने में बहुत लंबा समय नहीं लगता है। हालांकि, प्रारंभिक फ़ाइल गिनती प्रक्रिया को आसान बनाने के साथ थोड़ा सा मदद मिली। – Guavaman

0

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

var files = new List<string>(); 
// todo: fill the files list using directoryenumeration or so... 
var po = new ParallelOptions() {MaxDegreeOfParallelism = 2}; 
Parallel.ForEach(files, po, CopyAFile); 

// Routine to copy a single file 
private void CopyAFile(string file) { } 
1

तेजी से फ़ाइल प्रतिलिपि के लिए दो एल्गोरिदम हैं:

तो स्रोत और गंतव्य अलग-अलग डिस्क हैं तो:

  • एक थ्रेड लगातार फ़ाइलों को पढ़ने और एक बफर में संग्रहित करता है।
  • उस बफर से लगातार एक और थ्रेड लेखन फाइलें।

स्रोत और गंतव्य तो एक ही डिस्क है:

  • बाइट्स की एक निश्चित हिस्सा पढ़ें, एक समय में 8K कहते हैं, कोई फर्क नहीं पड़ता है कि कितने फ़ाइलें।
  • गंतव्य पर उस निश्चित खंड को लिखें, या तो एक फ़ाइल में या एकाधिक फ़ाइलों में।

इस तरह आपको महत्वपूर्ण प्रदर्शन मिलेगा।

वैकल्पिक है कि आप अपने .net कोड से सिर्फ xcopy का आह्वान करें। File.Copy का उपयोग करके इसे क्यों परेशान करते हैं। आप Process.StandardOutput का उपयोग कर xcopy आउटपुट कैप्चर कर सकते हैं और उपयोगकर्ता को यह दिखाने के लिए स्क्रीन पर दिखा सकते हैं कि क्या हो रहा है।

संबंधित मुद्दे