2 نوع پسورد میشه روی فایل های اکسل گذاشت، یکی روی شیت و ورکبوک هستش و دومی روی کل فایل، اگر نوع اول روی فایل باشه امکان مشاهده فایل و استفاده از اون بدون داشتن پسورد ممکنه ولی امکان مشاهده فرمول ها و ویرایش اون موجود نیست، اگر نوع دوم باشه کلا امکان باز کردن فایل بدون داشتن پسورد ممکن نیست.
توی این پست میخوایم باهم پسورد نوع اول رو از فایل حذف کنیم. روش های مختلفی برای این کار وجود داره مثل اجرا کردن یه اسکریپت vba یا ادیت فایل های xml که ما میخوایم از روش ادیت کردن فایل های xml پسورد رو حذف کنیم. فایل xlsx در واقع یه فایل zip هستش، اگر پسوند رو به zip تغییر بدید میتونید فایل های xml رو مشاهده کنید. ما باید فایل های workbook.xml و sheetx.xml رو ویرایش کنیم و تگ workbookProtection و sheetProtection رو حذف کنیم و دوباره محتوا رو zip کنیم و به xlsx تغییر بدیم.
یه پروژه جدید تو ویژوال استودیو ایجاد کنید.
برای اینکه نیاز هست فایل رو زیپ کنیم بعد استخراجش کنیم و دوباره زیپش کنیم ما ابتدا 4 تا متغیر تعریف میکنیم تا محل این فعالیت هارو مشخص کنه و توی کدنویسی دچار اشتباه نشیم.
private static readonly string Path = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "UnProtectTemp"); private readonly string _archivePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "UnProtectedArchives"); private readonly string _pathWorkBook = System.IO.Path.Combine(Path, @"xl\workbook.xml"); private readonly string _pathSheets = System.IO.Path.Combine(Path, @"xl\worksheets");
کارو با یه Button شروع میکنیم که قراره فایل های اکسل رو انتخاب کنه و عملیات رو شروع کنه.
اول چک میکنیم ببینیم پوشه مربوط به فایل های زیپ موجوده یا نه اگر بود که باید پاک بشه بعد به کمک OpenFileDialog فایل های اکسل رو انتخاب میکنیم امکان MultiSelect رو هم فعال میکنیم که بتونیم همزمان چندتا فایل رو انتخاب کنیم:
if (Directory.Exists(_archivePath)) { Directory.Delete(_archivePath, true); } OpenFileDialog openFileDialog = new OpenFileDialog { Multiselect = true, Filter = "Excel Files|*.xlsx" }; if (openFileDialog.ShowDialog() == true) { foreach (var file in openFileDialog.FileNames) { UnProtectExcel(file); } SaveUnProtectedExcel(); }
متد UnProtectExcel ادرس فایل اکسل رو میگیره و عملیات حذف پسورد رو انجام میده، بعد از تموم شدن حلقه و حذف پسورد تمام فایل ها، به کمک متد SaveUnProtectedExcel فایل های اصلاح شده رو به محل موردنظر کاربر منتقل میکنیم.
private void UnProtectExcel(string fileName) { if (Directory.Exists(Path)) { Directory.Delete(Path, true); } ZipFile.ExtractToDirectory(fileName, Path); UnProtect(_pathWorkBook, "workbookProtection"); UnProtectionSheets(); if (!Directory.Exists(_archivePath)) { Directory.CreateDirectory(_archivePath); } ZipFile.CreateFromDirectory(Path, System.IO.Path.Combine(_archivePath, System.IO.Path.Combine(_archivePath, System.IO.Path.GetFileName(fileName)))); }
چون قراره چندتا فایل رو مورد لطف قرار بدیم پس قبل از هرکاری مسیر عملیات رو چک میکنیم اگر فایل های قدیمی موجود بود پاک میکنیم. با ZipFile اکسل رو اکسترکت میکنیم (نیازی نیست پسوند رو تغییر بدیم خودش xlsx رو به عنوان زیپ میشناسه) با کمک متد UnProtect و دادن مسیر فایل و تگ پروتکشن پسورد رو از فایل workbook.xml حذف میکنیم. بعدش باید پسورد رو از فایل های sheetx.xml حذف کنیم که این کارو متد UnProtectionSheets انجام میده در نهایت اگر مسیر فایل های زیپ موجود نبود ایجاد میکنیم و فایل های اصلاح شده رو دوباره به کمک ZipFile بصورت زیپ درمیاریم. (باز هم نیازی نیست پسوند zip بکنیم و تغییر بدیم به xlsx، بصورت مستقیم میتونیم بصورت xlsx زیپ کنیم)
private void UnProtect(string path, string tagname) { XNamespace xn = "http://schemas.openxmlformats.org/spreadsheetml/2006/main" XDocument doc = XDocument.Load(path); var q = from node in doc.Descendants(xn + tagname) select node; q.ToList().ForEach(x => x.Remove()); doc.Save(path); }
با استفاده از LinqToXml تگ موردنظر رو داخل فایل xml جستجو میکنیم و اون رو حذف میکنیم و دوباره روی فایل ذخیره میکنیم.
private void UnProtectionSheets() { var files = Directory.EnumerateFiles(_pathSheets); foreach (var file in files) { UnProtect(file, "sheetProtection"); } }
چون ممکنه فایل اکسل بیشتر از یدونه شیت داشته باشه و هرکدومش با پسورد محافظت بشه برای همین با EnumerateFiles هرچی فایل داخل مسیر شیت ها باشه پیدا میکنیم و داخل حلقه با کمک همون متد قبلی پسوردشون رو حذف میکنیم.
و در نهایت متد اخرمون که قراره یه مسیر از کاربر بگیره و فایل های اصلاح شده رو منتقل کنه اونجا
private void SaveUnProtectedExcel() { using var fbd = new FolderBrowserDialog(); fbd.Description = "Save UnProtected Excels" fbd.UseDescriptionForTitle = true; fbd.ShowNewFolderButton = true; DialogResult result = fbd.ShowDialog(); if (result == System.Windows.Forms.DialogResult.OK && !string.IsNullOrWhiteSpace(fbd.SelectedPath)) { var files = Directory.GetFiles(_archivePath); foreach (var file in files) { File.Move(file, System.IO.Path.Combine(fbd.SelectedPath, System.IO.Path.GetFileName(file)), true); } } }
با استفاده از FolderBrowsingDialog یه مسیر از کاربر میگیریم و تمام فایل هایی که در مسیر زیپ هستن رو با File.Move به مسیر انتخابی منتقل میکنیم.