我有一个从 excel 文件读取并将结果存储在 DataSet
中的函数。我有另一个写入 excel 文件的函数。当我尝试从一个常规的人工生成的 excel 文件中读取时,excel 读取函数返回一个空白 DataSet
,但是当我从写入函数生成的 excel 文件中读取时,它工作得很好。该函数将无法处理常规生成的 excel 文件,即使我只是复制并粘贴函数生成的 excel 文件的内容也是如此。我终于找到了它,但我不知道从这里去哪里。我的代码有问题吗?
这里是excel生成函数:
public static Boolean writeToExcel(string fileName, DataSet data)
{
Boolean answer = false;
using (SpreadsheetDocument excelDoc = SpreadsheetDocument.Create(tempPath + fileName, SpreadsheetDocumentType.Workbook))
{
WorkbookPart workbookPart = excelDoc.AddWorkbookPart();
workbookPart.Workbook = new Workbook();
WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
Sheets sheets = excelDoc.WorkbookPart.Workbook.AppendChild<Sheets>(new Sheets());
Sheet sheet = new Sheet()
{
Id = excelDoc.WorkbookPart.GetIdOfPart(worksheetPart),
SheetId = 1,
Name = "Page1"
};
sheets.Append(sheet);
CreateWorkSheet(worksheetPart, data);
answer = true;
}
return answer;
}
private static void CreateWorkSheet(WorksheetPart worksheetPart, DataSet data)
{
Worksheet worksheet = new Worksheet();
SheetData sheetData = new SheetData();
UInt32Value currRowIndex = 1U;
int colIndex = 0;
Row excelRow;
DataTable table = data.Tables[0];
for (int rowIndex = -1; rowIndex < table.Rows.Count; rowIndex++)
{
excelRow = new Row();
excelRow.RowIndex = currRowIndex++;
for (colIndex = 0; colIndex < table.Columns.Count; colIndex++)
{
Cell cell = new Cell()
{
CellReference = Convert.ToString(Convert.ToChar(65 + colIndex)),
DataType = CellValues.String
};
CellValue cellValue = new CellValue();
if (rowIndex == -1)
{
cellValue.Text = table.Columns[colIndex].ColumnName.ToString();
}
else
{
cellValue.Text = (table.Rows[rowIndex].ItemArray[colIndex].ToString() != "") ? table.Rows[rowIndex].ItemArray[colIndex].ToString() : "*";
}
cell.Append(cellValue);
excelRow.Append(cell);
}
sheetData.Append(excelRow);
}
SheetFormatProperties formattingProps = new SheetFormatProperties()
{
DefaultColumnWidth = 20D,
DefaultRowHeight = 20D
};
worksheet.Append(formattingProps);
worksheet.Append(sheetData);
worksheetPart.Worksheet = worksheet;
}
而阅读功能如下:
public static void readInventoryExcel(string fileName, ref DataSet set)
{
using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Open(fileName, false))
{
WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart;
WorksheetPart worksheetPart = workbookPart.WorksheetParts.First();
SheetData sheetData = worksheetPart.Worksheet.Elements<SheetData>().First();
int count = -1;
foreach (Row r in sheetData.Elements<Row>())
{
if (count >= 0)
{
DataRow row = set.Tables[0].NewRow();
row["SerialNumber"] = r.ChildElements[1].InnerXml;
row["PartNumber"] = r.ChildElements[2].InnerXml;
row["EntryDate"] = r.ChildElements[3].InnerXml;
row["RetirementDate"] = r.ChildElements[4].InnerXml;
row["ReasonForReplacement"] = r.ChildElements[5].InnerXml;
row["RetirementTech"] = r.ChildElements[6].InnerXml;
row["IncludeInMaintenance"] = r.ChildElements[7].InnerXml;
row["MaintenanceTech"] = r.ChildElements[8].InnerXml;
row["Comment"] = r.ChildElements[9].InnerXml;
row["Station"] = r.ChildElements[10].InnerXml;
row["LocationStatus"] = r.ChildElements[11].InnerXml;
row["AssetName"] = r.ChildElements[12].InnerXml;
row["InventoryType"] = r.ChildElements[13].InnerXml;
row["Description"] = r.ChildElements[14].InnerXml;
set.Tables[0].Rows.Add(row);
}
count++;
}
}
}
最佳答案
我认为这是因为您只有一张工作表而 Excel 有三张。我不确定,但我认为这些表以相反的顺序返回,因此您应该更改行:
WorksheetPart worksheetPart = workbookPart.WorksheetParts.First();
到
WorksheetPart worksheetPart = workbookPart.WorksheetParts.Last();
搜索 WorksheetPart
可能更安全如果您可以通过工作表名称识别它。你需要找到 Sheet
首先然后使用它的 ID 找到 SheetPart
:
private WorksheetPart GetWorksheetPartBySheetName(WorkbookPart workbookPart, string sheetName)
{
//find the sheet first.
IEnumerable<Sheet> sheets = workbookPart.Workbook.GetFirstChild<Sheets>().Elements<Sheet>().Where(s => s.Name == sheetName);
if (sheets.Count() > 0)
{
string relationshipId = sheets.First().Id.Value;
WorksheetPart worksheetPart = (WorksheetPart)workbookPart.GetPartById(relationshipId);
return worksheetPart;
}
return null;
}
然后您可以使用:
WorksheetPart worksheetPart = GetWorksheetPartBySheetName(workbookPart, "Sheet1");
在查看您的代码时,我注意到了一些您可能(或可能不!)感兴趣的其他事情:
在您的代码中,您只阅读了 InnerXml
所以这对你来说可能无关紧要,但 Excel 存储字符串的方式与你编写它们的方式不同,因此读取 Excel 生成的文件可能不会给你你期望的值。在您的示例中,您将字符串直接写入单元格,如下所示:
但 Excel 使用 SharedStrings 概念,其中所有字符串都写入一个名为 sharedStrings.xml 的单独 XML 文件。该文件包含 Excel 文件中使用的字符串和引用, 值存储在工作表 XML 的单元格值中。
sharedString.xml 看起来像这样:
然后 Cell 看起来像这样:
47
在<v>
元素是对第 47 个共享字符串的引用。请注意,生成的 XML 中的类型(t
属性)是 str
但 Excel 生成文件中的类型是 s
.这表示您的是内联字符串,而他们的是共享字符串。
您可以像阅读任何其他部分一样阅读 SharedStrings:
var stringTable = workbookPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
if (stringTable != null)
{
sharedString = stringTable.SharedStringTable.ElementAt(int.Parse(value)).InnerText;
}
其次,如果您查看代码生成的单元格引用和 Excel 生成的单元格引用,您会发现您只输出列而不输出行(例如,您输出 A
而不是 A1
)。要解决此问题,您应该更改行:
CellReference = Convert.ToString(Convert.ToChar(65 + colIndex)),
到
CellReference = Convert.ToString(Convert.ToChar(65 + colIndex) + rowIndex.ToString()),
希望对您有所帮助。
关于c# - 使用 OpenXML sdk 读取 excel 文件时遇到问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25165637/