C#中可独立使用的SID-所有者映射Dictionary实现咨询
Hey there! Let's break down how to build that reusable, cacheable Dictionary for SID-to-Owner mappings you need, while fixing some potential pitfalls in your current code. Your core idea is smart—caching these mappings avoids redundant SID translations, which will definitely save you time.
First, Let's Fix the Key Issue in Your Current Code
Right now, you're collecting all SIDs and Owners in separate arrays, then running Distinct() on both. This is risky because:
- The order of unique SIDs and unique Owners might not line up (e.g., if two different SIDs map to the same Owner, your
Owner_Uniquelist will be shorter thanSID_Unique, breaking the index-based mapping). - You're still translating every SID every time you encounter it, even if it's a duplicate—defeating the purpose of caching!
Step 1: Build a Static Cache Dictionary
To make the dictionary reusable and only initialize once, we can create a static dictionary (either inside your Program class or a dedicated utility class). This way, it persists for the lifetime of your app and updates automatically when new SIDs are encountered.
Here's a dedicated utility class you can reuse anywhere in your project:
using System.Security.Principal; using System.Collections.Generic; public static class SidOwnerCache { // Static dictionary: only one instance exists, initialized once private static readonly Dictionary<SecurityIdentifier, NTAccount> _sidToOwnerMap = new Dictionary<SecurityIdentifier, NTAccount>(); // Get owner from cache or translate and cache if new public static NTAccount GetOwnerForSid(SecurityIdentifier sid) { // Check if we already have this SID in the cache if (_sidToOwnerMap.TryGetValue(sid, out NTAccount owner)) { return owner; } // If not, translate the SID to NTAccount and add to cache NTAccount newOwner = (NTAccount)sid.Translate(typeof(NTAccount)); _sidToOwnerMap.Add(sid, newOwner); return newOwner; } // Optional: Manually add a mapping if needed public static void AddManualMapping(SecurityIdentifier sid, NTAccount owner) { if (!_sidToOwnerMap.ContainsKey(sid)) { _sidToOwnerMap.Add(sid, owner); } } // Optional: Get all cached mappings public static IReadOnlyDictionary<SecurityIdentifier, NTAccount> GetAllMappings() { return _sidToOwnerMap.AsReadOnly(); } }
Step 2: Refactor Your Main Logic to Use the Cache
Now, update your file-traversal code to use this cache. We'll also simplify the file iteration (since you're using Alphaleonis for long paths, let's lean into that to avoid System.IO limitations) and handle potential permissions issues with try/catch blocks.
Here's the revised Main method:
using System; using System.Diagnostics; using System.IO; using System.Security.AccessControl; using System.Security.Principal; using Alphaleonis.Win32.Filesystem; namespace Get_SID_Owner_Info { internal class Program { private static void Main() { Console.Write("Please enter the Directory Path -- "); string foldr = Console.ReadLine(); Console.Write("Please enter the result path location e.g. D:\\Folder\\Outfile.csv -- "); string outfile = Console.ReadLine(); // Delete existing output file if it exists if (File.Exists(outfile)) { File.Delete(outfile); } var watch = Stopwatch.StartNew(); // Use Alphaleonis to get all files (supports long paths) using (StreamWriter sw = File.CreateText(outfile)) { sw.WriteLine("SID,Owner Name"); foreach (string filePath in Directory.EnumerateFiles(foldr, "*", SearchOption.AllDirectories)) { try { FileInfo fi = new FileInfo(filePath); FileSecurity fs = File.GetAccessControl(fi.FullName); SecurityIdentifier sid = (SecurityIdentifier)fs.GetOwner(typeof(SecurityIdentifier)); // Get owner from our cache (no redundant translation!) NTAccount owner = SidOwnerCache.GetOwnerForSid(sid); // Optional: If you want to log every file's SID/Owner, uncomment below // sw.WriteLine($"{sid},{owner}"); } catch (UnauthorizedAccessException) { // Skip files we don't have access to Console.WriteLine($"Skipping file: {filePath} (access denied)"); } catch (Exception ex) { Console.WriteLine($"Error processing {filePath}: {ex.Message}"); } } // Write all unique SID-Owner mappings from the cache to the CSV foreach (var entry in SidOwnerCache.GetAllMappings()) { sw.WriteLine($"{entry.Key},{entry.Value}"); } } watch.Stop(); Console.WriteLine($"Execution Time: {watch.ElapsedMilliseconds} ms"); Console.WriteLine($"Cached {SidOwnerCache.GetAllMappings().Count} unique SID-Owner pairs"); Console.ReadKey(); } } }
Why This Works Better
- No redundant translations: Every SID is only translated once, even if it appears in 1000 files.
- Guaranteed mapping accuracy: The dictionary directly links each SID to its correct Owner, so no mismatched indexes.
- Reusable: The
SidOwnerCacheclass can be imported and used in any other part of your project without reinitializing the dictionary. - Cleaner code: We merged your two file-traversal loops into one and added error handling to prevent crashes from inaccessible files.
Making the Dictionary Truly Independent
By putting the cache in a separate SidOwnerCache static class, you can use it anywhere in your solution—just reference the class and call SidOwnerCache.GetOwnerForSid(sid). The dictionary stays alive for the entire app session, and new mappings are added automatically when you encounter a new SID.
内容的提问来源于stack exchange,提问作者Vishwas Joshi

