ऐसी क्रॉस-नेटवर्क खोज को तेज़ करने की कुंजी नेटवर्क पर अनुरोधों की संख्या को कम करना है। सभी निर्देशिकाएं प्राप्त करने के बजाय, और फिर फ़ाइलों के लिए प्रत्येक की जांच करें, कोशिश करें और एक कॉल से सबकुछ प्राप्त करें।
.NET 3.5 में सभी फ़ाइलों और फ़ोल्डर्स को रिकर्सिवली करने के लिए कोई भी तरीका नहीं है, इसलिए आपको इसे स्वयं बनाना होगा (नीचे देखें)। एक चरण में .NET 4 नए अधिभार में मौजूद है।
DirectoryInfo
का उपयोग करके यह भी जानकारी प्राप्त करता है कि लौटाया गया नाम एक फ़ाइल या निर्देशिका है, जो कॉल को भी घटा देता है।
struct AllDirectories {
public List<string> DirectoriesWithoutFiles { get; set; }
public List<string> DirectoriesWithFiles { get; set; }
}
static class FileSystemScanner {
public AllDirectories DivideDirectories(string startingPath) {
var startingDir = new DirectoryInfo(startingPath);
// allContent IList<FileSystemInfo>
var allContent = GetAllFileSystemObjects(startingDir);
var allFiles = allContent.Where(f => !(f.Attributes & FileAttributes.Directory))
.Cast<FileInfo>();
var dirs = allContent.Where(f => (f.Attributes & FileAttributes.Directory))
.Cast<DirectoryInfo>();
var allDirs = new SortedList<DirectoryInfo>(dirs, new FileSystemInfoComparer());
var res = new AllDirectories {
DirectoriesWithFiles = new List<string>()
};
foreach (var file in allFiles) {
var dirName = Path.GetDirectoryName(file.Name);
if (allDirs.Remove(dirName)) {
// Was removed, so first time this dir name seen.
res.DirectoriesWithFiles.Add(dirName);
}
}
// allDirs now just contains directories without files
res.DirectoriesWithoutFiles = new List<String>(addDirs.Select(d => d.Name));
}
class FileSystemInfoComparer : IComparer<FileSystemInfo> {
public int Compare(FileSystemInfo l, FileSystemInfo r) {
return String.Compare(l.Name, r.Name, StringComparison.OrdinalIgnoreCase);
}
}
}
को लागू करने GetAllFileSystemObjects
नेट संस्करण पर निर्भर करता है:
इस बंटवारे सभी निर्देशिकाओं और फ़ाइलों की एक सूची का मतलब है कुछ इस तरह हो जाता है। पर ।नेट 4 यह बहुत आसान है:
ILIst<FileSystemInfo> GetAllFileSystemObjects(DirectoryInfo root) {
return root.GetFileSystemInfos("*.*", SearchOptions.AllDirectories);
}
पहले के संस्करणों पर थोड़ा और अधिक काम की जरूरत है:
ILIst<FileSystemInfo> GetAllFileSystemObjects(DirectoryInfo root) {
var res = new List<FileSystemInfo>();
var pending = new Queue<DirectoryInfo>(new [] { root });
while (pending.Count > 0) {
var dir = pending.Dequeue();
var content = dir.GetFileSystemInfos();
res.AddRange(content);
foreach (var dir in content.Where(f => (f.Attributes & FileAttributes.Directory))
.Cast<DirectoryInfo>()) {
pending.Enqueue(dir);
}
}
return res;
}
यह दृष्टिकोण संभव के रूप में कई बार, बस एक बार नेट 4 पर या के रूप में फाइल सिस्टम में कॉल एक बार प्रति संस्करणों पर प्रति निर्देशिका, नेटवर्क क्लाइंट और सर्वर को अंतर्निहित फाइल सिस्टम कॉल और नेटवर्क राउंड ट्रिप की संख्या को कम करने की इजाजत देता है।
FileSystemInfo
प्राप्त करने के उदाहरणों में एकाधिक फ़ाइल सिस्टम संचालन की आवश्यकता है (मुझे विश्वास है कि यह कुछ हद तक ओएस निर्भर है), लेकिन प्रत्येक नाम के लिए किसी भी समाधान को यह जानने की जरूरत है कि यह फ़ाइल या निर्देशिका है, तो यह कुछ स्तर पर टालने योग्य नहीं है (FindFileFirst
/FindNextFile
/FindClose
के पी/Invoke का उपयोग किए बिना)।
अलावा, ऊपर एक विभाजन विस्तार विधि के साथ आसान होगा:
Tuple<IEnumerable<T>,IEnumerable<T>> Extensions.Partition<T>(
this IEnumerable<T> input,
Func<T,bool> parition);
लेखन कि आलसी एक दिलचस्प व्यायाम होगा होने के लिए (केवल इनपुट लेने जब आउटपुट में से एक पर कुछ दोहराता, जबकि दूसरे को बफरिंग)।
"यह" कितना समय लगता है? कोड की यह विशेष पंक्ति, या अपनी डिस्क पर हजारों निर्देशिकाओं पर लूप में इसका उपयोग कर रही है? –
फ़ोल्डर में कितनी फाइलें हैं? –
@ करल्सन प्रत्येक फ़ोल्डर में एक फ़ाइल है। – user278618