如何使用Open XML SDK在新副本中移除只读限制
问题
在使用Open XML SDK转换Excel文件时,遇到两类报错:
- 文件存在只读密码保护(无密码可破解)
- 文件处于共享状态(已被其他网络用户打开,需对方关闭后才能编辑)
使用Excel Interop时,可以通过设置参数打开文件副本并启用写入权限,从而继续程序化转换流程,以下是借助IgnoreReadOnlyRecommended实现该行为的代码:
// 使用Microsoft Office Interop Excel将旧版Excel文件转换为.xlsx Transitional格式 public bool Convert_Legacy_ExcelInterop(string input_filepath, string output_filepath) { bool convert_success = false; // 打开Excel应用 Excel.Application app = new Excel.Application(); // 创建Excel实例 app.DisplayAlerts = false; // 不显示任何Excel提示框 Excel.Workbook wb = app.Workbooks.Open(input_filepath, ReadOnly: false, Password: "'", WriteResPassword: "'", IgnoreReadOnlyRecommended: true, Notify: false); // 创建工作簿实例 // 将工作簿另存为.xlsx Transitional格式并关闭Excel wb.SaveAs(output_filepath, 51); wb.Close(); app.Quit(); return convert_success = true; }
请问如何使用Open XML SDK实现相同的行为?以下是我的现有代码:
// 转换为.xlsx Transitional格式 public bool Convert_to_OOXML_Transitional(string input_filepath, string output_filepath) { bool convert_success = false; // 检测文件是否被写保护或被其他用户占用 using (SpreadsheetDocument spreadsheet = SpreadsheetDocument.Open(input_filepath, false)) { if (spreadsheet.WorkbookPart.Workbook.WorkbookProtection != null || spreadsheet.WorkbookPart.Workbook.FileSharing != null) { // 使用Excel Interop转换文件 Convert_Legacy_ExcelInterop(input_filepath, output_filepath); return convert_success = true; // 请用Open XML SDK原生代码替换上述逻辑 } } // 转换文件 byte[] byteArray = File.ReadAllBytes(input_filepath); using (MemoryStream stream = new MemoryStream()) { stream.Write(byteArray, 0, (int)byteArray.Length); using (SpreadsheetDocument spreadsheet = SpreadsheetDocument.Open(stream, true)) { spreadsheet.ChangeDocumentType(SpreadsheetDocumentType.Workbook); } File.WriteAllBytes(output_filepath, stream.ToArray()); } // 修复文件 Repair rep = new Repair(); rep.Repair_OOXML(output_filepath); // 返回成功状态 convert_success = true; return convert_success; }
解决方案
首先明确:Open XML SDK是直接操作Excel文件底层OOXML格式的工具,它没有Excel Interop那样与系统文件锁交互的能力,也无法绕过加密的密码保护(加密文件内容为密文,SDK无解密能力)。针对两类场景的处理方式如下:
1. 只读密码保护(无密码)
如果文件是加密型只读保护(需要密码才能打开),Open XML SDK无法直接读取或转换——因为加密后的文件内容无法解析,这种场景仍需依赖Excel Interop处理,或提示用户提供密码。
如果只是Excel层面的只读推荐(仅提示建议只读打开,无需密码),Open XML SDK可直接读取文件,因为这种保护并未加密文件内容。
2. 文件处于共享/被其他用户打开状态
对于文件被其他用户锁定的情况,可先创建原文件的本地临时副本,再对副本执行Open XML SDK的转换操作——原文件被系统锁定,但副本不受锁限制。
修改后的代码示例
将原有代码中调用Interop的逻辑替换为副本处理逻辑:
// 转换为.xlsx Transitional格式 public bool Convert_to_OOXML_Transitional(string input_filepath, string output_filepath) { bool convert_success = false; string tempCopyPath = Path.Combine(Path.GetTempPath(), $"temp_{Path.GetFileName(input_filepath)}"); try { bool useCopy = false; // 检测文件状态或捕获锁定异常 try { using (SpreadsheetDocument spreadsheet = SpreadsheetDocument.Open(input_filepath, false)) { if (spreadsheet.WorkbookPart.Workbook.WorkbookProtection != null || spreadsheet.WorkbookPart.Workbook.FileSharing != null) { useCopy = true; } } } catch (IOException) { // 文件被其他用户锁定,启用副本处理 useCopy = true; } if (useCopy) { // 创建原文件的临时副本 File.Copy(input_filepath, tempCopyPath, true); // 对副本执行转换逻辑 byte[] byteArray = File.ReadAllBytes(tempCopyPath); using (MemoryStream stream = new MemoryStream()) { stream.Write(byteArray, 0, (int)byteArray.Length); using (SpreadsheetDocument spreadsheet = SpreadsheetDocument.Open(stream, true)) { spreadsheet.ChangeDocumentType(SpreadsheetDocumentType.Workbook); } File.WriteAllBytes(output_filepath, stream.ToArray()); } // 修复转换后的文件 Repair rep = new Repair(); rep.Repair_OOXML(output_filepath); convert_success = true; } else { // 原文件可正常操作,执行原有转换逻辑 byte[] byteArray = File.ReadAllBytes(input_filepath); using (MemoryStream stream = new MemoryStream()) { stream.Write(byteArray, 0, (int)byteArray.Length); using (SpreadsheetDocument spreadsheet = SpreadsheetDocument.Open(stream, true)) { spreadsheet.ChangeDocumentType(SpreadsheetDocumentType.Workbook); } File.WriteAllBytes(output_filepath, stream.ToArray()); } Repair rep = new Repair(); rep.Repair_OOXML(output_filepath); convert_success = true; } } finally { // 清理临时副本 if (File.Exists(tempCopyPath)) { File.Delete(tempCopyPath); } } return convert_success; }
逻辑说明
- 增加
IOException捕获:当文件被其他用户锁定时,自动触发副本处理流程。 - 临时副本存储在系统临时目录,转换完成后自动清理,避免残留文件。
- 对于加密型密码保护文件,上述逻辑仍无法处理,需保留Excel Interop的调用分支作为 fallback。
内容的提问来源于stack exchange,提问作者Asbjoedt
相关产品推荐
相关产品推荐

