2014-04-19 195 views
4

早上好, 我想从已有的excell文件中编辑一些单元格。我试过使用EPPlus和普通的OpenXml类。但是我失败了。在这两种情况下,程序不会崩溃,但总是返回旧的(未修改的)excel。请问我做错了什么?修改excel单元格

试验1 - EPPlus:

MemoryStream memoryStream = new MemoryStream(); 
using (var fs = new FileStream(@"Path\Test.xlsx", FileMode.Open, FileAccess.Read)) 
{ 
    byte[] buffer = new byte[1024]; 
    int bytesRead = 0; 
    while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0) 
    { 
     memoryStream.Write(buffer, 0, bytesRead); 
    } 
} 

using (ExcelPackage excelPackage = new ExcelPackage(memoryStream)) 
{ 
    ExcelWorkbook excelWorkBook = excelPackage.Workbook; 
    ExcelWorksheet excelWorksheet = excelWorkBook.Worksheets.First(); 
    excelWorksheet.Cells[1, 1].Value = "Test"; 
    excelWorksheet.Cells[3, 2].Value = "Test2"; 
    excelWorksheet.Cells[3, 3].Value = "Test3"; 

    excelPackage.Save(); 
} 

memoryStream.Position = 0; 
return new FileStreamResult(memoryStream, "application/xlsx") 
{ 
    FileDownloadName = "Tester.xlsx" 
}; 

我怎么说,返回旧的Excel。但在调试模式下它也包含新的值。它看起来像memoryStream不能被修改。

试验2 - 处理OpenXML类

Stream stream = System.IO.File.Open(@"Path\Test.xlsx", FileMode.Open); 
using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Open(stream, true)) 
{ 
    WorksheetPart worksheetPart = GetWorksheetPartByName(spreadSheet, "Sheet1"); 

    Cell cell = GetCell(worksheetPart.Worksheet, "C", 3); 
    cell.CellValue = new CellValue("Testos"); 
    cell.DataType = new EnumValue<CellValues>(CellValues.String); 
    worksheetPart.Worksheet.Save(); 
} 

stream.Position = 0; 

return new FileStreamResult(stream, "application/xlsx") 
{ 
    FileDownloadName = "Tester.xlsx" 
}; 

和辅助方法:

private static Row GetRow(Worksheet worksheet, uint rowIndex) 
{ 
    Row row; 
    if (worksheet.GetFirstChild<SheetData>().Elements<Row>().Where(r => r.RowIndex == rowIndex).Count() != 0) 
    { 
     row = worksheet.Elements<Row>().Where(r => r.RowIndex == rowIndex).FirstOrDefault(); 
    } 
    else 
    { 
     row = new Row() { RowIndex = rowIndex }; 
     worksheet.Append(row); 
    } 
    return row; 
} 

private static Cell GetCell(Worksheet worksheet, string columnName, uint rowIndex) 
{ 
    Row row = GetRow(worksheet, rowIndex); 

    string cellReference = columnName + rowIndex; 
    if (row.Elements<Cell>().Where(c => c.CellReference.Value == columnName + rowIndex).Count() > 0) 
    { 
     return row.Elements<Cell>().Where(c => c.CellReference.Value == cellReference).FirstOrDefault(); 
    } 
    else 
    { 
     Cell refCell = null; 
     foreach (Cell cell in row.Elements<Cell>()) 
     { 
      if (string.Compare(cell.CellReference.Value, cellReference, true) > 0) 
      { 
       refCell = cell; 
       break; 
      } 
     } 

     Cell newCell = new Cell() { CellReference = cellReference }; 
     row.InsertBefore(newCell, refCell); 

     worksheet.Save(); 
     return newCell; 
    } 
} 

private static WorksheetPart GetWorksheetPartByName(SpreadsheetDocument document, string sheetName) 
{ 
    IEnumerable<Sheet> sheets = document.WorkbookPart.Workbook.GetFirstChild<Sheets>().Elements<Sheet>().Where(s => s.Name == sheetName); 

    string relationshipId = sheets.First().Id.Value; 
    WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(relationshipId); 
    return worksheetPart; 
} 

再次感谢您的帮助。

回答

8

的问题在这两种情况下是,修改后不保存工作簿回到流:

MemoryStream ms = new MemoryStream(); 
using (FileStream fs = File.OpenRead(@"Path\Test.xlsx") 
using (ExcelPackage excelPackage = new ExcelPackage(fs)) 
{ 
    ExcelWorkbook excelWorkBook = excelPackage.Workbook; 
    ExcelWorksheet excelWorksheet = excelWorkBook.Worksheets.First(); 
    excelWorksheet.Cells[1, 1].Value = "Test"; 
    excelWorksheet.Cells[3, 2].Value = "Test2"; 
    excelWorksheet.Cells[3, 3].Value = "Test3"; 

    excelPackage.SaveAs(ms); // This is the important part. 
} 

ms.Position = 0; 
return new FileStreamResult(ms, "application/xlsx") 
{ 
    FileDownloadName = "Tester.xlsx" 
}; 
3

您可以使用Microsoft的Interop dll编辑Office文档http://msdn.microsoft.com/en-us/library/15s06t57.aspx。将“Microsoft.Office.Interop.Excel.dll”添加到您的解决方案。有了这段代码,我改变了2个单元格的值。

static void Main(string[] args) 
{ 
     Application excel = new Application(); 

     Workbook workbook = excel.Workbooks.Open(@"C:\Users\Martijn\Documents\Test.xlsx", ReadOnly: false, Editable:true); 
     Worksheet worksheet = workbook.Worksheets.Item[1] as Worksheet; 
     if (worksheet == null) 
      return; 

     Range row1 = worksheet.Rows.Cells[1, 1]; 
     Range row2 = worksheet.Rows.Cells[2, 1]; 

     row1.Value = "Test100"; 
     row2.Value = "Test200"; 


     excel.Application.ActiveWorkbook.Save(); 
     excel.Application.Quit(); 
     excel.Quit(); 
    } 

我已经开始使用Test1和Test2,在程序运行改变为适当的值之后。

Situation before running code Situation after running code

+0

它看起来非常好,它可以适用于流?由于我需要编辑本地Excel文件并将其返回下载。 (流和多路访问的可能性(更多的用户在时间)。谢谢。 – Ademar

+0

随着Interop的使用,我不认为它可能与内存流工作。建议:http://www.codeproject.com/Questions/623916/Load-excel-workbook-from-memory-stream考虑将文件写入临时文件夹,然后将其作为内存流返回给用户 –

2

我使用ClosedXML其中更新单元格的值是一个没有脑子:

var workbook = new XLWorkbook("HelloWorld.xlsx"); // load the existing excel file 
var worksheet = workbook.Worksheets.Worksheet(1); 
worksheet.Cell("A1").SetValue("Hello World!"); 
workbook.Save(); 

的NuGet包可以发现here

+0

感谢您的回答,但EPPlus也可以做到这一点。忘了说我需要有更多的用户可以打开和编辑它,它可以用流编辑并返回新版本吗? Becouse EPPlus可以使用流,但总是返回旧的excel。谢谢。 – Ademar

7

虽然这回答,我会从我的经验补充。

从FileInfo而不是Stream打开ExcelPackage比较容易,然后保存变得更简单。

FileInfo file = new FileInfo(path); 

     using (var package = new ExcelPackage(file)) 
     { 
      ExcelWorkbook workBook = package.Workbook; 
      ExcelWorksheet currentWorksheet = workBook.Worksheets.SingleOrDefault(w => w.Name == "sheet1"); 

      int totalRows = currentWorksheet.Dimension.End.Row; 
      int totalCols = currentWorksheet.Dimension.End.Column; 

      for (int i = 2; i <= totalRows; i++) 
      {     
       try 
       { 
        currentWorksheet.Cells[i, 1].Value = "AAA"; 

       } 
       catch (Exception ex) 
       { 
        _logger.Error(String.Format("Error: failed editing excel. See details: {0}", ex)); 
        return; 
       } 
      } 

      package.Save();