ফোল্ডারটি (। নেট) ফাঁকা আছে কীভাবে তা দ্রুত পরীক্ষা করবেন?


140

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

public static bool CheckFolderEmpty(string path)
{
    if (string.IsNullOrEmpty(path))
    {
        throw new ArgumentNullException("path");
    }

    var folder = new DirectoryInfo(path);
    if (folder.Exists)
    {
        return folder.GetFileSystemInfos().Length == 0;
    }

    throw new DirectoryNotFoundException();
}

এই পদ্ধতির ঠিক আছে বলে মনে হচ্ছে। কিন্তু !! পারফরম্যান্সের দৃষ্টিকোণ থেকে এটি খুব খারাপ। গেটফাইসিসটেমআইএনফোস () একটি খুব কঠিন পদ্ধতি। প্রকৃতপক্ষে, এটি ফোল্ডারের সমস্ত ফাইল সিস্টেমের অবজেক্টগুলিকে গণ্য করে, তাদের সমস্ত বৈশিষ্ট্য পায়, বস্তু তৈরি করে, টাইপিত অ্যারে ইত্যাদি পূরণ করে এবং এগুলি কেবল দৈর্ঘ্য পরীক্ষা করার জন্য। বোকা, তাই না?

আমি সবেমাত্র এই জাতীয় কোডটির প্রোফাইল দিয়েছি এবং নির্ধারিত করেছি যে এই জাতীয় পদ্ধতির ~ 250 ডলার calls 500ms এ কার্যকর করা হয়। এটি খুব ধীর এবং আমি বিশ্বাস করি যে এটি আরও দ্রুত করা সম্ভব।

কোনও পরামর্শ?


7
কৌতূহলের বাইরে, আপনি কেন 250 বার ডিরেক্টরিটি পরীক্ষা করতে চান?
ya23

2
@ ya23 আমি মনে করি যে কেউ 250 টি ভিন্ন ভিন্ন ডিরেক্টরি পরীক্ষা করতে চান। এক একও 250 বার নয়।
ম্যাথিউ পাগ

উত্তর:


282

.NET 4 এ Directoryএবং এর DirectoryInfoমধ্যে একটি নতুন বৈশিষ্ট্য রয়েছে যা তাদের IEnumerableঅ্যারের পরিবর্তে একটি ফিরিয়ে আনতে দেয় এবং সমস্ত ডিরেক্টরি বিষয়বস্তু পড়ার আগে ফলাফলগুলি ফেরত শুরু করে।

public bool IsDirectoryEmpty(string path)
{
    IEnumerable<string> items = Directory.EnumerateFileSystemEntries(path);
    using (IEnumerator<string> en = items.GetEnumerator())
    {
        return !en.MoveNext();
    }
}

সম্পাদনা: উত্তরটি আবার দেখে, আমি বুঝতে পারি যে এই কোডটি আরও সহজ করা যেতে পারে ...

public bool IsDirectoryEmpty(string path)
{
    return !Directory.EnumerateFileSystemEntries(path).Any();
}

আমি এই সমাধানটি পছন্দ করি, এটি কি কিছু নির্দিষ্ট ফাইল টাইপের জন্য পরীক্ষা করা যায়? .নিয় (এর পরিবর্তে) ("jpg") কাজ করছে বলে মনে হয় নি
ডেনিস

5
@ ডেনিস, আপনি কলটিতে একটি ওয়াইল্ডকার্ড প্যাটার্ন নির্দিষ্ট করতে পারেন EnumerateFileSystemEntriesবা ব্যবহার করতে পারেন .Any(condition)(ল্যাম্বডা এক্সপ্রেশন হিসাবে শর্তটি নির্দিষ্ট করুন বা একটি প্যারামিটার হিসাবে কোনও পথ গ্রহণ করে এমন পদ্ধতি হিসাবে)।
টমাস লেভেস্ক

টাইপকাস্ট প্রথম কোড উদাহরণ থেকে সরানো যেতে পারে:return !items.GetEnumerator().MoveNext();
গ্যারি

1
@ গ্যারি, আপনি যদি এটি করেন, তবে গণকের নিষ্পত্তি হবে না, সুতরাং গণকটি আবর্জনা সংগ্রহ না করা অবধি ডিরেক্টরিটি তালাবন্ধ হয়ে যাবে।
টমাস লেভস্ক

এটি ফাইল রয়েছে এমন ডিরেক্টরিগুলির জন্য দুর্দান্ত কাজ করে বলে মনে হয় তবে ডিরেক্টরিতে যদি অন্য পরিচালক থাকে তবে এটি খালি রয়েছে বলে ফিরে আসে।
কাইরান

32

এখানে অতিরিক্ত দ্রুত সমাধানটি দেওয়া হয়েছে, যা আমি শেষ পর্যন্ত বাস্তবায়ন করেছি। এখানে আমি WinAPI এবং ফাংশন FindFirstFile , FindNextFile ব্যবহার করছি । এটি ফোল্ডারে সমস্ত আইটেমের গণনা এড়াতে দেয় এবং ফোল্ডারের প্রথম অবজেক্ট সনাক্ত করার পরে ঠিক থেমে যায় । এই বর্ণনটি উপরে বর্ণিত চেয়ে ~ 6 (!!) গুণ বেশি গতিযুক্ত। ৩ms০ এসএম তে 250 কল!

private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct WIN32_FIND_DATA
{
    public uint dwFileAttributes;
    public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
    public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
    public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
    public uint nFileSizeHigh;
    public uint nFileSizeLow;
    public uint dwReserved0;
    public uint dwReserved1;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
    public string cFileName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
    public string cAlternateFileName;
}

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);

[DllImport("kernel32.dll")]
private static extern bool FindClose(IntPtr hFindFile);

public static bool CheckDirectoryEmpty_Fast(string path)
{
    if (string.IsNullOrEmpty(path))
    {
        throw new ArgumentNullException(path);
    }

    if (Directory.Exists(path))
    {
        if (path.EndsWith(Path.DirectorySeparatorChar.ToString()))
            path += "*";
        else
            path += Path.DirectorySeparatorChar + "*";

        WIN32_FIND_DATA findData;
        var findHandle = FindFirstFile(path, out findData);

        if (findHandle != INVALID_HANDLE_VALUE)
        {
            try
            {
                bool empty = true;
                do
                {
                    if (findData.cFileName != "." && findData.cFileName != "..")
                        empty = false;
                } while (empty && FindNextFile(findHandle, out findData));

                return empty;
            }
            finally
            {
                FindClose(findHandle);
            }
        }

        throw new Exception("Failed to get directory first file",
            Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()));
    }
    throw new DirectoryNotFoundException();
}

আমি আশা করি এটি ভবিষ্যতে কারও জন্য কার্যকর হবে।


আপনার সমাধান ভাগ করে নেওয়ার জন্য আপনাকে ধন্যবাদ।
গ্রেগ

3
আপনি যোগ করতে হবে SetLastError = trueকরতে DllImportজন্য FindFirstFileজন্য, যাতে Marshal.GetHRForLastWin32Error()এর মন্তব্য বিভাগে বর্ণিত হিসাবে, সঠিকভাবে কাজ করার আহ্বান () GetHRForLastWin32Error জন্য দুটিই MSDN ডক
জোয়েল ভি। আর্নেস্ট-দেইং

আমি নিম্নলিখিত মনে উত্তর একটু ভাল এটা এছাড়াও সাব ডিরেক্টরি ফাইলের জন্য হচ্ছে stackoverflow.com/questions/724148/...
মায়াঙ্ক

21

আপনি চেষ্টা করে দেখতে পারেন Directory.Exists(path)এবং Directory.GetFiles(path)- সম্ভবত কম ওভারহেড (কোনো অবজেক্ট - শুধু স্ট্রিং ইত্যাদি)।


সর্বদা হিসাবে, আপনি দ্রুত ট্রিগার বন্ধ! সেখানে কয়েক সেকেন্ডের মধ্যে আমাকে মারধর! :-)
সেরেব্রেস

আপনি উভয়েই আমার চেয়ে দ্রুত ছিলেন ... বিস্তারিত আমার দৃষ্টি আকর্ষণ করা ;-)
ইওন ক্যাম্পবেল

2
যদিও আমার কোন ভাল কাজ করেনি; প্রথম উত্তর, এবং একটি ভোট ছাড়া ;-( শুধুমাত্র এক
মার্ক Gravell

আনপিক্সড ... কারও হাতে পিষে কুড়াল রয়েছে, মিথথিন্স
মার্ক গ্র্যাভেল

1
আমি ভাল হিসাবে, আত মনে GetFiles ডিরেক্টরি একটি তালিকা পাবে তাই এটি একটি ভাল ধারণা GetDirectories জন্য একটি চেক করা হবে বলে মনে হয়
Kairan

18
private static void test()
{
    System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    sw.Start();

    string [] dirs = System.IO.Directory.GetDirectories("C:\\Test\\");
    string[] files = System.IO.Directory.GetFiles("C:\\Test\\");

    if (dirs.Length == 0 && files.Length == 0)
        Console.WriteLine("Empty");
    else
        Console.WriteLine("Not Empty");

    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);
}

এই দ্রুত পরীক্ষাটি ফোল্ডারটির জন্য 2 মিলি সেকেন্ডে ফিরে আসে যখন খালি থাকে এবং সাবফোল্ডার এবং ফাইল থাকে (প্রতিটি ফোল্ডারে 5 টি ফোল্ডার থাকে)


3
ফাইলগুলির তালিকা না পেয়েই যদি 'ডায়ার' সরাসরি খালি না হয় তবে আপনি ফিরে এসে এটি উন্নতি করতে পারবেন।
সামজডসন

3
হ্যাঁ, তবে এতে হাজার হাজার ফাইল থাকলে কী হবে?
টমাস লেভস্কে

3
আপনি কনসোলটিতে লেখার জন্য সময়টিও মাপছেন, যা তুচ্ছ নয়।
ctusch

11

আমি এটি ফোল্ডার এবং ফাইলগুলির জন্য ব্যবহার করি (এটি অনুকূল কিনা জানেন না)

    if(Directory.GetFileSystemEntries(path).Length == 0)

8

আপনি যদি খাঁটি সি # রেখে এবং উইনপি কলের জন্য যেতে আপত্তি করেন না , তবে আপনি প্যাথসডাইরেক্টরিএম্পটি () ফাংশনটি বিবেচনা করতে চাইতে পারেন । এমএসডিএন অনুসারে, ফাংশন:

যদি pszPath একটি খালি ডিরেক্টরি হয় তবে সত্য ফেরত দেয়। যদি pszPath ডিরেক্টরি না হয় বা এটিতে কমপক্ষে একটি ফাইল অন্তর্ভুক্ত থাকে তবে FALSE প্রদান করে। বা ".."।

এটি এমন একটি ফাংশন বলে মনে হচ্ছে যা আপনি যা চান ঠিক তেমন করে তাই এটি সম্ভবত সেই কাজের জন্য ভালভাবে অনুকূলিত হয়েছে (যদিও আমি এটি পরীক্ষা করে দেখিনি)।

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


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

4
যারা এই পথে যেতে চান তাদের জন্য একটি নোট। দেখে মনে হচ্ছে shlwapi.dll থেকে এই PathIsDirectoryEmpty () পদ্ধতিটি ভিস্তা 32/64 এবং এক্সপি 32/64 মেশিনে সূক্ষ্ম কাজ করে তবে কিছু উইন 7 মেশিনে বোমা ফাটিয়ে দেয়। Shlwapi.dll এর সংস্করণগুলি উইন্ডোজের বিভিন্ন সংস্করণে প্রেরণে এটির কিছু করতে হবে। সতর্ক থাকুন।
অ্যালেক্স_১

7

আমি এটির মধ্যে পারফরম্যান্সের পরিসংখ্যান সম্পর্কে জানি না, তবে আপনি কি Directory.GetFiles()স্থির পদ্ধতিটি ব্যবহার করার চেষ্টা করেছেন ?

এটি ফাইলের নামযুক্ত ফাইল স্ট্রিং অ্যারে ফিরিয়ে দেয় (ফাইলআইএনফোস নয়) এবং আপনি অ্যারের দৈর্ঘ্য উপরের মতো একইভাবে পরীক্ষা করতে পারবেন।


একই সমস্যা, অনেকগুলি ফাইল থাকলে এটি ধীর হতে পারে ... তবে এটি সম্ভবত গেটফাইসিসটেমআইএনফোস এর চেয়ে দ্রুত
থমাস

4

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

  public bool DirectoryIsEmpty(string path)
  {
    int fileCount = Directory.GetFiles(path).Length;
    if (fileCount > 0)
    {
        return false;
    }

    string[] dirs = Directory.GetDirectories(path);
    foreach (string dir in dirs)
    {
      if (! DirectoryIsEmpty(dir))
      {
        return false;
      }
    }

    return true;
  }

Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories).Any()
জোনাথন গিলবার্ট

3

আপনাকে যে কোনও ক্ষেত্রে এই তথ্যের জন্য হার্ড ড্রাইভ যেতে হবে, এবং এটি একা কোনও অবজেক্ট তৈরি এবং অ্যারে পূরণকে তিরস্কার করবে।


1
সত্য, যদিও কিছু বস্তু তৈরির ক্ষেত্রে ডিস্কে অতিরিক্ত মেটাডেটা সন্ধান করা জড়িত যা প্রয়োজনীয় হতে পারে না।
অ্যাডাম রোজেনফিল্ড

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

3

আমি কোনও পদ্ধতির বিষয়ে অবগত নই যা কোনও সংক্ষেপে আপনাকে জানাবে যে কোনও প্রদত্ত ফোল্ডারে অন্য কোনও ফোল্ডার বা ফাইল রয়েছে কিনা তা ব্যবহার করে:

Directory.GetFiles(path);
&
Directory.GetDirectories(path);

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


2

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

সমস্ত তদন্তের পরে, আমি একটি সিদ্ধান্তে পৌঁছেছি, যে খাঁটি। নেট অধীন আরও অনুকূলিতা অসম্ভব। আমি WinAPI এর FindFirstFile ফাংশন নিয়ে খেলতে যাচ্ছি । আশা করি এটি সাহায্য করবে।


1
আগ্রহের বাইরে, এই ক্রিয়াকলাপের জন্য আপনার এত উচ্চ দক্ষতার প্রয়োজনের কারণগুলি কী কী?
meandmycode

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

2

কিছু সময় আপনি উপ ডিরেক্টরিগুলির মধ্যে কোনও ফাইল উপস্থিত কিনা তা যাচাই করতে চাইতে পারেন এবং খালি সাব ডিরেক্টরিগুলি উপেক্ষা করুন; এই ক্ষেত্রে আপনি নীচের পদ্ধতি ব্যবহার করতে পারেন:

public bool isDirectoryContainFiles(string path) {
    if (!Directory.Exists(path)) return false;
    return Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories).Any();
}


0

ব্র্যাড পার্কস কোড ভিত্তিক :

    public static bool DirectoryIsEmpty(string path)
    {
        if (System.IO.Directory.GetFiles(path).Length > 0) return false;

        foreach (string dir in System.IO.Directory.GetDirectories(path))
            if (!DirectoryIsEmpty(dir)) return false;

        return true;
    }

-1

আমার কোডটি আশ্চর্যজনক যে এটি মাত্র 00: 00: 00.0007143 ফোল্ডারে 34 ফাইল সহ মিলিসেকেন্ডের তুলনায় কম

   System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    sw.Start();

     bool IsEmptyDirectory = (Directory.GetFiles("d:\\pdf").Length == 0);

     sw.Stop();
     Console.WriteLine(sw.Elapsed);

প্রকৃতপক্ষে, আপনি যদি এটি 229 দিয়ে গুন করেন এবং গেটডাইরেটরিজ () যোগ করেন তবে আপনি আমার হিসাবে একই ফল পাবেন :)
zhe

-1

এখানে এমন কিছু যা আপনাকে এটি করতে সহায়তা করতে পারে। আমি এটি দুটি পুনরাবৃত্তিতে করতে সক্ষম হয়েছি।

 private static IEnumerable<string> GetAllNonEmptyDirectories(string path)
   {
     var directories =
        Directory.EnumerateDirectories(path, "*.*", SearchOption.AllDirectories)
        .ToList();

     var directoryList = 
     (from directory in directories
     let isEmpty = Directory.GetFiles(directory, "*.*", SearchOption.AllDirectories).Length == 0
     where !isEmpty select directory)
     .ToList();

     return directoryList.ToList();
   }

-1

যেহেতু আপনি যে কোনও উপায়ে ডিরেক্টরীআইনফোতে কাজ করতে যাচ্ছেন, তাই আমি একটি এক্সটেনশন নিয়ে যাব

public static bool IsEmpty(this DirectoryInfo directoryInfo)
{
    return directoryInfo.GetFileSystemInfos().Count() == 0;
}

-2

এটা ব্যবহার কর. ইহা সহজ.

Public Function IsDirectoryEmpty(ByVal strDirectoryPath As String) As Boolean
        Dim s() As String = _
            Directory.GetFiles(strDirectoryPath)
        If s.Length = 0 Then
            Return True
        Else
            Return False
        End If
    End Function

2
সহজ, সম্ভবত। তবে ভুল। এটিতে দুটি বড় বাগ রয়েছে: এটি কোনও ফোল্ডার পথে রয়েছে কিনা তা সনাক্ত করে না , কেবল ফাইল রয়েছে এবং এটি অস্তিত্বহীন পথে একটি ব্যতিক্রম ছুঁড়ে দেবে। এটি আসলে ওপি-র মূলের তুলনায় ধীর হওয়ার সম্ভাবনাও রয়েছে কারণ আমি নিশ্চিত যে এটি সমস্ত এন্ট্রি পেয়েছে এবং সেগুলি ফিল্টার করে।
অ্যান্ড্রু বারবার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.