2012-06-11 13 views
46

जब एक फ़ाइल बनाई जाती है (FileSystemWatcher_Created) एक निर्देशिका में मैं इसे दूसरे पर कॉपी करता हूं। लेकिन जब मैं एक बड़ी (> 10 एमबी) फ़ाइल बनाता हूं तो यह फ़ाइल की प्रतिलिपि बनाने में विफल रहता है, क्योंकि यह पहले से ही कॉपी करना शुरू कर देता है, जब फ़ाइल अभी तक तैयार नहीं होती है ...
यह कारण फ़ाइल की प्रतिलिपि नहीं बना सकता है, क्योंकि इसका उपयोग दूसरे द्वारा किया जाता है उठाए जाने के लिए प्रक्रिया। ;?। (
किसी भी मददफ़ाइल पूरी तरह से लिखे जाने तक प्रतीक्षा करें

class Program 
{ 
    static void Main(string[] args) 
    { 
     string path = @"D:\levan\FolderListenerTest\ListenedFolder"; 
     FileSystemWatcher listener; 
     listener = new FileSystemWatcher(path); 
     listener.Created += new FileSystemEventHandler(listener_Created); 
     listener.EnableRaisingEvents = true; 

     while (Console.ReadLine() != "exit") ; 
    } 

    public static void listener_Created(object sender, FileSystemEventArgs e) 
    { 
     Console.WriteLine 
       (
        "File Created:\n" 
        + "ChangeType: " + e.ChangeType 
        + "\nName: " + e.Name 
        + "\nFullPath: " + e.FullPath 
       ); 
     File.Copy(e.FullPath, @"D:\levan\FolderListenerTest\CopiedFilesFolder\" + e.Name); 
     Console.Read(); 
    } 
} 
+1

मैं इस सवाल का जवाब यहाँ खेद पाया [Stackoverflow पर हल यह समस्या] [1] [1] : http://stackoverflow.com/questions/1406808/wait-for-file-to-be-freed-by-process – levi

+1

संभावित डुप्लिकेट [क्या यह जांचने का कोई तरीका है कि कोई फ़ाइल है या नहीं n उपयोग?] (http://stackoverflow.com/questions/876473/is-there-a-way-to-check-if-a-file-is-in-use) –

उत्तर

32

वहाँ जिस समस्या का सामना कर रहे हैं के लिए केवल समाधान नहीं है।

कॉपी करें कि कॉपी की प्रक्रिया शुरू करने से पहले प्रक्रिया में फ़ाइल आईडी जांचें या नहीं। जब तक आप गलत मान प्राप्त नहीं करते हैं तब तक आप निम्न फ़ंक्शन को कॉल कर सकते हैं।

1 विधि, this answer से सीधे कॉपी किया:

private bool IsFileLocked(FileInfo file) 
{ 
    FileStream stream = null; 

    try 
    { 
     stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None); 
    } 
    catch (IOException) 
    { 
     //the file is unavailable because it is: 
     //still being written to 
     //or being processed by another thread 
     //or does not exist (has already been processed) 
     return true; 
    } 
    finally 
    { 
     if (stream != null) 
      stream.Close(); 
    } 

    //file is not locked 
    return false; 
} 

2 विधि:

const int ERROR_SHARING_VIOLATION = 32; 
const int ERROR_LOCK_VIOLATION = 33; 
private bool IsFileLocked(string file) 
{ 
    //check that problem is not in destination file 
    if (File.Exists(file) == true) 
    { 
     FileStream stream = null; 
     try 
     { 
      stream = File.Open(file, FileMode.Open, FileAccess.ReadWrite, FileShare.None); 
     } 
     catch (Exception ex2) 
     { 
      //_log.WriteLog(ex2, "Error in checking whether file is locked " + file); 
      int errorCode = Marshal.GetHRForException(ex2) & ((1 << 16) - 1); 
      if ((ex2 is IOException) && (errorCode == ERROR_SHARING_VIOLATION || errorCode == ERROR_LOCK_VIOLATION)) 
      { 
       return true; 
      } 
     } 
     finally 
     { 
      if (stream != null) 
       stream.Close(); 
     } 
    } 
    return false; 
} 
+40

हम्म काम करता है, यह सीधे है: http://stackoverflow.com/a/937558/97000। – pyrocumulus

+1

और आप निरंतर मानों की प्रतिलिपि बनाना भूल गए ('ERROR_SHARING_VIOLATION' = 32,' ERROR_LOCK_VIOLATION' = 33) –

4

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

जब आप किसी फ़ाइल तक नहीं पहुंच पा रहे हैं, तो आप मान सकते हैं कि यह अभी भी उपयोग में है (बेहतर अभी तक - इसे विशेष मोड में खोलने का प्रयास करें, और देखें कि कोई और वर्तमान में है या नहीं फ़ाइल.कॉपी की विफलता से अनुमान लगाने के बजाए इसे खोलना)। अगर फ़ाइल लॉक है, तो आपको इसे किसी अन्य समय कॉपी करना होगा। अगर यह लॉक नहीं है, तो आप इसे कॉपी कर सकते हैं (दौड़ की स्थिति के लिए थोड़ी सी संभावना है यहां)

वह 'अन्य समय' कब होता है? मुझे याद नहीं है जब FileSystemWatcher प्रति फ़ाइल एकाधिक घटनाएं भेजता है - इसे जांचें, यह आपके लिए ईवेंट को अनदेखा करने और किसी अन्य की प्रतीक्षा करने के लिए पर्याप्त हो सकता है। यदि नहीं, तो आप हमेशा एक समय सेट कर सकते हैं और फ़ाइल को 5 सेकंड में पुनः जांच सकते हैं।

7

प्रलेखन से FileSystemWatcher के लिए:

OnCreated घटना जैसे ही एक फ़ाइल बनाई गई है उठाया है। यदि फ़ाइल को कॉपी या स्थानांतरित निर्देशिका में स्थानांतरित किया जा रहा है, तो OnCreated ईवेंट तुरंत उठाया जाएगा, इसके बाद एक या अधिक OnChanged ईवेंट होंगे।

तो, अगर प्रति विफल रहता है,, (अपवाद को पकड़ने) फ़ाइलें है कि अभी भी ले जाया जा करने की जरूरत है की एक सूची में जोड़ने, और OnChanged घटना के दौरान नकल का प्रयास। आखिरकार, यह काम करना चाहिए।

तरह (अपूर्ण; विशिष्ट अपवाद को पकड़ने, प्रारंभ चर, आदि):

public static void listener_Created(object sender, FileSystemEventArgs e) 
    { 
     Console.WriteLine 
       (
        "File Created:\n" 
        + "ChangeType: " + e.ChangeType 
        + "\nName: " + e.Name 
        + "\nFullPath: " + e.FullPath 
       ); 
     try { 
      File.Copy(e.FullPath, @"D:\levani\FolderListenerTest\CopiedFilesFolder\" + e.Name); 
     } 
     catch { 
      _waitingForClose.Add(e.FullPath); 
     } 
     Console.Read(); 
    } 

    public static void listener_Changed(object sender, FileSystemEventArgs e) 
    { 
     if (_waitingForClose.Contains(e.FullPath)) 
     { 
       try { 
        File.Copy(...); 
        _waitingForClose.Remove(e.FullPath); 
       } 
       catch {} 
     } 
    } 
+0

यह बहुत अच्छा तरीका है लेकिन मुझे इसकी आवश्यकता है एक बार में, इसलिए मैंने IsFileReady को थोड़ी देर में रखा है और यह अब – levi

2

वैसे आप पहले से ही अपने आप को जवाब दे; आपको फाइल को खत्म करने के लिए इंतजार करना होगा। ऐसा करने का एक तरीका यह जांचना है कि फ़ाइल अभी भी उपयोग में है या नहीं। इसका एक उदाहरण यहां पाया जा सकता है: Is there a way to check if a file is in use?

ध्यान दें कि आपको अपनी स्थिति में काम करने के लिए इस कोड को संशोधित करना होगा।आप की तरह (स्यूडोकोड) कुछ है करने के लिए चाहते हो सकता है:

public static void listener_Created() 
{ 
    while CheckFileInUse() 
     wait 1000 milliseconds 

    CopyFile() 
} 

जाहिर है आप अपने आप को एक अनंत while सिर्फ मामले में मालिक आवेदन कभी नहीं अवरोध समाप्त से रक्षा करनी चाहिए। साथ ही, FileSystemWatcher से अन्य ईवेंट की जांच करने के लायक हो सकते हैं, जिनकी आप सदस्यता ले सकते हैं। ऐसी कोई घटना हो सकती है जिसका उपयोग आप इस पूरी समस्या को रोकने के लिए कर सकते हैं।

0

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

आपको अभी भी जांचना चाहिए कि फ़ाइल.कॉपी विफल हो जाती है, क्योंकि कोई अन्य एप्लिकेशन उस फ़ाइल के बीच फ़ाइल खोल सकता है जब आप फ़ाइल को चेक करते हैं और जिस क्षण आप इसे कॉपी करते हैं।

public static bool IsFileClosed(string filename) 
{ 
    try 
    { 
     using (var inputStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.None)) 
     { 
      return true; 
     } 
    } 
    catch (IOException) 
    { 
     return false; 
    } 
} 
+0

डाउनवोट क्यों? – Michael

+0

यदि आप एक अपवाद का सामना करते हैं जो IOException नहीं है तो यह कोड वापस क्या करता है? –

+0

यदि फ़ाइल। ओपन IOException के अलावा एक अपवाद फेंकता है, तो यह विधि कोई मान नहीं लौटाती है। यह किसी भी गैर-IOExceptions को जांचने के लिए कॉलर की ज़िम्मेदारी है: https://msdn.microsoft.com/en-us/library/y973b725(v=vs.110).aspx – Michael

6

यह पुराना धागा है, लेकिन मैं अन्य लोगों के लिए कुछ जानकारी जोड़ूंगा।

मुझे पीडीएफ फाइलों को लिखने वाले प्रोग्राम के साथ एक समान समस्या का अनुभव हुआ, कभी-कभी उन्हें प्रस्तुत करने में 30 सेकंड लगते हैं .. यह वही अवधि है जब मेरी watcher_FileCreated कक्षा फ़ाइल की प्रतिलिपि बनाने से पहले प्रतीक्षा करती है।

फ़ाइलों को लॉक नहीं किया गया था।

इस मामले में मैंने पीडीएफ के आकार की जांच की और फिर नए आकार की तुलना करने से पहले 2 सेकंड इंतजार किया, अगर वे असमान थे तो थ्रेड 30 सेकंड तक सो जाएगा और फिर से प्रयास करें।

-3

मैं यहां एक उत्तर जोड़ना चाहता हूं, क्योंकि यह मेरे लिए काम करता है। मैंने समय देरी का इस्तेमाल किया, जबकि लूप, सबकुछ मैं सोच सकता था।

मेरे पास आउटपुट फ़ोल्डर की विंडोज एक्सप्लोरर विंडो खुली थी। मैंने इसे बंद कर दिया, और सब कुछ एक आकर्षण की तरह काम किया।

मुझे आशा है कि इससे किसी की मदद मिलेगी।

+1

तो अब आपका यदि teh उपयोगकर्ता की निर्देशिका खुली है तो ऐप क्रैश हो जाता है? – Epirocks

0

जब फ़ाइल बाइनरी (बाइट द्वारा बाइट) में लिख रहा है,,, FileStream और इसके बाद के संस्करण समाधान काम नहीं बनाते हैं, क्योंकि फ़ाइल तैयार है और हर बाइट में wrotted है तो इस स्थिति में आप इस तरह अन्य वैकल्पिक हल की जरूरत है: इस जब करो फ़ाइल बनाया है या आप फ़ाइल पर प्रोसेसिंग शुरू करने के लिए

long fileSize = 0; 
currentFile = new FileInfo(path); 

while (fileSize < currentFile.Length)//check size is stable or increased 
{ 
    fileSize = currentFile.Length;//get current size 
    System.Threading.Thread.Sleep(500);//wait a moment for processing copy 
    currentFile.Refresh();//refresh length value 
} 

//Now file is ready for any process! 
1

तो चाहते हैं, इन और अन्य इसी तरह के सवाल मैं दो अलग-अलग कार्यक्रमों एक का उपयोग कर के साथ एक समस्या को सुलझाने की कोशिश आज दोपहर एक प्रमुदित हंस का पीछा करने पर चला गया के कुछ के माध्यम से जल्दी से नजर होने सिंक्रनाइज़ेशन (और फाइल सेव) विधि के रूप में फ़ाइल करें। एक असामान्य स्थिति का थोड़ा सा, लेकिन यह निश्चित रूप से मेरे लिए 'हाइलाइट किया गया है कि फाइल को लॉक किया गया है, तो जांचें', तो इसे खोलें, अगर यह 'दृष्टिकोण नहीं है तो इसे खोलें।

समस्या यह है: फ़ाइल हो सकती है जब आप इसे चेक करते समय और वास्तव में फ़ाइल खोलने के बीच लॉक हो जाते हैं। स्पोरैडिक को ट्रैक करना वाकई मुश्किल है फ़ाइल की प्रतिलिपि नहीं बना सकता है, क्योंकि यह किसी अन्य प्रक्रिया द्वारा उपयोग किया जाता है त्रुटि अगर आप इसे भी नहीं ढूंढ रहे हैं।

मूल संकल्प सिर्फ पकड़ ब्लॉक के अंदर फ़ाइल को खोलने का प्रयास करना है ताकि अगर यह बंद हो जाए, तो आप फिर कोशिश कर सकते हैं। इस तरह चेक और ओपनिंग के बीच कोई समय नहीं है, ओएस उन्हें एक ही समय में करता है।

यहां कोड फ़ाइल का उपयोग करता है।आदि

/// <param name="timeout">how long to keep trying in milliseconds</param> 
static void safeCopy(string src, string dst, int timeout) 
{ 
    while (timeout > 0) 
    { 
     try 
     { 
      File.Copy(src, dst); 

      //don't forget to either return from the function or break out fo the while loop 
      break; 
     } 
     catch (IOException) 
     { 
      //you could do the sleep in here, but its probably a good idea to exit the error handler as soon as possible 
     } 
     Thread.Sleep(100); 

     //if its a very long wait this will acumulate very small errors. 
     //For most things it's probably fine, but if you need precision over a long time span, consider 
     // using some sort of timer or DateTime.Now as a better alternative 
     timeout -= 100; 
    } 
} 

parellelism पर एक और छोटी टिप्पणी File.Open, File.ReadAllText, File.WriteAllText,: यह कॉपी, लेकिन यह स्थिर फ़ाइल वर्ग के तरीकों में से किसी के साथ तरह ही काम करता एक सिंक्रोनस विधि है, जो प्रतीक्षा करते समय और थ्रेड पर काम करते समय दोनों को अपने धागे को अवरुद्ध कर देगी। यह सबसे आसान तरीका है, लेकिन यदि फ़ाइल लंबे समय तक बंद रहती है तो आपका प्रोग्राम उत्तरदायी नहीं हो सकता है। पेरेलेलिज्म यहां गहराई से जाने के लिए एक विषय बहुत बड़ा है, (और जिस तरह से आप एसिंक्रोनस रीड/राइट सेट अप कर सकते हैं, वह कई प्रकार का अपरिपक्व है) लेकिन यहां एक तरीका है जिसे इसे पेरेलेलाइज्ड किया जा सकता है।

public class FileEx 
{ 
    public static async void CopyWaitAsync(string src, string dst, int timeout, Action doWhenDone) 
    { 
     while (timeout > 0) 
     { 
      try 
      { 
       File.Copy(src, dst); 
       doWhenDone(); 
       break; 
      } 
      catch (IOException) { } 

      await Task.Delay(100); 
      timeout -= 100; 
     } 
    } 

    public static async Task<string> ReadAllTextWaitAsync(string filePath, int timeout) 
    { 
     while (timeout > 0) 
     { 
      try { 
       return File.ReadAllText(filePath); 
      } 
      catch (IOException) { } 

      await Task.Delay(100); 
      timeout -= 100; 
     } 
     return ""; 
    } 

    public static async void WriteAllTextWaitAsync(string filePath, string contents, int timeout) 
    { 
     while (timeout > 0) 
     { 
      try 
      { 
       File.WriteAllText(filePath, contents); 
       return; 
      } 
      catch (IOException) { } 

      await Task.Delay(100); 
      timeout -= 100; 
     } 
    } 
} 

और यहाँ है कि यह कैसे इस्तेमाल किया जा सकता है:

public static void Main() 
{ 
    test_FileEx(); 
    Console.WriteLine("Me First!"); 
}  

public static async void test_FileEx() 
{ 
    await Task.Delay(1); 

    //you can do this, but it gives a compiler warning because it can potentially return immediately without finishing the copy 
    //As a side note, if the file is not locked this will not return until the copy operation completes. Async functions run synchronously 
    //until the first 'await'. See the documentation for async: https://msdn.microsoft.com/en-us/library/hh156513.aspx 
    CopyWaitAsync("file1.txt", "file1.bat", 1000); 

    //this is the normal way of using this kind of async function. Execution of the following lines will always occur AFTER the copy finishes 
    await CopyWaitAsync("file1.txt", "file1.readme", 1000); 
    Console.WriteLine("file1.txt copied to file1.readme"); 

    //The following line doesn't cause a compiler error, but it doesn't make any sense either. 
    ReadAllTextWaitAsync("file1.readme", 1000); 

    //To get the return value of the function, you have to use this function with the await keyword 
    string text = await ReadAllTextWaitAsync("file1.readme", 1000); 
    Console.WriteLine("file1.readme says: " + text); 
} 

//Output: 
//Me First! 
//file1.txt copied to file1.readme 
//file1.readme says: Text to be duplicated! 
संबंधित मुद्दे