使用Open XML SDK建立xlsx檔案卻出現內容必須修正的原因:AutoSave

  • 1424
  • 0

使用Open XML SDK建立xlsx檔案卻出現內容必須修正的原因:AutoSave

問題情境:

使用Open XML SDK 2.5的SpreadsheetDocument.Create()建立xlsx檔案之後,企圖使用Excel 2013開啟,卻出現錯誤訊息。

 

問題描述:

使用Excel 2013開啟的錯誤訊息如下圖:

image

 

點選Yes進行修復之後的錯誤訊息如下圖:

image

 

依據前述的錯誤訊息,檢視位於使用者資料夾之下的AppData\Local\Temp\的Log檔,內容如下:



<recoveryLog xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
	<logFileName>error081200_01.xml</logFileName>
	<summary>Errors were detected in file 'C:\Users\Kyle\Documents\Test\Test.xlsx'</summary>
	<removedParts summary="Following is a list of removed parts:">
		<removedPart>Replaced Part: /xl/worksheets/sheet.xml part with XML error. A document must contain exactly one root element. Line 1, column 0.</removedPart>
	</removedParts>
</recoveryLog>

 

使用Open XML SDK 2.5 Productivity Tool開啟xlsx檔案的錯誤訊息如下圖:

image

 

將Test.xlsx更名為Test.xlsx.zip之後再解壓縮,發現sheet.xml檔案內容完全空白。

 

產生問題的原因:

下列程式碼的第三個參數將AutoSave設為false,所以系統不會自動為程式設計師產生的WorkSheet呼叫Save。

 

解決問題的方法:

方法一:

程式設計師必須一一為每一個產生的WorkSheet呼叫Save,否則將會出現前述錯誤。


WorksheetPart worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet(new SheetData());
worksheetPart.Worksheet.Save();

方法二:

不要變更AutoSave的預設值。(自Open XML SDK 2.0開始支援AutoSave的預設值)[1]

補充說明:

1、buffer是在記憶體中的資料,可以不必透過OS直接存取以提高存取速度。
(A buffer is a block of bytes in memory used to cache data, thereby reducing the number of calls to the operating system. Buffers improve read and write performance. A buffer can be used for either reading or writing, but never both simultaneously.)[2]

2、stream是一組byte[]的資料。
(A stream is an abstraction of a sequence of bytes, such as a file, an input/output device, an inter-process communication pipe, or a TCP/IP socket.)[3]

3、flush method將buffer的資料清出至目的地。
(Override Flush on streams that implement a buffer. Use this method to move any information from an underlying buffer to its destination, clear the buffer, or both.)[4]

4、WorkSheet的Save方法將buffer的資料寫入WorkSheetPart。
(Saves the data in the DOM tree back to the part. It could be called multiple times as well. Each time it is called, the stream will be flushed.)[5]

 

範例程式碼[6]:


{

    CreateSpreadsheetWorkbook(@"C:\Users\Kyle\My Documents\Test\Test.xlsx");
}

public static void CreateSpreadsheetWorkbook(string filepath)
{
    // Create a spreadsheet document by supplying the filepath.
    // By default, AutoSave = true, Editable = true, and Type = xlsx.
    //SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(filepath, SpreadsheetDocumentType.Workbook);
    SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(filepath, SpreadsheetDocumentType.Workbook, false);

    // Add a WorkbookPart to the document.
    WorkbookPart workbookpart = spreadsheetDocument.AddWorkbookPart();
    workbookpart.Workbook = new Workbook();

    // Add a WorksheetPart to the WorkbookPart.
    WorksheetPart worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
    worksheetPart.Worksheet = new Worksheet(new SheetData());
    worksheetPart.Worksheet.Save();

    // Add Sheets to the Workbook.
    Sheets sheets = spreadsheetDocument.WorkbookPart.Workbook.AppendChild<Sheets>(new Sheets());

    // Append a new worksheet and associate it with the workbook.
    Sheet sheet = new Sheet() { Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart), SheetId = 1, Name = "mySheet" };
    sheets.Append(sheet);

    workbookpart.Workbook.Save();

    // Close the document.
    spreadsheetDocument.Close();
}

 

資料來源:

[1]Improvements Made to the Final Open XML SDK 2.0 compared to the December 2009 CTP
http://blogs.msdn.com/b/brian_jones/archive/2010/05/03/improvements-made-to-the-final-open-xml-sdk-2-0-compared-to-the-december-2009-ctp.aspx

[2]BufferedStream Class
https://msdn.microsoft.com/en-us/library/system.io.bufferedstream(v=vs.110).aspx

[3]Stream Class
https://msdn.microsoft.com/en-us/library/system.io.stream(v=vs.110).aspx

[4]Stream.Flush Method
https://msdn.microsoft.com/en-us/library/system.io.stream.flush(v=vs.110).aspx

[5]Worksheet.Save Method
https://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.worksheet.save(v=office.14).aspx

[6]Structure of a SpreadsheetML document (Open XML SDK)
https://msdn.microsoft.com/en-us/library/office/gg278316.aspx