在C#中检测指定路径下各类文件的密码保护状态并统计加密数量
Hey there! Let's break down how to solve your two C# tasks—detecting password-protected files individually, and counting them across a specified path for .sdf, .sdb, and other formats. Since there's no universal "magic bullet" (different file types use entirely distinct encryption mechanisms), we'll build targeted logic for each format and wrap it all together into a cohesive solution.
We'll handle common file types you care about, starting with .sdf/.sdb, then covering Office files (since you mentioned existing solutions here), and even add a framework to extend to other formats later.
SQL Server Compact Files (.sdf, .sdb)
For these database files, we can leverage SqlCeConnection to attempt a connection with an empty password. If it throws a specific exception, we know the file is password-protected.
using System.Data.SqlServerCe; using System.IO; public bool IsSdfPasswordProtected(string filePath) { if (!File.Exists(filePath)) throw new FileNotFoundException("Target file doesn't exist.", filePath); try { // Try connecting with an empty password using var conn = new SqlCeConnection($"Data Source={filePath};Password="); conn.Open(); // If we can open it, no password protection exists return false; } catch (SqlCeException ex) { // Native error 28559 = file requires a password or provided password is wrong if (ex.NativeError == 28559) return true; // Re-throw other exceptions (like corrupted files) for proper handling throw; } }
Office Files (.doc, .xls, .docx, .xlsx)
Modern OpenXML Formats (.docx/.xlsx)
Use the official DocumentFormat.OpenXml NuGet package to attempt opening the file without credentials:
using DocumentFormat.OpenXml.Packaging; public bool IsOpenXmlPasswordProtected(string filePath) { try { using var doc = WordprocessingDocument.Open(filePath, false); return false; } catch (OpenXmlPackageException ex) { // Check if the exception mentions a password requirement return ex.Message.Contains("password", StringComparison.OrdinalIgnoreCase); } }
Legacy Office Formats (.doc/.xls)
You can use Microsoft Interop (note: requires Office installed) or third-party libraries like NPOI. Here's the Interop approach:
using Microsoft.Office.Interop.Word; using System.Runtime.InteropServices; public bool IsOldWordPasswordProtected(string filePath) { var wordApp = new Application(); try { // Attempt to open with an empty password wordApp.Documents.Open(filePath, PasswordDocument: ""); return false; } catch (COMException ex) { // Error code -2147467259 = file requires a password if (ex.ErrorCode == -2147467259) return true; throw; } finally { // Clean up COM object to avoid lingering processes wordApp.Quit(SaveChanges: false); Marshal.ReleaseComObject(wordApp); } }
Unified Detection Wrapper
Create a single method that routes to the correct detector based on file extension:
using System.IO; public bool IsFilePasswordProtected(string filePath) { var extension = Path.GetExtension(filePath).ToLowerInvariant(); return extension switch { ".sdf" or ".sdb" => IsSdfPasswordProtected(filePath), ".docx" => IsOpenXmlPasswordProtected(filePath), ".doc" => IsOldWordPasswordProtected(filePath), // Add more formats here (e.g., .pdf with iTextSharp, .zip with System.IO.Compression) _ => throw new NotSupportedException($"File type {extension} isn't supported yet."), }; }
Now let's build a method to scan a directory (and subdirectories) for target file types and count how many are password-protected:
using System.IO; public int CountPasswordProtectedFiles(string rootPath, params string[] targetExtensions) { int protectedFileCount = 0; foreach (var ext in targetExtensions) { // Get all files matching the extension, including subdirectories var matchingFiles = Directory.GetFiles(rootPath, $"*{ext}", SearchOption.AllDirectories); foreach (var file in matchingFiles) { try { if (IsFilePasswordProtected(file)) { protectedFileCount++; } } catch (Exception ex) { // Log errors (e.g., corrupted files, permission issues) instead of failing silently Console.WriteLine($"Failed to check {file}: {ex.Message}"); } } } return protectedFileCount; }
Usage Example
// Count password-protected .sdf and .sdb files in the D:\Data directory int protectedCount = CountPasswordProtectedFiles(@"D:\Data", ".sdf", ".sdb"); Console.WriteLine($"Total password-protected files found: {protectedCount}");
- NuGet Dependencies: You'll need to install packages like
Microsoft.SqlServer.Compact,DocumentFormat.OpenXml, oriTextSharp(for PDF support) via NuGet. - Exception Handling: Extend the error handling to fit your use case—log to a file, notify users, or skip problematic files without stopping the entire scan.
- Performance: For large directory structures, consider converting the batch method to use async/await to avoid blocking the main thread.
内容的提问来源于stack exchange,提问作者karthikraja

