কোনও ফাইল ব্যবহার হচ্ছে কিনা তা পরীক্ষা করার কোনও উপায় আছে?


845

আমি সি # তে একটি প্রোগ্রাম লিখছি যা বার বার 1 টি চিত্র ফাইল অ্যাক্সেস করতে হবে। বেশিরভাগ সময় এটি কাজ করে, তবে যদি আমার কম্পিউটারটি দ্রুত চলতে থাকে তবে ফাইলটি সিস্টেমে ফিরে সংরক্ষণ করার আগে এটি ফাইলটি অ্যাক্সেস করার চেষ্টা করবে এবং একটি ত্রুটি ছুঁড়ে ফেলবে: "অন্য প্রক্রিয়া দ্বারা ব্যবহৃত ফাইল"

আমি এর আশেপাশে কোনও উপায় খুঁজতে চাই, তবে আমার সমস্ত গুগলিং কেবল ব্যতিক্রম হ্যান্ডলিং ব্যবহার করে চেক তৈরি করতে পেরেছে। এটি আমার ধর্মের পরিপন্থী, তাই আমি ভাবছিলাম যে কারও কাছে করার আরও ভাল উপায় আছে?


30
ঠিক আছে, আপনি সিস্টেমে সমস্ত খোলা হ্যান্ডলগুলি পরীক্ষা করে এটি পরীক্ষা করতে পারেন। তবে, উইন্ডোজ যেহেতু একটি মাল্টিটাস্কিং অপারেটিং সিস্টেম, তাই ফাইলটি খোলা আছে এবং আপনি তা মনে করছেন না তা নির্ধারণ করার জন্য আপনার কোডটি চালানোর ঠিক পরে একটি প্রক্রিয়া কোড সেই ফাইলটি ব্যবহার শুরু করে, তারপরে আপনি যখন চেষ্টা করবেন তখন এটি ব্যবহার করুন, আপনি একটি ত্রুটি পাবেন। তবে, প্রথমে যাচাই-বাছাইয়ে কোনও দোষ নেই; যখন আপনার আসলে এটির প্রয়োজন হয় তখন এটি ব্যবহার করা হয় না বলে মনে করবেন না।
ববিশ্যাফটোয়

3
তবে কেবল এই নির্দিষ্ট ইস্যুর জন্য; আমি ফাইল হ্যান্ডলগুলি পরীক্ষা না করার পরামর্শ দিচ্ছি এবং ব্যর্থ হওয়ার আগে 3-5 বলুন, কিছু প্রিসেট সংখ্যক বার চেষ্টা করে দেখাব।
ববিশ্যাফটোয়

এই চিত্র ফাইলটি কীভাবে উত্পন্ন হয়? প্রজন্ম শেষ না হওয়া পর্যন্ত আপনি কি আপনার প্রোগ্রামটি থামিয়ে / ঘুমাতে / বিরতি দিতে পারবেন? পরিস্থিতি সামাল দেওয়ার জন্য এটি সর্বোত্তম উপায়। যদি তা না হয় তবে আমি মনে করি না আপনি ব্যতিক্রম হ্যান্ডলিং ব্যবহার এড়াতে পারবেন।

ইচ্ছাকৃতভাবে ব্যর্থতার সম্ভাবনা প্রত্যাখ্যান না করে ব্যতিক্রমগুলির সমস্ত ব্যবহার কি সম্ভাব্য বিপজ্জনক কিছু করে কিছু অনুমানের উপর নজর দেওয়া যায় না?
jwg

26
আপনার দর্শনের ব্যতিক্রমগুলির সম্পর্কে খারাপ ধারণা রয়েছে। বেশিরভাগ লোক মনে করেন ব্যতিক্রমগুলির অর্থ পবিত্র-ক্র্যাপ-ডুম-এর-ডুম-কিছু-এর-ভুল-ডাই-ডাই-ডাই। যখন ব্যতিক্রম মানে .... ব্যতিক্রম। এর অর্থ ব্যতিক্রমী কিছু ঘটেছিল যা আপনাকে "হ্যান্ডেল" করতে হবে (বা তার জন্য অ্যাকাউন্ট করতে হবে)। হতে পারে আপনি ডেটা অ্যাক্সেসের জন্য পুনরায় চেষ্টা চালিয়ে যেতে চান, সম্ভবত ব্যবহারকারীর জানতে হবে যে আপনি কোনও সংযোগ পেতে পারেন না। আপনি কি করেন? আপনি কানেকশনফেইডএক্সেপশন পরিচালনা করেন এবং ব্যবহারকারীকে অবহিত করেন, তাই সম্ভবত, তারা এক ঘন্টা পরে চেষ্টা করা বন্ধ করে দেবে, এবং তারেরটি আনপ্লাগড লক্ষ্য করেছে।
লি লুভিয়ের

উত্তর:


543

এই সমাধানটির জন্য আপডেট করা দ্রষ্টব্য : চেক করা FileAccess.ReadWriteকেবল পঠনযোগ্য ফাইলগুলির জন্য ব্যর্থ হবে তাই সমাধানটি পরীক্ষা করার জন্য সমাধানটি পরিবর্তন করা হয়েছে FileAccess.Read। যদিও এই সমাধানটি কাজ করে যাচাই করার চেষ্টা করা FileAccess.Readব্যর্থ হবে যদি ফাইলটিতে রাইটিং বা রিড লক থাকে তবে এই সমাধানটি কাজ করবে না যদি ফাইলটিতে রাইটিং বা রিড লক না থাকে, অর্থাৎ এটি খোলা হয়েছে ফাইল পড়ার জন্য (পড়তে বা লেখার জন্য) পড়ুন।

মূল: আমি বিগত বেশ কয়েক বছর ধরে এই কোডটি ব্যবহার করেছি এবং এটি নিয়ে আমার কোনও সমস্যা হয়নি।

ব্যতিক্রমগুলি ব্যবহার সম্পর্কে আপনার দ্বিধা বুঝতে পারেন তবে আপনি সেগুলি সব সময় এড়াতে পারবেন না:

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
এটি দুর্দান্ত সমাধান, তবে আমার একটি মন্তব্য আছে - আপনি অ্যাক্সেস মোড ফাইলঅ্যাক্সেসের সাহায্যে ফাইলটি খুলতে চাইবেন না since পড়ুন লেখার সময় থেকে পড়ুন ফাইলটি কেবল পঠনযোগ্য হলেই সর্বদা ব্যর্থ হবে।
adeel825

219
-1। এটি একটি দুর্বল উত্তর, কারণ ইসফিললকে বন্ধ হয়ে যাওয়ার পরে এবং আপনার থ্রেডটি খোলার সুযোগ পাওয়ার আগে ফাইলটি অন্য থ্রেড / প্রক্রিয়া দ্বারা লক হয়ে যেতে পারে gets
পলিফুন

16
আমি মনে করি এটি একটি দুর্দান্ত উত্তর। আমি এটিকে এক্সটেনশন পদ্ধতি হিসাবে ব্যবহার করছি public static bool IsLocked(this FileInfo file) {/*...*/}। লা ।
মনুজোর

53
@ ক্রিসডাব্লু: আপনি কী ভাবছেন তা ভাবতে পারেন। শঙ্কিত হবেন না। আপনি কেবল ডেইলি ডব্লিউটিএফ সম্প্রদায়ের ক্রোধের শিকার হচ্ছেন: thedailywtf.com/Comments/…
পিয়েরে লেবাউপিন

16
@ ক্রিসডব্লু কেন এটি একটি খারাপ জিনিস। এই সম্প্রদায়টি এখানে ভাল এবং খারাপ উত্তরগুলি নির্দেশ করার জন্য। যদি গুচ্ছ পেশাদাররা লক্ষ্য করেন যে এটি একটি খারাপ জিনিস, এবং ডাউনটাতে যোগ দিন, তবে সাইটটি ডব্লিউএআই। এবং আপনি নেতিবাচক হওয়ার আগে, আপনি এই নিবন্ধটি পড়লে, তারা "সঠিক উত্তরটি আপভোট করুন" বলে ভুলটিকে নীচে নামাবেন না। আপনি কি চান যে তারা মন্তব্যগুলিতেও তাদের উপকারগুলি ব্যাখ্যা করবে? আমাকে অন্য একটি ভাল সাইটে পরিচয় করিয়ে দেওয়ার জন্য ধন্যবাদ!
লি লুভিয়ের

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 CAS সমর্থন করে না। এর মতো কিছু, ট্রিওপেনফাইলে (রেফারেন্স ফাইলহ্যান্ডল) যা সাফল্য / ব্যর্থতা ফেরায়। সর্বদা এমন একটি কাজ থাকা উচিত যা একা ব্যতিক্রম হ্যান্ডলিংয়ের উপর নির্ভর না করে। আমি অবাক হয়ে দেখি মাইক্রোসফ্ট অফিস এটি কীভাবে করে।
তমুসজেরোয়েস

2
এখানে বোঝার মূল বিষয়টি হ'ল এই এপিআইটি কোনও ফাইল হ্যান্ডেল পাওয়ার জন্য উইন্ডোজ এপিআই ব্যবহার করছে। এ হিসাবে তাদের সিআইপি থেকে প্রাপ্ত ত্রুটি কোডটি অনুবাদ করতে হবে এবং এটিকে নিক্ষেপ করার জন্য ব্যতিক্রম করতে আবদ্ধ করতে হবে। আমাদের কাছে নেট ব্যর্থতার হাতল রয়েছে et নেট তাই কেন এটি ব্যবহার করবেন না। এইভাবে আপনি আপনার কোডে একটি পরিষ্কার অগ্রসর পাথ লিখতে পারেন এবং একটি পৃথক কোডের পথে ত্রুটিটি পরিচালনা করার বিষয়টি ছেড়ে যেতে পারেন।
স্প্যান্স

36
ব্যবহারের বিবৃতিটি হল আমার কাজ শেষ হওয়ার পরে স্ট্রিমটি বন্ধ হয়ে গেছে তা নিশ্চিত করা। আমি মনে করি আপনি দেখতে পাচ্ছেন যে () {using ব্যবহারটি চেষ্টা-এর চেয়ে কম অক্ষর}} অবশেষে {.জেজ.ডিসপজ ()}} আপনি দেখতে পাবেন যে আপনাকে এখন আপনার স্টেটমেন্টের রেফারেন্সটি ব্যবহারের স্টেটমেন্টের বাইরে ঘোষণা করতে হবে যা বেশি টাইপ করছে। আপনার যদি একটি স্পষ্ট ইন্টারফেস থাকে তবে আপনাকেও কাস্ট করতে হবে। অবশেষে আপনি ASAP নিষ্পত্তি করতে চান, এবং শেষ অবধি যুক্তিযুক্ত UI বা অন্য কোনও দীর্ঘ চলমান ক্রিয়া থাকতে পারে যা আইডিসপোজ কল করার সাথে খুব কমই আছে। </ran>
স্পেন

2
এটি এই সত্যটিকে অস্বীকার করে না যে আপনাকে চেষ্টা করার বাইরে আপনার অবজেক্টটি ঘোষণা করতে হবে এবং স্পষ্টভাবে ডিসপোজ কল করতে হবে, যা আপনার জন্য ব্যবহার করে এবং একই জিনিসটি বোঝায়।
স্পেন 0

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
আমি সেখানে উজ্জীবিত হত যদি সেখানে "জাদু সংখ্যা" খুব বেশি না থাকে en.wikedia.org/wiki/Magic_number_( প্রোগ্রামিং)
ক্রিস

3
আমি বিট শিফট নয়, ত্রুটি কোড কোডের তুলনা উল্লেখ করছি। যদিও এখন আপনি এটি উল্লেখ করেছেন ...
ক্রিস

1
আপনার ক্যাচটি IOExceptionসাধারণের পরিবর্তে Exceptionএবং তারপরে টাইপ পরীক্ষা করা উচিত।
আসকোলিন

3
@ জেরেমি টম্পসন দুঃখের সাথে আপনি সাধারণটির IOExceptionপরে নির্দিষ্টটি রেখেছেন । জেনারেল যাবতীয় সমস্ত কিছু ধরে ফেলবে এবং নির্দিষ্টটি 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

সম্ভবত আপনি একটি ফাইলসিস্টেমওয়াটার ব্যবহার করতে পারেন এবং পরিবর্তিত ইভেন্টের জন্য নজর রাখতে পারেন ।

আমি নিজে এটি ব্যবহার করি নি, তবে এটি শটের জন্য মূল্যবান হতে পারে। যদি ফাইলসীমওয়াতচার এই মামলার জন্য কিছুটা ভারী হয়ে যায় তবে আমি চেষ্টা / ধরা / স্লিপ লুপে যাব।


1
একটি ফাইলসিস্টেমওয়াচার ব্যবহার করে কোনও লাভ হয় না, কারণ তৈরি এবং পরিবর্তিত ইভেন্টগুলি ফাইল তৈরি / পরিবর্তনের শুরুতে উত্থাপিত হয়। এমনকি নেট ফাইলগুলিকে অপারেটিং সিস্টেম দ্বারা রাইটিং এবং বন্ধ করার জন্য আরও বেশি সময় প্রয়োজন need এটি অত্যন্ত দুঃখজনক, তবে ফাইলটি অ্যাক্সেস করার আগে বা অপেক্ষা ব্যতীত লুপগুলিতে চালানোর আগে

ফাইলসিস্টেমওয়াটার যদিও একই সাথে প্রচুর পরিবর্তনগুলি খুব ভালভাবে পরিচালনা করে না, তাই এটির সাথে সতর্ক থাকুন।
বেন এফ

1
বিটিডাব্লু, আপনি কি থ্রেডগুলি ডিবাগিং এবং পর্যবেক্ষণ করার সময় লক্ষ্য করেছেন যে এমএস তাদের নিজস্ব এফএসডাব্লু "ফাইলসিস্টেমওয়াদার" বলে? যাইহোক একটি w11 কি?
ডেভলর্ড

অবশ্যই আমি এই সমস্যাটি পেয়েছি কারণ প্রক্রিয়াটি বন্ধ হওয়ার আগে ফাইলসিসটামওয়াচার সহ একটি উইন্ডোজ পরিষেবা ফাইলটি পড়ার চেষ্টা করে।
ফ্রিডোভেলপার

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()?
সিএডি

@ ক্যাডব্লোক, আপনি একটি খুব ভাল বিষয় উত্থাপন করেছেন। প্রকৃতপক্ষে আমার নমুনায় স্ট্যাক ওভারফ্লো ব্যতিক্রম থাকতে পারে যদি কোনও ফাইল দীর্ঘ সময়ের জন্য উপলব্ধ না হয়। এই উত্তরের সাথে সম্পর্কিত স্ট্যাকওভারফ্লো / প্রশ্নগুলি / 4513438/… , এটি 5 ঘন্টা ব্যতিক্রম বাড়িয়ে তুলতে পারে।
ইভান ব্রানেটস

আপনার ব্যবহারের ক্ষেত্রে সম্পর্কিত যদি I বলি যে ফাইলটি পড়ার 10 টি প্রচেষ্টা ব্যর্থ হয়েছে তবে I / O ব্যতিক্রম ছুঁড়ে দেওয়া ভাল। অন্য কৌশলগুলি সম্ভবত 10 টি প্রচেষ্টা ব্যর্থ হয়ে যাওয়ার পরে দ্বিতীয়টির জন্য অপেক্ষা করার সময় বাড়িয়ে তুলতে পারে। আপনি উভয় একটি মিশ্রণ ব্যবহার করতে পারেন।
ইভান ব্রানেটস

আমি ফাইলটি লক করা আছে কেবলমাত্র (এবং কর) ব্যবহারকারীকে সতর্ক করব। তারা এটিকে সাধারণত নিজেরাই লক করে রাখে তাই তারা সম্ভবত এটি সম্পর্কে কিছু করবে। অথবা না.
সিএডি

কিছু ক্ষেত্রে, আপনাকে পুনরায় চেষ্টা করার নীতি ব্যবহার করা উচিত কারণ কোনও ফাইল এখনও প্রস্তুত না হতে পারে। কিছু অস্থায়ী ফোল্ডারে চিত্রগুলি ডাউনলোড করতে একটি ডেস্কটপ অ্যাপ্লিকেশনটি কল্পনা করুন। অ্যাপ্লিকেশনটি ডাউনলোড শুরু হয় এবং একই সাথে আপনি এই ফোল্ডারটি ফাইল এক্সপ্লোরারে খুলুন। উইন্ডোজ তাত্ক্ষণিকভাবে একটি থাম্বনেইল তৈরি করতে এবং ফাইলটি লক করতে চায়। একই সময়ে, আপনার অ্যাপ লক করা চিত্রটি অন্য কোনও জায়গায় প্রতিস্থাপন করার চেষ্টা করে। আপনি যদি পুনরায় চেষ্টা করার নীতিটি ব্যবহার না করেন তবে আপনি একটি ব্যতিক্রম পাবেন।
ইভান ব্রানেটস

4

আমার জানা একমাত্র উপায় হ'ল উইন 32 এক্সক্লুসিভ লক এপিআই ব্যবহার করা যা খুব দ্রুত নয়, তবে উদাহরণ বিদ্যমান।

বেশিরভাগ লোক, এর সহজ সমাধানের জন্য, কেবল / ধরা / ঘুমের লুপগুলি চেষ্টা করে try


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
আপনার করা আসল চেকটি ঠিক আছে; এটি একটি ফাংশন ভিতরে রাখা বিভ্রান্তিকর। আপনি কোনও ফাইল খোলার আগে এই জাতীয় কোনও ফাংশন ব্যবহার করতে চান না। ফাংশনের অভ্যন্তরে ফাইলটি খোলা, চেক করা এবং বন্ধ করা হয়। তারপরে প্রোগ্রামার এই ফাইলটি ধরে রাখার জন্য এটি এখনও ঠিক আছে এবং এটি ব্যবহারের জন্য খোলার চেষ্টা করে। এটি খারাপ কারণ এটি ব্যবহার করতে এবং এই ফাইলটি খোলার জন্য সারি করা অন্য প্রক্রিয়া দ্বারা লক করা যেতে পারে। প্রথমবারের মধ্যে এটি খোলা হয়েছিল (যাচাই করার জন্য) এবং দ্বিতীয় বার এটি খোলা হয়েছিল (ব্যবহারের জন্য), ওএস আপনার প্রক্রিয়াটি নির্ধারণ করতে পারে এবং অন্য কোনও প্রক্রিয়া চালিয়ে যেতে পারে।
লেকি

3

উপরের স্বীকৃত উত্তরগুলি এমন একটি সমস্যায় ভুগছে যেখানে ফাইল যদি কোন ফাইল-শেয়ারের সাথে লেখার জন্য খোলা হয়েছে e পড়ুন মোডে বা যদি ফাইলটিতে কেবল পঠনযোগ্য বৈশিষ্ট্য থাকে তবে কোডটি কাজ করবে না। এই পরিবর্তিত সমাধানটি দুটি বিষয় মাথায় রাখার সাথে (গ্রহণযোগ্য সমাধানের ক্ষেত্রেও সত্য) সবচেয়ে নির্ভরযোগ্যভাবে কাজ করে:

  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
এটি সত্য, একমাত্র যে কোনও নির্দিষ্ট মুহুর্তে (বা ইভেন্টগুলিতে সাবস্ক্রাইব) চেক করতে পারবেন, গৃহীত সমাধানের মাধ্যমে এই পদ্ধতির সুবিধাটি হ'ল এটি কেবল একটি পঠনযোগ্য বৈশিষ্ট্য এবং একটি লেখার লক পরীক্ষা করতে পারে এবং কোনও মিথ্যা ইতিবাচক প্রত্যাবর্তন করতে পারে না।
rboy

3

3-লাইনারগুলি কাজ করা বাদ দিন এবং কেবল রেফারেন্সের জন্য: আপনি যদি পুরো বিকাশ চান তবে তথ্য চান - মাইক্রোসফ্ট ডেভ সেন্টারে একটি ছোট প্রকল্প রয়েছে:

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

ভূমিকা থেকে:

.NET ফ্রেমওয়ার্ক ৪.০-তে বিকশিত সি # নমুনা কোডটি কোনও ফাইলটিতে লক রয়েছে এমন প্রক্রিয়াটি কী তা খুঁজে বের করতে সহায়তা করবে। আরআরস্টার্টসেশন ফাংশন যা rstrtmgr.dll এ অন্তর্ভুক্ত রয়েছে তা পুনরায় আরম্ভের ব্যবস্থাপক সেশন তৈরি করতে ব্যবহৃত হয়েছে এবং রিটার্ন ফলাফল অনুসারে উইন 32 এক্সেক্সিপশন অবজেক্টের একটি নতুন উদাহরণ তৈরি করা হয়েছে। আরএমরেজিস্টাররেসকোর্স ফাংশনের মাধ্যমে রিস্টার্ট ম্যানেজার সেশনে রিসোর্সগুলি রেজিস্ট্রেশন করার পরে , আরএমগ্রেটলিস্ট ফাংশনটি আরএম_প্রোসিএসসিপিএফও অ্যারে গণনা করে কোনও নির্দিষ্ট ফাইল কী ব্যবহার করছে তা যাচাই করার জন্য ডাকা হয়

এটি "পুনঃসূচনা পরিচালক সেশন" এর সাথে সংযুক্ত হয়ে কাজ করে works

পুনরায় আরম্ভ করার ব্যবস্থাপকটি কোন অ্যাপ্লিকেশন এবং পরিষেবাগুলি বন্ধ করে পুনরায় চালু করতে হবে তা নির্ধারণের জন্য অধিবেশনটির সাথে নিবন্ধিত সংস্থার তালিকা ব্যবহার করে। সম্পদগুলি ফাইলের নাম, পরিষেবা সংক্ষিপ্ত নাম বা RM_UNIQUE_PROCESS স্ট্রাকচার দ্বারা সনাক্ত করা যেতে পারে যা চলমান অ্যাপ্লিকেশনগুলিকে বর্ণনা করে।

এটি আপনার নির্দিষ্ট প্রয়োজনের জন্য কিছুটা ওভাররেঞ্জিনারিড হতে পারে ... তবে যদি আপনি এটি চান তবে এগিয়ে যান এবং বনাম-প্রকল্পটি ধরুন


2

আমার অভিজ্ঞতায় আপনি সাধারণত এটি করতে চান, তারপরে অভিনব কিছু করার জন্য আপনার ফাইলগুলি 'রক্ষা করুন' এবং তারপরে 'সুরক্ষিত' ফাইলগুলি ব্যবহার করুন। যদি আপনি কেবল একটি ফাইল ব্যবহার করতে চান তবে আপনি জেরেমি থম্পসনের উত্তরে বর্ণিত কৌশলটি ব্যবহার করতে পারেন। তবে, আপনি যদি প্রচুর ফাইলগুলিতে এটি করার চেষ্টা করেন (যেমন উদাহরণস্বরূপ আপনি যখন ইনস্টলারটি লিখছেন) তবে আপনি কিছুটা ক্ষতি করতে পারেন।

এটি সমাধানের খুব দুর্দান্ত উপায় হ'ল এই বিষয়টি ব্যবহার করে যে আপনার ফাইল সিস্টেমটি সেখানকার যে কোনও একটি ফাইল যদি ব্যবহৃত হচ্ছে তবে আপনাকে কোনও ফোল্ডারের নাম পরিবর্তন করতে দেয় না। ফোল্ডারটিকে একই ফাইল সিস্টেমে রাখুন এবং এটি কবজির মতো কাজ করবে।

মনে রাখবেন যে এটি ব্যবহার করা যেতে পারে এমন স্পষ্ট উপায় সম্পর্কে আপনার সচেতন হওয়া উচিত। সর্বোপরি, ফাইলগুলি লক হবে না। এছাড়াও, সচেতন থাকুন যে আরও কিছু কারণ রয়েছে যার ফলে আপনার Moveঅপারেশন ব্যর্থ হতে পারে। স্পষ্টতই সঠিক ত্রুটি হ্যান্ডলিং (এমএসডিএন) এখানে সহায়তা করতে পারে।

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
@ জেরেমি টম্পসন আপনি ঠিক বলেছেন, ধন্যবাদ, আমি পোস্টটি সম্পাদনা করব। আমি আপনার কাছ থেকে সমাধানটি ব্যবহার করব, মূলত আপনার সঠিক ব্যবহার FileShareএবং লকটি পরীক্ষা করার কারণে।
অ্যাটলাস্ট

2

এখানে এমন কিছু কোড রয়েছে যা আমি যতটা ভাল বলতে পারি তা গৃহীত উত্তর হিসাবে তবে কম কোড সহ একই কাজ করে:

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

তবে আমি নিম্নলিখিত পদ্ধতিতে এটি করা আরও দৃ more় বলে মনে করি:

    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

ডেমো যুক্ত হয়েছে :) দুঃখিত @ পেপার 1111
টমাসজ Żmuda

1
সহযোগিতা করার জন্য ফাইলটি ব্যবহার করা সমস্ত প্রক্রিয়া প্রয়োজন। ওপিএস মূল সমস্যার ক্ষেত্রে প্রযোজ্য নয়।
হ্যারি জনস্টন 21

2

আমার একবার অনলাইন ব্যাকআপ সংরক্ষণাগারে পিডিএফগুলি আপলোড করা দরকার ছিল। তবে ব্যবহারকারী যদি অন্য কোনও প্রোগ্রামে ফাইল খোলা থাকে (যেমন পিডিএফ রিডার) the আমার তাড়াহুড়োয়, আমি এই থ্রেডের শীর্ষ কয়েকটি উত্তর চেষ্টা করেছি কিন্তু সেগুলি কাজ করতে পারা যায় না। আমার জন্য কী কাজ করেছিল তা পিডিএফ ফাইলটিকে তার নিজস্ব ডিরেক্টরিতে স্থানান্তরিত করার চেষ্টা করছিল । আমি খুঁজে পেয়েছি যে ফাইলটি অন্য কোনও প্রোগ্রামে খোলা থাকলে এটি ব্যর্থ হবে, এবং যদি পদক্ষেপটি সফল হয় তবে পুনরুদ্ধার-অপারেশন প্রয়োজন হবে না কারণ এটি আলাদা ডিরেক্টরিতে সরিয়ে নেওয়া হলে হবে। অন্যের নির্দিষ্ট ব্যবহারের ক্ষেত্রে এটি কার্যকর হতে পারে সে ক্ষেত্রে আমি আমার মৌলিক সমাধানটি পোস্ট করতে চাই।

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আমি সঠিক আইওএক্সেপশন (গুলি) ধরছি তা নিশ্চিত করার জন্য ব্লকে । আমি সম্ভবত স্টার্টআপে অ্যাপ স্টোরেজটি পরিষ্কার করে ফেলব কারণ এই ফাইলগুলি যাইহোক অস্থায়ী হওয়ার উদ্দেশ্যে।

আমি বুঝতে পারি যে এটি ফাইলটি ব্যবহার করছে কিনা তা খতিয়ে দেখার ওপির প্রশ্নের পরিধি ছাড়িয়ে গেছে তবে এখানে আসার সময় আমি যে সমস্যাটি সমাধান করতে চাইছিলাম তা সম্ভবত এটি অন্য কারও পক্ষে কার্যকর হবে।


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
যদি আপনি ফাইলটি অনুলিপি করেন, অন্য কেউ এটির কাজ না করে বলে প্রত্যাশী হন এবং আপনি টেম্প ফাইলটি ব্যবহার করতে যাচ্ছেন, এবং তারপরে কেউ এটি অনুলিপি করার পরে ঠিকই এটি লক করে রাখে, তবে আপনি সম্ভাব্য ডেটা হারিয়ে ফেলেছেন।
jcolebrand

-3

আমি এই কার্যকারিতাটি ব্যবহার করি, তবে ইসফাইললকড ফাংশনটির সাথে ফাইল লকিং পরীক্ষা করার সময় এবং আমি ফাইলটি খোলার মাঝে আমার একটি টাইমস্প্যান থাকে। এই টাইমস্প্যানে অন্য কিছু থ্রেড ফাইলটি খুলতে পারে, তাই আমি আইওএক্সেপশন পেয়ে যাব।

সুতরাং, আমি এটির জন্য অতিরিক্ত কোড যুক্ত করেছি। আমার ক্ষেত্রে আমি এক্সডোকামেন্ট লোড করতে চাই:

        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!!!!!");
            }
        }

আপনি কি মনে করেন? আমি কি কিছু পরিবর্তন করতে পারি? সম্ভবত আমি ইসফাইলবিজিং ফাংশনটি আদৌ ব্যবহার করতে পারি নি?

ধন্যবাদ


4
ইসফাইলবিজিং কি? ইসফাইলবিজিংস সম্পর্কে উত্স কোড?
কিকিনেট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.