यदि कोई फ़ाइल उपयोग में है, तो क्या यह जांचने का कोई तरीका है?


845

मैं C # में एक प्रोग्राम लिख रहा हूं जिसमें 1 इमेज फाइल को बार-बार एक्सेस करने की आवश्यकता है। अधिकांश समय यह काम करता है, लेकिन अगर मेरे कंप्यूटर का काम तेजी से चल रहा है, तो इससे पहले कि वह फाइल सिस्टम में वापस सेव हो जाए और फाइल को एक्सेस करने का प्रयास करे: "एक अन्य प्रक्रिया द्वारा फाइल का उपयोग करें"

मैं इसके चारों ओर एक रास्ता खोजना चाहता हूं, लेकिन मेरे सभी Googling ने केवल अपवाद हैंडलिंग का उपयोग करके चेक बनाने की उपज ली है। यह मेरे धर्म के खिलाफ है, इसलिए मैं सोच रहा था कि क्या किसी के पास इसे करने का बेहतर तरीका है?


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

3
लेकिन सिर्फ इस विशिष्ट मुद्दे के लिए; मैं फ़ाइल के हैंडल की जाँच नहीं करने की सलाह देता हूँ और असफल होने से पहले 3-5 बार कुछ प्रीसेट नंबर की कोशिश करें।
बॉबीशाफ्टो

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

क्या अपवाद के सभी उपयोग कुछ संभावित रूप से खतरनाक करके कुछ धारणा पर एक जांच नहीं है जबकि जानबूझकर विफलता की संभावना से इनकार नहीं कर रहे हैं?
jwg

26
आपके दर्शन में अपवादों की बुरी समझ है। अधिकांश लोग सोचते हैं कि अपवाद का मतलब पवित्र-बकवास-से-कयामत-कुछ-कुछ-गलत-मरना-मरना-मरना है। जब अपवाद का अर्थ है .... अपवाद। इसका मतलब है कि कुछ असाधारण घटना हुई जिसे आपको "संभालना" (या खाते के लिए) की आवश्यकता है। हो सकता है कि आप डेटा एक्सेस के लिए पुनः प्रयास करते रहना चाहते हों, हो सकता है कि उपयोगकर्ता को यह पता होना चाहिए कि आपको कनेक्शन नहीं मिल सकता है। आप क्या करते हैं? आप ConnectionFailedException को हैंडल करें और उपयोगकर्ता को सूचित करें, इसलिए हो सकता है, वे एक घंटे के बाद प्रयास करना बंद कर दें, और नोटिस करें कि केबल अनप्लग है।
ली लुईविअर

जवाबों:


543

इस समाधान पर अपडेट किया गया नोट : FileAccess.ReadWriteरीड-ओनली फ़ाइलों के लिए जाँच विफल हो जाएगी ताकि समाधान को जांचने के लिए संशोधित किया गया है FileAccess.Read। हालाँकि यह समाधान काम करता है क्योंकि इसके साथ जांच करने की कोशिश करना FileAccess.Readविफल हो जाएगा यदि फ़ाइल पर लिखें या पढ़ें लॉक है, हालांकि, यह समाधान काम नहीं करेगा यदि फ़ाइल पर लिखें या पढ़ें लॉक नहीं है, अर्थात इसे खोला गया है। (फाइल पढ़ने या लिखने के लिए) FileShare.Read या FileShare.Write एक्सेस के साथ।

मूल: मैंने पिछले कई वर्षों से इस कोड का उपयोग किया है, और मेरे पास इसके साथ कोई समस्या नहीं है।

अपवादों का उपयोग करने के बारे में अपनी झिझक को समझें, लेकिन आप उन सभी से बच नहीं सकते हैं:

protected virtual bool IsFileLocked(FileInfo file)
{
    try
    {
        using(FileStream stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None))
        {
            stream.Close();
        }
    }
    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;
    }

    //file is not locked
    return false;
}

60
यह एक महान समाधान है, लेकिन मेरी एक टिप्पणी है - आप फ़ाइल को एक्सेस मोड FileAccess के साथ खोलने के लिए तैयार नहीं हो सकते हैं। क्योंकि Readwrite हमेशा विफल हो जाएगा यदि फ़ाइल केवल-पढ़ने के लिए होती है।
adeel825

219
-1। यह एक खराब उत्तर है, क्योंकि फ़ाइल को किसी अन्य थ्रेड / प्रक्रिया द्वारा लॉक किया जा सकता है क्योंकि इसे IsFileLocked में बंद किया गया है, और इससे पहले कि आपके थ्रेड को इसे खोलने का मौका मिले।
पॉलीफ़ुन

16
मुझे लगता है कि यह एक शानदार जवाब है। मैं इस का उपयोग कर रहा के रूप में एक विस्तार विधि ला एक public static bool IsLocked(this FileInfo file) {/*...*/}
मनुजोर

53
@ क्रिस: आप सोच रहे होंगे कि क्या चल रहा है। चिंतित मत हो। आप डेली डब्ल्यूटीएफ समुदाय के क्रोध के अधीन हो रहे हैं: thedailywtf.com/Comments/…
पियरे लेबेपिन

16
@ क्रिस यह एक बुरी बात क्यों है। यह समुदाय अच्छे और बुरे उत्तरों की ओर इशारा करता है। यदि पेशेवरों का एक झुंड नोटिस करता है कि यह एक बुरी बात है, और नीचता में शामिल हो जाते हैं, तो साइट WAI है। और इससे पहले कि आप नकारात्मक हो जाएं, यदि आप उस लेख को पढ़ते हैं, तो वे "सही उत्तर को बढ़ावा देना" कहते हैं, गलत को कम नहीं करते। क्या आप चाहते हैं कि वे टिप्पणियों में भी अपने उत्थान की व्याख्या करें। मुझे एक और अच्छी साइट से परिचित कराने के लिए धन्यवाद!
ली लोविरे

569

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

आपका सबसे अच्छा दांव एक कोशिश पकड़ / अंत में जो फ़ाइल संभाल पाने की कोशिश करता है।

try
{
   using (Stream stream = new FileStream("MyFilename.txt", FileMode.Open))
   {
        // File/Stream manipulating code here
   }
} catch {
  //check here why it failed and ask user to retry if the file is in use.
}

124
+1। "कोई फ़ाइल उपयोग में है या नहीं" जानने के लिए कोई 100% सुरक्षित तरीका नहीं है क्योंकि मिलीसेकंड के बाद आप चेक करते हैं, फ़ाइल अब उपयोग में नहीं हो सकती है, या इसके विपरीत। इसके बजाय, आप केवल फ़ाइल खोलें और यदि कोई अपवाद नहीं है, तो इसका उपयोग करें।
सेदत कपानोग्लू

8
बहुत बुरा .NET कैस का समर्थन नहीं करता है। कुछ ऐसा, TryOpenFile (Ref FileHandle) जो सफलता / असफलता लौटाता है। हमेशा एक काम के आसपास होना चाहिए, अकेले अपवाद को संभालने पर भरोसा नहीं करना चाहिए। मुझे आश्चर्य है कि Microsoft Office यह कैसे करता है।
TamusJRoyce

2
यहाँ समझने के लिए महत्वपूर्ण बात यह है कि यह एपीआई केवल एक फ़ाइल हैंडल प्राप्त करने के लिए विंडोज़ एपीआई का उपयोग कर रहा है। जैसे कि उन्हें सी एपीआई से प्राप्त त्रुटि कोड का अनुवाद करना होगा और इसे फेंकने के लिए अपवाद के रूप में लपेटना होगा। हमारे पास .Net में अपवाद हैंडलिंग है तो इसका उपयोग क्यों न करें। इस तरह से आप अपने कोड में एक क्लीन फॉरवर्ड पाथ लिख सकते हैं और एरर हैंडलिंग को एक अलग कोड पाथ में छोड़ सकते हैं।
Spence

36
मेरे द्वारा किए जाने के बाद स्ट्रीम को बंद करना सुनिश्चित करने के लिए उपयोग कथन है। मुझे लगता है कि आप पाएंगे कि {}}} () {} का उपयोग करने की कोशिश {}} {obj.Dispose ()} की तुलना में कम वर्ण है। आपको यह भी पता चलेगा कि अब आपको उपयोग किए जाने वाले कथन के बाहर अपना ऑब्जेक्ट संदर्भ घोषित करने की आवश्यकता है, जो अधिक टाइपिंग है। यदि आपके पास एक स्पष्ट इंटरफ़ेस है तो आपको भी डालना होगा। अंत में आप ASAP को निपटाना चाहते हैं, और अंत में तर्क में UI या कोई अन्य लंबे समय तक चलने वाली क्रियाएं हो सकती हैं, जिनका कॉलिंग आईडीसपोज के साथ बहुत कम संबंध है। </ rant>
स्पैन

2
यह इस तथ्य को नकारता नहीं है कि आपको कोशिश के बाहर अपनी वस्तु को घोषित करना होगा और स्पष्ट रूप से निपटान को कॉल करना होगा, जो आपके लिए उपयोग करता है और एक ही चीज का मतलब है।
स्पेंस

92

यह जाँचने के लिए प्रयोग करें कि क्या कोई फ़ाइल लॉक है:

using System.IO;
using System.Runtime.InteropServices;
internal static class Helper
{
const int ERROR_SHARING_VIOLATION = 32;
const int ERROR_LOCK_VIOLATION = 33;

private static bool IsFileLocked(Exception exception)
{
    int errorCode = Marshal.GetHRForException(exception) & ((1 << 16) - 1);
    return errorCode == ERROR_SHARING_VIOLATION || errorCode == ERROR_LOCK_VIOLATION;
}

internal static bool CanReadFile(string filePath)
{
    //Try-Catch so we dont crash the program and can check the exception
    try {
        //The "using" is important because FileStream implements IDisposable and
        //"using" will avoid a heap exhaustion situation when too many handles  
        //are left undisposed.
        using (FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) {
            if (fileStream != null) fileStream.Close();  //This line is me being overly cautious, fileStream will never be null unless an exception occurs... and I know the "using" does it but its helpful to be explicit - especially when we encounter errors - at least for me anyway!
        }
    }
    catch (IOException ex) {
        //THE FUNKY MAGIC - TO SEE IF THIS FILE REALLY IS LOCKED!!!
        if (IsFileLocked(ex)) {
            // do something, eg File.Copy or present the user with a MsgBox - I do not recommend Killing the process that is locking the file
            return false;
        }
    }
    finally
    { }
    return true;
}
}

प्रदर्शन कारणों से मैं आपको उसी ऑपरेशन में फ़ाइल सामग्री पढ़ने की सलाह देता हूं। यहाँ कुछ उदाहरण हैं:

public static byte[] ReadFileBytes(string filePath)
{
    byte[] buffer = null;
    try
    {
        using (FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
        {
            int length = (int)fileStream.Length;  // get file length
            buffer = new byte[length];            // create buffer
            int count;                            // actual number of bytes read
            int sum = 0;                          // total number of bytes read

            // read until Read method returns 0 (end of the stream has been reached)
            while ((count = fileStream.Read(buffer, sum, length - sum)) > 0)
                sum += count;  // sum is a buffer offset for next reading

            fileStream.Close(); //This is not needed, just me being paranoid and explicitly releasing resources ASAP
        }
    }
    catch (IOException ex)
    {
        //THE FUNKY MAGIC - TO SEE IF THIS FILE REALLY IS LOCKED!!!
        if (IsFileLocked(ex))
        {
            // do something? 
        }
    }
    catch (Exception ex)
    {
    }
    finally
    {
    }
    return buffer;
}

public static string ReadFileTextWithEncoding(string filePath)
{
    string fileContents = string.Empty;
    byte[] buffer;
    try
    {
        using (FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
        {
            int length = (int)fileStream.Length;  // get file length
            buffer = new byte[length];            // create buffer
            int count;                            // actual number of bytes read
            int sum = 0;                          // total number of bytes read

            // read until Read method returns 0 (end of the stream has been reached)
            while ((count = fileStream.Read(buffer, sum, length - sum)) > 0)
            {
                sum += count;  // sum is a buffer offset for next reading
            }

            fileStream.Close(); //Again - this is not needed, just me being paranoid and explicitly releasing resources ASAP

            //Depending on the encoding you wish to use - I'll leave that up to you
            fileContents = System.Text.Encoding.Default.GetString(buffer);
        }
    }
    catch (IOException ex)
    {
        //THE FUNKY MAGIC - TO SEE IF THIS FILE REALLY IS LOCKED!!!
        if (IsFileLocked(ex))
        {
            // do something? 
        }
    }
    catch (Exception ex)
    {
    }
    finally
    { }     
    return fileContents;
}

public static string ReadFileTextNoEncoding(string filePath)
{
    string fileContents = string.Empty;
    byte[] buffer;
    try
    {
        using (FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
        {
            int length = (int)fileStream.Length;  // get file length
            buffer = new byte[length];            // create buffer
            int count;                            // actual number of bytes read
            int sum = 0;                          // total number of bytes read

            // read until Read method returns 0 (end of the stream has been reached)
            while ((count = fileStream.Read(buffer, sum, length - sum)) > 0) 
            {
                sum += count;  // sum is a buffer offset for next reading
            }

            fileStream.Close(); //Again - this is not needed, just me being paranoid and explicitly releasing resources ASAP

            char[] chars = new char[buffer.Length / sizeof(char) + 1];
            System.Buffer.BlockCopy(buffer, 0, chars, 0, buffer.Length);
            fileContents = new string(chars);
        }
    }
    catch (IOException ex)
    {
        //THE FUNKY MAGIC - TO SEE IF THIS FILE REALLY IS LOCKED!!!
        if (IsFileLocked(ex))
        {
            // do something? 
        }
    }
    catch (Exception ex)
    {
    }
    finally
    {
    }

    return fileContents;
}

इसे स्वयं आज़माएँ:

byte[] output1 = Helper.ReadFileBytes(@"c:\temp\test.txt");
string output2 = Helper.ReadFileTextWithEncoding(@"c:\temp\test.txt");
string output3 = Helper.ReadFileTextNoEncoding(@"c:\temp\test.txt");

8
अगर वहाँ इतने सारे "मैजिक नंबर" नहीं होते, तो मैं upvote करता। en.wikipedia.org/wiki/Magic_number_(programming)
Kris

3
मैं एररकोड तुलना की बात कर रहा था, बिट शिफ्ट्स की नहीं। हालाँकि अब आप इसका उल्लेख करते हैं ...
क्रिश

1
आपका कैच IOExceptionसामान्य की जगह Exceptionऔर फिर टाइप पर टेस्ट होना चाहिए ।
Askolein

3
@JeremyThompson दुख की बात है कि आपने विशिष्ट IOExceptionको सामान्य के बाद रखा । सामान्य व्यक्ति पास से गुजरने वाली हर चीज को पकड़ लेगा और विशिष्ट IOExceptionहमेशा अकेला रहेगा। बस दो को स्वैप कर दो।
Askolein

मुझे यह समाधान पसंद है। एक अन्य सुझाव: अगर (IsFileLocked (पूर्व)) के रूप में एक और पकड़ के अंदर मैं पूर्व फेंक देंगे। यह तब उस मामले को संभालेगा जहां फ़ाइल मौजूद नहीं है (या कोई अन्य IOException) अपवाद को फेंककर।
shindigo

7

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

उदाहरण के लिए, नीचे दिए गए फ़ंक्शन का उपयोग करें

TimeoutFileAction(() => { System.IO.File.etc...; return null; } );

पुन: प्रयोज्य विधि जो 2 सेकंड के बाद निकलती है

private T TimeoutFileAction<T>(Func<T> func)
{
    var started = DateTime.UtcNow;
    while ((DateTime.UtcNow - started).TotalMilliseconds < 2000)
    {
        try
        {
            return func();                    
        }
        catch (System.IO.IOException exception)
        {
            //ignore, or log somewhere if you want to
        }
    }
    return default(T);
}

6

शायद आप FileSystemWatcher का उपयोग कर सकते हैं और परिवर्तित घटना के लिए देख सकते हैं ।

मैंने खुद इसका इस्तेमाल नहीं किया है, लेकिन यह एक शॉट के लायक हो सकता है। यदि फाइलसिस्टम वॉच इस मामले के लिए थोड़ा भारी हो जाता है, तो मैं कोशिश / कैच / स्लीप लूप के लिए जाऊंगा।


1
FileSystemWatcher का उपयोग करना मदद नहीं करता है, क्योंकि फ़ाइल निर्माण / परिवर्तन की शुरुआत में बनाई गई और बदली गई घटनाएं उठाती हैं। यहां तक ​​कि छोटी फ़ाइलों को .NET सिस्टम द्वारा फाइलसिस्टमइवेंटहैंडलर कॉलबैक के माध्यम से चलाने के लिए ऑपरेटिंग सिस्टम द्वारा लिखित और बंद करने के लिए अधिक समय की आवश्यकता होती है। यह बहुत दुखद है, लेकिन फ़ाइल तक पहुंचने से पहले प्रतीक्षा समय का अनुमान लगाने या अपवाद लूप में चलाने के अलावा कोई अन्य विकल्प नहीं है ...

FileSystemWatcher एक ही समय में बहुत सारे परिवर्तनों को बहुत अच्छी तरह से संभाल नहीं पाता है, इसलिए इससे सावधान रहें।
बेन एफ

1
BTW, क्या आप लोगों ने डिबगिंग करते हुए और थ्रेड्स देखते समय देखा है कि MS अपने FSW "FileSystemWather" को कॉल करता है? वैसे भी क्या है?
देवलोक

शायद ही मुझे यह समस्या मिली क्योंकि फ़ाइलसिस्टमवॉचर के साथ एक विंडोज़ सेवा प्रक्रिया को बंद करने से पहले फ़ाइल को पढ़ने की कोशिश करती है।
15

6

आप एक ऐसा कार्य लौटा सकते हैं जो उपलब्ध होते ही आपको एक धारा प्रदान करता है। यह एक सरलीकृत समाधान है, लेकिन यह एक अच्छा प्रारंभिक बिंदु है। यह धागा सुरक्षित है।

private async Task<Stream> GetStreamAsync()
{
    try
    {
        return new FileStream("sample.mp3", FileMode.Open, FileAccess.Write);
    }
    catch (IOException)
    {
        await Task.Delay(TimeSpan.FromSeconds(1));
        return await GetStreamAsync();
    }
}

आप हमेशा की तरह इस स्ट्रीम का उपयोग कर सकते हैं:

using (var stream = await FileStreamGetter.GetStreamAsync())
{
    Console.WriteLine(stream.Length);
}

3
जब तक एक पुनरावृत्ति से एक ढेर अतिप्रवाह तक कितने सेकंड GetStreamAsync()?
सीएडी ने

@Cadbloke, आपने बहुत अच्छी बात उठाई है। वास्तव में मेरा नमूना स्टैक ओवरफ़्लो अपवाद हो सकता है, अगर कोई फ़ाइल लंबे समय तक उपलब्ध नहीं है। इस उत्तर से संबंधित stackoverflow.com/questions/4513438/… , यह 5 घंटे में अपवाद को बढ़ा सकता है।
इवान ब्रान्ट्स

अपने उपयोग के मामलों से संबंधित I / O अपवाद को फेंकना बेहतर है यदि हम कहते हैं कि फ़ाइल को पढ़ने के 10 प्रयास विफल हो गए हैं। 10 बार विफल होने के बाद दूसरी रणनीति एक दूसरे के लिए प्रतीक्षा समय बढ़ा रही हो सकती है। आप दोनों का मिश्रण भी उपयोग कर सकते हैं।
इवान ब्रान्स

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

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

4

एकमात्र तरीका मुझे पता है कि Win32 अनन्य लॉक API का उपयोग करना है जो बहुत तेज़ नहीं है, लेकिन उदाहरण मौजूद हैं।

ज्यादातर लोग, इस के लिए एक सरल समाधान के लिए, बस कोशिश / पकड़ / नींद छोरों।


1
आप इस API का उपयोग पहली बार फाइल को खोले बिना नहीं कर सकते हैं, जिस बिंदु पर अब आपको इसकी आवश्यकता नहीं है।
हैरी जॉनसन

1
श्रोडिंगर की फाइल।
TheLastGIS

4
static bool FileInUse(string path)
    {
        try
        {
            using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
            {
                fs.CanWrite
            }
            return false;
        }
        catch (IOException ex)
        {
            return true;
        }
    }

string filePath = "C:\\Documents And Settings\\yourfilename";
bool isFileInUse;

isFileInUse = FileInUse(filePath);

// Then you can do some checking
if (isFileInUse)
   Console.WriteLine("File is in use");
else
   Console.WriteLine("File is not in use");

उम्मीद है की यह मदद करेगा!


10
आपके द्वारा किया गया वास्तविक चेक ठीक है; इसे एक फंक्शन के अंदर रखना भ्रामक है। आप फ़ाइल खोलने से पहले इस तरह के फ़ंक्शन का उपयोग नहीं करना चाहते हैं। फ़ंक्शन के अंदर, फ़ाइल को खोला, जांचा और बंद किया गया है। तब प्रोग्रामर ASSUMES फ़ाइल का उपयोग करने के लिए फ़ाइल ठीक है और उपयोग के लिए इसे खोलने का प्रयास करता है। यह खराब है क्योंकि इसका उपयोग किया जा सकता है और इस फाइल को खोलने के लिए कतारबद्ध एक अन्य प्रक्रिया द्वारा लॉक किया जा सकता है। पहली बार इसे (जाँच के लिए) खोला गया था और दूसरी बार इसे (उपयोग के लिए) खोला गया था, OS आपकी प्रक्रिया को रद्द कर सकता था और दूसरी प्रक्रिया चला सकता था।
लेक

3

ऊपर दिए गए स्वीकृत उत्तर एक समस्या से ग्रस्त हैं जहाँ अगर फ़ाइल को FileShare.Read मोड के साथ लिखने के लिए खोला गया है या यदि फ़ाइल में रीड-ओनली विशेषता है तो कोड काम नहीं करेगा। यह संशोधित समाधान सबसे मज़बूती से काम करता है, दो बातों को ध्यान में रखकर (जैसा कि स्वीकृत समाधान के लिए भी सही है):

  1. यह उन फाइलों के लिए काम नहीं करेगा जिन्हें राइट शेयर मोड के साथ खोला गया है
  2. यह थ्रेडिंग मुद्दों को ध्यान में नहीं रखता है, इसलिए आपको इसे अलग से लॉक करने या थ्रेडिंग समस्याओं को संभालने की आवश्यकता होगी।

उपरोक्त को ध्यान में रखते हुए, यह जाँचता है कि क्या फ़ाइल को लिखने के लिए लॉक किया गया है या पढ़ने को रोकने के लिए लॉक किया गया है :

public static bool FileLocked(string FileName)
{
    FileStream fs = null;

    try
    {
        // NOTE: This doesn't handle situations where file is opened for writing by another process but put into write shared mode, it will not throw an exception and won't show it as write locked
        fs = File.Open(FileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None); // If we can't open file for reading and writing then it's locked by another process for writing
    }
    catch (UnauthorizedAccessException) // https://msdn.microsoft.com/en-us/library/y973b725(v=vs.110).aspx
    {
        // This is because the file is Read-Only and we tried to open in ReadWrite mode, now try to open in Read only mode
        try
        {
            fs = File.Open(FileName, FileMode.Open, FileAccess.Read, FileShare.None);
        }
        catch (Exception)
        {
            return true; // This file has been locked, we can't even open it to read
        }
    }
    catch (Exception)
    {
        return true; // This file has been locked
    }
    finally
    {
        if (fs != null)
            fs.Close();
    }
    return false;
}

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

1
यह सच है, व्यक्ति केवल किसी भी समय जांच कर सकता है (या घटनाओं की सदस्यता ले सकता है), स्वीकृत समाधान पर इस दृष्टिकोण का लाभ यह है कि यह केवल पढ़ने के लिए विशेषता और राइट लॉक की जांच कर सकता है और गलत सकारात्मक नहीं लौटा सकता है।
रॉबर्ट

3

3-लाइनर काम करने के अलावा और केवल संदर्भ के लिए: यदि आप पूर्ण विकसित जानकारी चाहते हैं - Microsoft देव केंद्र पर एक छोटी परियोजना है:

https://code.msdn.microsoft.com/windowsapps/How-to-know-the-process-704839f4

परिचय से:

.NET फ्रेमवर्क 4.0 में विकसित C # नमूना कोड यह पता लगाने में मदद करेगा कि कौन सी प्रक्रिया है जो किसी फ़ाइल पर लॉक है। RmStartSession फ़ंक्शन जो rstrtmgr.dll में शामिल है, का उपयोग रीस्टार्ट प्रबंधक सत्र बनाने के लिए किया गया है और वापसी परिणाम के अनुसार Win32Exception ऑब्जेक्ट का एक नया उदाहरण बनाया गया है। RmRegisterRescources फ़ंक्शन के माध्यम से रीस्टार्ट प्रबंधक सत्र के लिए संसाधनों को पंजीकृत करने के बाद , RmGetList फ़ंक्शन को यह जांचने के लिए आमंत्रित किया जाता है कि कौन से अनुप्रयोग RM_PROCESS_INSTO सरणी की गणना करके किसी विशेष फ़ाइल का उपयोग कर रहे हैं ।

यह "रीस्टार्ट मैनेजर सेशन" से जुड़कर काम करता है।

रीस्टार्ट प्रबंधक सत्र के साथ पंजीकृत संसाधनों की सूची का उपयोग करता है ताकि यह निर्धारित किया जा सके कि कौन से एप्लिकेशन और सेवाएं बंद होनी चाहिए और फिर से चालू होनी चाहिए। संसाधनों को फ़ाइल नाम, सेवा संक्षिप्त नाम या RM_UNIQUE_PROCESS संरचनाओं द्वारा पहचाना जा सकता है जो चल रहे अनुप्रयोगों का वर्णन करते हैं।

यह आपकी विशेष जरूरतों के लिए थोड़ा अतिरंजित हो सकता है ... लेकिन यदि आप चाहते हैं, तो आगे बढ़ें और बनाम परियोजना को पकड़ो।


2

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

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

ध्यान दें कि आपको उन स्पष्ट तरीकों के बारे में पता होना चाहिए जिनका यह शोषण किया जा सकता है। आखिरकार, फाइलें लॉक नहीं होंगी। इसके अलावा, ध्यान रखें कि ऐसे अन्य कारण भी हैं जिनके परिणामस्वरूप आपका Moveऑपरेशन विफल हो सकता है। स्पष्ट रूप से उचित त्रुटि से निपटने (MSDN) यहाँ मदद कर सकता है।

var originalFolder = @"c:\myHugeCollectionOfFiles"; // your folder name here
var someFolder = Path.Combine(originalFolder, "..", Guid.NewGuid().ToString("N"));

try
{
    Directory.Move(originalFolder, someFolder);

    // Use files
}
catch // TODO: proper exception handling
{
    // Inform user, take action
}
finally
{
    Directory.Move(someFolder, originalFolder);
}

व्यक्तिगत फ़ाइलों के लिए मैं जेरेमी थॉम्पसन द्वारा पोस्ट किए गए लॉकिंग सुझाव के साथ रहना चाहूंगा।


नमस्ते, जब से उत्तरों के क्रम में परिवर्तन होता है, आप स्पष्ट कर सकते हैं कि आपके ऊपर कौन सा पद इस लोकप्रिय क्यूए के पाठकों के लिए है। धन्यवाद।
जेरेमी थॉम्पसन

1
@JeremyThompson आप सही हैं, धन्यवाद, मैं पोस्ट संपादित करूँगा। मैं आपसे समाधान का उपयोग करूँगा, मुख्यतः आपके FileShareलॉक के सही उपयोग और जाँच के कारण।
atlaste

2

यहाँ कुछ कोड है जो जहाँ तक मैं बता सकता हूं वह वही है जो स्वीकृत उत्तर के समान है लेकिन कम कोड के साथ:

    public static bool IsFileLocked(string file)
    {
        try
        {
            using (var stream = File.OpenRead(file))
                return false;
        }
        catch (IOException)
        {
            return true;
        }        
    }

हालाँकि मुझे लगता है कि निम्नलिखित तरीके से इसे करना अधिक मजबूत है:

    public static void TryToDoWithFileStream(string file, Action<FileStream> action, 
        int count, int msecTimeOut)
    {
        FileStream stream = null;
        for (var i = 0; i < count; ++i)
        {
            try
            {
                stream = File.OpenRead(file);
                break;
            }
            catch (IOException)
            {
                Thread.Sleep(msecTimeOut);
            }
        }
        action(stream);
    }

2

आप एकाधिक एप्लिकेशन से फ़ाइलों तक पहुँचने के लिए मेरी लाइब्रेरी का उपयोग कर सकते हैं।

आप इसे एनगेट से स्थापित कर सकते हैं: इंस्टाल-पैकेज Xabe.FileLock

यदि आप इसके बारे में अधिक जानकारी चाहते हैं तो https://github.com/tomaszzmuda/Xabe.FileLock की जाँच करें

ILock fileLock = new FileLock(file);
if(fileLock.Acquire(TimeSpan.FromSeconds(15), true))
{
    using(fileLock)
    {
        // file operations here
    }
}

fileLock.Acquire मेथड तभी सही वापस आएगा जब इस ऑब्जेक्ट के लिए एक्सक्लूसिव फाइल को लॉक किया जा सकता है। लेकिन जो ऐप फाइल अपलोड कर रहा है, उसे फाइल लॉक में भी करना होगा। यदि ऑब्जेक्ट दुर्गम है तो मेट्रो झूठी हो जाती है।


1
कृपया उत्तर के रूप में कुछ टूल या लाइब्रेरी पोस्ट न करें। कम से कम यह प्रदर्शित करें कि यह उत्तर में समस्या को कैसे हल करता है।
पेपर 1111

जोड़ा गया डेमो :) क्षमा करें @ paper1111
टॉमस udaमुडा

1
सभी प्रक्रियाओं की आवश्यकता है जो सहयोग करने के लिए फ़ाइल का उपयोग कर रहे हैं। ओपी मूल समस्या के लिए लागू नहीं होना चाहिए।
हैरी जॉनसन

2

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

string str_path_and_name = str_path + '\\' + str_filename;
FileInfo fInfo = new FileInfo(str_path_and_name);
bool open_elsewhere = false;
try
{
    fInfo.MoveTo(str_path_and_name);
}
catch (Exception ex)
{
    open_elsewhere = true;
}

if (open_elsewhere)
{
    //handle case
}

0

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

इस तरह के घृणित तरीके से विफल होने के बजाय, मैंने ऑटो-इन्क्रिएटेड फ़ाइल संस्करण पर भरोसा करने का फैसला किया:

private static string WriteFileToDisk(byte[] data, string fileName, int version = 0)
{
    try
    {
        var versionExtension = version > 0 ? $"_{version:000}" : string.Empty;
        var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{fileName}{versionExtension}.pdf");
        using (var writer = new FileStream(filePath, FileMode.Create))
        {
            writer.Write(data, 0, data.Length);
        }
        return filePath;
    }
    catch (IOException)
    {
        return WriteFileToDisk(data, fileName, ++version);
    }
}

catchसही IOException (s) को पकड़ने के लिए ब्लॉक को कुछ और देखभाल दी जा सकती है । मैं शायद स्टार्टअप पर ऐप स्टोरेज को भी साफ कर दूंगा क्योंकि ये फाइलें अस्थायी वैसे भी होती हैं।

मुझे लगता है कि यह ओपी के सवाल के दायरे से परे है कि अगर फ़ाइल का उपयोग हो रहा है, लेकिन यह वास्तव में समस्या थी जिसे मैं हल करने के लिए देख रहा था जब मैं यहां पहुंचा तो शायद यह किसी और के लिए उपयोगी होगा।


0

कुछ इस तरह की मदद करेगा?

var fileWasWrittenSuccessfully = false;
while (fileWasWrittenSuccessfully == false)
{
    try
    {
        lock (new Object())
        {
            using (StreamWriter streamWriter = new StreamWriter(filepath.txt"), true))
            {
                streamWriter.WriteLine("text");
            }
        }

        fileWasWrittenSuccessfully = true;
    }
    catch (Exception)
    {

    }
}

-2

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


@jcolebrand ताले क्या? आप की नकल? या जो आपने टेम्पर में डाला है?
कलुब

5
यदि आप फ़ाइल की प्रतिलिपि बनाते हैं, तो उस पर किसी और से काम करने की अपेक्षा नहीं की जाती है, और आप अस्थायी फ़ाइल का उपयोग करने जा रहे हैं, और फिर कोई इसे कॉपी करने के ठीक बाद आपको लॉक कर देता है, तो संभवतः आपने डेटा खो दिया है।
21

-3

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

इसलिए, मैंने इसके लिए अतिरिक्त कोड जोड़ा। मेरे मामले में मैं लोड करना चाहता हूँ XDocument:

        XDocument xDoc = null;

        while (xDoc == null)
        {
            while (IsFileBeingUsed(_interactionXMLPath))
            {
                Logger.WriteMessage(Logger.LogPrioritet.Warning, "Deserialize can not open XML file. is being used by another process. wait...");
                Thread.Sleep(100);
            }
            try
            {
                xDoc = XDocument.Load(_interactionXMLPath);
            }
            catch
            {
                Logger.WriteMessage(Logger.LogPrioritet.Error, "Load working!!!!!");
            }
        }

तुम क्या सोचते हो? क्या मैं किसी चीज़ को बदल सकता हूँ? शायद मुझे IsFileBeingUsed फ़ंक्शन का उपयोग करने की आवश्यकता नहीं थी?

धन्यवाद


4
IsFileBeingUsed क्या है? IsFileBeingUsed के बारे में स्रोत कोड?
किनिकेत
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.