在不丢失格式的情况下编辑现有 excel 个文件 ASP.Net
Edit existing excel files ASP.Net without losing formatting
我有一种情况需要使用 Excel 模板并插入值,然后允许用户下载更新的文件。我使用 ClosedXML 完成了此操作,但由于它使用 xlsx 的非本机格式,因此在打开下载的文档时出现格式错误,并且保存的文档实例丢失了模板中的所有格式。
我需要一个输出 xlsx 文档的解决方案,该文档是原始模板、格式和所有内容的副本,以及附加的插入值。如果需要,我可以在服务器上临时复制一份模板。
是否有我可以用于此目的的工具?
我最终使用了 OpenXML。我在这个项目中使用 VB.Net,因为我在 VB 中发现的示例代码很少(主要是 java 或 c#),我将附上它以便它可以用作参考。
关于它的真正好处是您从中得到的文档没有任何验证错误或任何东西,并且所有 sheet 格式(文本对齐、字体等)仍然存在。
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
Dim path = Server.MapPath("~/ExcelTemplates/rfi.xlsx")
Dim templateBytes As Byte() = System.IO.File.ReadAllBytes(path)
Using templateStream As MemoryStream = New MemoryStream
templateStream.Write(templateBytes, 0, templateBytes.Length)
Using sheetInstance As SpreadsheetDocument = SpreadsheetDocument.Open(templateStream, True)
Dim worksheetPart As WorksheetPart = GetWorksheetPartByName(sheetInstance, "Sheet1")
If worksheetPart IsNot Nothing Then
'this writes "Test!!!" to cell C7
'Dim cell As Cell = GetCell(worksheetPart.Worksheet, "C", 7)
'cell.CellValue = New CellValue("Test!!!")
'another way of doing it
GetCell(worksheetPart.Worksheet, "C", 7).CellValue = New CellValue("Test12")
'this next line would change the cell's contents data type
'cell.DataType = New EnumValue(Of CellValues)(CellValues.String)
worksheetPart.Worksheet.Save()
templateStream.Position = 0
Using ms As MemoryStream = New MemoryStream
templateStream.CopyTo(ms)
Response.Buffer = True
Response.Clear()
Response.ContentType = "application/vnd.ms-excel"
Response.AppendHeader("Content-Disposition", "filename=RFI.xlsx")
ms.WriteTo(Response.OutputStream)
Response.End()
End Using
End If
End Using
End Using
End Sub
Private Shared Function GetWorksheetPartByName(ByVal document As SpreadsheetDocument, ByVal sheetName As String) As WorksheetPart
Dim sheets As IEnumerable(Of Sheet) = document.WorkbookPart.Workbook.GetFirstChild(Of Sheets)().Elements(Of Sheet)().Where(Function(s) s.Name = sheetName)
If sheets.Count() = 0 Then
Return Nothing
End If
Dim relationshipId As String = sheets.First().Id.Value
Dim worksheetPart As WorksheetPart = CType(document.WorkbookPart.GetPartById(relationshipId), WorksheetPart)
Return worksheetPart
End Function
Private Shared Function GetCell(ByVal worksheet As Worksheet, ByVal columnName As String, ByVal rowIndex As UInteger) As Cell
Dim row As Row = GetRow(worksheet, rowIndex)
If row Is Nothing Then Return Nothing
Return row.Elements(Of Cell)().Where(Function(c) String.Compare(c.CellReference.Value, columnName & rowIndex, True) = 0).First()
End Function
Private Shared Function GetRow(ByVal worksheet As Worksheet, ByVal rowIndex As UInteger) As Row
Return worksheet.GetFirstChild(Of SheetData)().Elements(Of Row)().Where(Function(r) CType(r.RowIndex, UInteger) = rowIndex).First()
End Function
我有一种情况需要使用 Excel 模板并插入值,然后允许用户下载更新的文件。我使用 ClosedXML 完成了此操作,但由于它使用 xlsx 的非本机格式,因此在打开下载的文档时出现格式错误,并且保存的文档实例丢失了模板中的所有格式。
我需要一个输出 xlsx 文档的解决方案,该文档是原始模板、格式和所有内容的副本,以及附加的插入值。如果需要,我可以在服务器上临时复制一份模板。
是否有我可以用于此目的的工具?
我最终使用了 OpenXML。我在这个项目中使用 VB.Net,因为我在 VB 中发现的示例代码很少(主要是 java 或 c#),我将附上它以便它可以用作参考。
关于它的真正好处是您从中得到的文档没有任何验证错误或任何东西,并且所有 sheet 格式(文本对齐、字体等)仍然存在。
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
Dim path = Server.MapPath("~/ExcelTemplates/rfi.xlsx")
Dim templateBytes As Byte() = System.IO.File.ReadAllBytes(path)
Using templateStream As MemoryStream = New MemoryStream
templateStream.Write(templateBytes, 0, templateBytes.Length)
Using sheetInstance As SpreadsheetDocument = SpreadsheetDocument.Open(templateStream, True)
Dim worksheetPart As WorksheetPart = GetWorksheetPartByName(sheetInstance, "Sheet1")
If worksheetPart IsNot Nothing Then
'this writes "Test!!!" to cell C7
'Dim cell As Cell = GetCell(worksheetPart.Worksheet, "C", 7)
'cell.CellValue = New CellValue("Test!!!")
'another way of doing it
GetCell(worksheetPart.Worksheet, "C", 7).CellValue = New CellValue("Test12")
'this next line would change the cell's contents data type
'cell.DataType = New EnumValue(Of CellValues)(CellValues.String)
worksheetPart.Worksheet.Save()
templateStream.Position = 0
Using ms As MemoryStream = New MemoryStream
templateStream.CopyTo(ms)
Response.Buffer = True
Response.Clear()
Response.ContentType = "application/vnd.ms-excel"
Response.AppendHeader("Content-Disposition", "filename=RFI.xlsx")
ms.WriteTo(Response.OutputStream)
Response.End()
End Using
End If
End Using
End Using
End Sub
Private Shared Function GetWorksheetPartByName(ByVal document As SpreadsheetDocument, ByVal sheetName As String) As WorksheetPart
Dim sheets As IEnumerable(Of Sheet) = document.WorkbookPart.Workbook.GetFirstChild(Of Sheets)().Elements(Of Sheet)().Where(Function(s) s.Name = sheetName)
If sheets.Count() = 0 Then
Return Nothing
End If
Dim relationshipId As String = sheets.First().Id.Value
Dim worksheetPart As WorksheetPart = CType(document.WorkbookPart.GetPartById(relationshipId), WorksheetPart)
Return worksheetPart
End Function
Private Shared Function GetCell(ByVal worksheet As Worksheet, ByVal columnName As String, ByVal rowIndex As UInteger) As Cell
Dim row As Row = GetRow(worksheet, rowIndex)
If row Is Nothing Then Return Nothing
Return row.Elements(Of Cell)().Where(Function(c) String.Compare(c.CellReference.Value, columnName & rowIndex, True) = 0).First()
End Function
Private Shared Function GetRow(ByVal worksheet As Worksheet, ByVal rowIndex As UInteger) As Row
Return worksheet.GetFirstChild(Of SheetData)().Elements(Of Row)().Where(Function(r) CType(r.RowIndex, UInteger) = rowIndex).First()
End Function