![](/img/trans.png)
[英]File contains corrupted data error when opening Excel sheet with OpenXML
[英]Replacing Invalid XML characters from an excel file and writing it back to disk causes file is corrupted error on opening in MS Excel
關於問題的一些背景:
我們有一個ASP.NET MVC5應用程序,我們在其中使用FlexMonster在網格中顯示數據。 數據源是一個存儲過程,它將所有數據帶入UI網格,一旦用戶單擊“導出”按鈕,它將報表導出到Excel。 但是,在某些情況下,導出到excel失敗。 有些數據有一些無效字符,這是不可能/不可行固定源的建議在這里
到目前為止,我的方法:
EPPlus庫無法初始化工作簿,因為輸入的excel文件包含一些無效的XML字符。 我發現轉儲文件中包含一些無效字符。 我研究了可能的方法。
首先,我在excel文件中確定了有問題的字符。 我首先嘗試使用Notepad ++手動將無效字符替換為空格,然后EPPlus可以成功讀取文件。
現在,使用此處和此處其他SO線程中給出的方法,我替換了所有可能出現的無效字符。 我正在使用
XmlConvert.IsXmlChar
找出有問題的XML字符並用空格替換的方法。
我創建了一個示例程序,試圖在有問題的Excel工作表上工作。
//in main method
String readFile = File.ReadAllText(filePath);
string content = RemoveInvalidXmlChars(readFile);
File.WriteAllText(filePath, content);
//removal of invalid characters
static string RemoveInvalidXmlChars(string inputText)
{
StringBuilder withoutInvalidXmlCharsBuilder = new StringBuilder();
int firstOccurenceOfRealData = inputText.IndexOf("<t>");
int lastOccurenceOfRealData = inputText.LastIndexOf("</t>");
if (firstOccurenceOfRealData < 0 ||
lastOccurenceOfRealData < 0 ||
firstOccurenceOfRealData > lastOccurenceOfRealData)
return inputText;
withoutInvalidXmlCharsBuilder.Append(inputText.Substring(0, firstOccurenceOfRealData));
int remaining = lastOccurenceOfRealData - firstOccurenceOfRealData;
string textToCheckFor = inputText.Substring(firstOccurenceOfRealData, remaining);
foreach (char c in textToCheckFor)
{
withoutInvalidXmlCharsBuilder.Append((XmlConvert.IsXmlChar(c)) ? c : ' ');
}
withoutInvalidXmlCharsBuilder.Append(inputText.Substring(lastOccurenceOfRealData));
return withoutInvalidXmlCharsBuilder.ToString();
}
如果我使用notepad ++手動替換有問題的字符,則該文件可以在MSExcel中正常打開。 上面提到的代碼成功替換了相同的無效字符,並將內容寫回到文件中。 但是,當我嘗試使用MS Excel打開excel文件時,它拋出一個錯誤,指出該文件可能已損壞並且沒有內容顯示(下面的快照) 。 此外,以下代碼
var excelPackage = new ExcelPackage(new FileInfo(filePath));
通過記事本++更新的文件上,出現以下異常
"CRC error: the file being extracted appears to be corrupted. Expected 0x7478AABE, Actual 0xE9191E00"}
我的問題:
打開文件時顯示錯誤(沒有無效的XML字符):
首先彈出
當我點擊是
提前致謝 !
根據您的最新評論,它聽起來確實像一個二進制文件(可能是XLSX)。 要確認,請使用7zip打開由FlexMonster創建的文件。 如果打開正確,並且您在文件夾中看到一堆XML文件,則為XLSX。
在這種情況下,在二進制文件上進行搜索/替換聽起來是一個非常糟糕的主意。 它可能適用於XML部分,但也可能替代其他部分中的合法字符。 我認為更好的方法是按照@PanagiotisKanavos的建議進行操作並使用ZipArchive
。 但是您必須按照正確的順序重建它,否則Excel會抱怨。 類似於此處https://stackoverflow.com/a/33312038/1324284的操作 ,您可以執行以下操作:
public static void ReplaceXmlString(this ZipArchive xlsxZip, FileInfo outFile, string oldString, string newstring)
{
using (var outStream = outFile.Open(FileMode.Create, FileAccess.ReadWrite))
using (var copiedzip = new ZipArchive(outStream, ZipArchiveMode.Update))
{
//Go though each file in the zip one by one and copy over to the new file - entries need to be in order
foreach (var entry in xlsxZip.Entries)
{
var newentry = copiedzip.CreateEntry(entry.FullName);
var newstream = newentry.Open();
var orgstream = entry.Open();
//Copy non-xml files over
if (!entry.Name.EndsWith(".xml"))
{
orgstream.CopyTo(newstream);
}
else
{
//Load the xml document to manipulate
var xdoc = new XmlDocument();
xdoc.Load(orgstream);
var xml = xdoc.OuterXml.Replace(oldString, newstring);
xdoc = new XmlDocument();
xdoc.LoadXml(xml);
xdoc.Save(newstream);
}
orgstream.Close();
newstream.Flush();
newstream.Close();
}
}
}
像這樣使用時:
[TestMethod]
public void ReplaceXmlTest()
{
var datatable = new DataTable("tblData");
datatable.Columns.AddRange(new[]
{
new DataColumn("Col1", typeof (int)),
new DataColumn("Col2", typeof (int)),
new DataColumn("Col3", typeof (string))
});
for (var i = 0; i < 10; i++)
{
var row = datatable.NewRow();
row[0] = i;
row[1] = i * 10;
row[2] = i % 2 == 0 ? "ABCD" : "AXCD";
datatable.Rows.Add(row);
}
using (var pck = new ExcelPackage())
{
var workbook = pck.Workbook;
var worksheet = workbook.Worksheets.Add("source");
worksheet.Cells.LoadFromDataTable(datatable, true);
worksheet.Tables.Add(worksheet.Cells["A1:C11"], "Table1");
//Now similulate the copy/open of the excel file into a zip archive
using (var orginalzip = new ZipArchive(new MemoryStream(pck.GetAsByteArray()), ZipArchiveMode.Read))
{
var fi = new FileInfo(@"c:\temp\ReplaceXmlTest.xlsx");
if (fi.Exists)
fi.Delete();
orginalzip.ReplaceXmlString(fi, "AXCD", "REPLACED!!");
}
}
}
給出以下內容:
請記住,這完全是蠻力。 您可以做的所有使文件篩選器更智能的工作,而不是簡單地處理所有xml文件都是一件非常好的事情。 如果這是問題所在或工作表文件夾中的xml文件,則可以將其限制為SharedString.xml文件。 在不了解更多數據的情況下很難說。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.