use*_*818 3 c# asp.net excel openxml openxml-sdk
我有一个函数可以从 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;
}
Run Code Online (Sandbox Code Playgroud)
而读取功能如下:
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++;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我认为这是因为您只有一张工作表而 Excel 有三张工作表。我不确定,但我认为工作表以相反的顺序返回,因此您应该更改行:
WorksheetPart worksheetPart = workbookPart.WorksheetParts.First();
Run Code Online (Sandbox Code Playgroud)
到
WorksheetPart worksheetPart = workbookPart.WorksheetParts.Last();
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
然后您可以使用:
WorksheetPart worksheetPart = GetWorksheetPartBySheetName(workbookPart, "Sheet1");
Run Code Online (Sandbox Code Playgroud)
在查看您的代码时,我还注意到了一些您可能(或可能不感兴趣!)感兴趣的其他事情:
在您的代码中,您只是在阅读 ,InnerXml所以这对您来说可能无关紧要,但 Excel 存储字符串的方式与您编写字符串的方式不同,因此读取 Excel 生成的文件可能不会为您提供您期望的值。在您的示例中,您将字符串直接写入单元格,如下所示:

但 Excel 使用 SharedStrings 概念,其中所有字符串都写入一个名为 sharedStrings.xml 的单独 XML 文件。该文件包含 Excel 文件中使用的字符串和引用,并且该值存储在表单 XML 的单元格值中。
sharedString.xml 看起来像这样:

然后 Cell 看起来像这样:

的47在<v>元件是第47共享字符串的引用。请注意,t生成的 XML中的类型(属性)是,str但 Excel 生成的文件中的类型是s. 这表示您的是内联字符串,而他们的是共享字符串。
您可以像阅读任何其他部分一样阅读 SharedStrings:
var stringTable = workbookPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
if (stringTable != null)
{
sharedString = stringTable.SharedStringTable.ElementAt(int.Parse(value)).InnerText;
}
Run Code Online (Sandbox Code Playgroud)
其次,如果您查看代码生成的单元格引用和 Excel 生成的单元格引用,您会发现您只输出列而不是行(例如,您输出A而不是A1)。要解决此问题,您应该更改该行:
CellReference = Convert.ToString(Convert.ToChar(65 + colIndex)),
Run Code Online (Sandbox Code Playgroud)
到
CellReference = Convert.ToString(Convert.ToChar(65 + colIndex) + rowIndex.ToString()),
Run Code Online (Sandbox Code Playgroud)
我希望这有帮助。
| 归档时间: |
|
| 查看次数: |
6776 次 |
| 最近记录: |