使用 OpenXML 使用目录文件填充 excel sheet 列
Populate an excel sheet column with directory files using OpenXML
我有一个 excel 工作簿,其中包含两个工作 Sheet,"Tourist Information" 和 "Documents"。在 "Documents" sheet 中,我必须用目录中找到的所有文件名填充 "Scanned Document" 列。除了 Scanned Document 列之外,我不必填写任何其他列。我无法用从单元格引用 C3 开始的文件名填充 excel sheet。你能帮我用文件名填充该列吗?
"Documents" Sheet 是:
我的代码是:
//Open the Excel file in Read Mode using OpenXML
using (SpreadsheetDocument doc = SpreadsheetDocument.Open(@"C:\TouristRecord.xlsx", true))
{
WorksheetPart documents = GetWorksheetPart(doc.WorkbookPart, "Documents");
Worksheet documentsWorksheet = documents.Worksheet;
IEnumerable<Row> documentsRows = documentsWorksheet.GetFirstChild<SheetData>().Descendants<Row>();
//Loop through the Worksheet rows
foreach (var files in Directory.GetFiles(@"C:\DocumentsFolder"))
{
foreach (Row row in documentsRows)
{
// I am unable to write logic to update the excel sheet value here.
}
}
doc.Save();
}
而GetWorksheet部分方法是:
public WorksheetPart GetWorksheetPart(WorkbookPart workbookPart, string sheetName)
{
string relId = workbookPart.Workbook.Descendants<Sheet>().First(s => sheetName.Equals(s.Name)).Id;
return (WorksheetPart)workbookPart.GetPartById(relId);
}
要将单元格添加到 C3,您需要创建一个新的 Cell
对象,为其分配 C3 的单元格引用,设置其值,然后将其添加到代表行的 Row
3 上 sheet。我们可以将该逻辑包装到这样的方法中:
private void AddCellToRow(Row row, string value, string cellReference)
{
//the cell might already exist, if it does we should use it.
Cell cell = row.Descendants<Cell>().FirstOrDefault(c => c.CellReference == cellReference);
if (cell == null)
{
cell = new Cell();
cell.CellReference = cellReference;
}
cell.CellValue = new CellValue(value);
cell.DataType = CellValues.String;
row.Append(cell);
}
如果我们假设当前工作sheet 有一组连续的行,那么写入内容的逻辑就非常简单:
- 迭代文档中的每一行
- 检查行索引是否大于2(因为你想从3开始写)。如果是:
- 获取第 3 个
Cell
或如果不存在则创建它。
- 将文件列表的第 n 个元素添加到
Cell
。
- 递增n
- 迭代文件列表中的剩余文件(因为文件可能多于原始文档中的行)。为每一个:
- 添加一个新的
Row
- 将新的
Cell
添加到 Row
并将文件名作为单元格的值。
将其放入您最终得到的代码中:
using (SpreadsheetDocument doc = SpreadsheetDocument.Open(@"C:\TouristRecord.xlsx", true))
{
WorksheetPart documents = GetWorksheetPart(doc.WorkbookPart, "Documents");
//get the she sheetdata as that's where we need to add rows
SheetData sheetData = documents.Worksheet.GetFirstChild<SheetData>();
IEnumerable<Row> documentsRows = sheetData.Descendants<Row>();
//get all of the files into an array
var filenames = Directory.GetFiles(@"C:\DocumentsFolder");
if (filenames.Length > 0)
{
int currentFileIndex = 0;
// keep the row index in case the rowindex property is null anywhere
// the spec allows for it to be null, in which case the row
// index is one more than the previous row (or 1 if this is the first row)
uint currentRowIndex = 1;
foreach (var documentRow in documentsRows)
{
if (documentRow.RowIndex.HasValue)
{
currentRowIndex = documentRow.RowIndex.Value;
}
else
{
currentRowIndex++;
}
if (currentRowIndex <= 2)
{
//this is row 1 or 2 so we can ignore it
continue;
}
AddCellToRow(documentRow, filenames[currentFileIndex], "C" + currentRowIndex);
currentFileIndex++;
if (filenames.Length <= currentFileIndex)
{
// there are no more files so we can stop
break;
}
}
// now output any files we haven't already output. These will need a new row as there isn't one
// in the document as yet.
for (int i = currentFileIndex; i < filenames.Length; i++)
{
//there are more files than there were rows in the directory, add more rows
Row row = new Row();
currentRowIndex++;
row.RowIndex = currentRowIndex;
AddCellToRow(row, filenames[i], "C" + currentRowIndex);
sheetData.Append(row);
}
}
}
上面假设当前工作sheet 有一组连续的行。这可能并不总是正确的,因为规范允许不将空行写入 XML。在这种情况下,您最终可能会在输出中出现空白。假设原始文件的第 1、2 和 5 行有数据;在那种情况下,foreach 会导致您跳过写入第 3 行和第 4 行。这可以通过检查循环内的 currentRowIndex
并为可能出现的任何间隙添加新的 Row
来解决。我没有添加该代码,因为它很复杂,有损于答案的基本原理。
我有一个 excel 工作簿,其中包含两个工作 Sheet,"Tourist Information" 和 "Documents"。在 "Documents" sheet 中,我必须用目录中找到的所有文件名填充 "Scanned Document" 列。除了 Scanned Document 列之外,我不必填写任何其他列。我无法用从单元格引用 C3 开始的文件名填充 excel sheet。你能帮我用文件名填充该列吗?
"Documents" Sheet 是:
我的代码是:
//Open the Excel file in Read Mode using OpenXML
using (SpreadsheetDocument doc = SpreadsheetDocument.Open(@"C:\TouristRecord.xlsx", true))
{
WorksheetPart documents = GetWorksheetPart(doc.WorkbookPart, "Documents");
Worksheet documentsWorksheet = documents.Worksheet;
IEnumerable<Row> documentsRows = documentsWorksheet.GetFirstChild<SheetData>().Descendants<Row>();
//Loop through the Worksheet rows
foreach (var files in Directory.GetFiles(@"C:\DocumentsFolder"))
{
foreach (Row row in documentsRows)
{
// I am unable to write logic to update the excel sheet value here.
}
}
doc.Save();
}
而GetWorksheet部分方法是:
public WorksheetPart GetWorksheetPart(WorkbookPart workbookPart, string sheetName)
{
string relId = workbookPart.Workbook.Descendants<Sheet>().First(s => sheetName.Equals(s.Name)).Id;
return (WorksheetPart)workbookPart.GetPartById(relId);
}
要将单元格添加到 C3,您需要创建一个新的 Cell
对象,为其分配 C3 的单元格引用,设置其值,然后将其添加到代表行的 Row
3 上 sheet。我们可以将该逻辑包装到这样的方法中:
private void AddCellToRow(Row row, string value, string cellReference)
{
//the cell might already exist, if it does we should use it.
Cell cell = row.Descendants<Cell>().FirstOrDefault(c => c.CellReference == cellReference);
if (cell == null)
{
cell = new Cell();
cell.CellReference = cellReference;
}
cell.CellValue = new CellValue(value);
cell.DataType = CellValues.String;
row.Append(cell);
}
如果我们假设当前工作sheet 有一组连续的行,那么写入内容的逻辑就非常简单:
- 迭代文档中的每一行
- 检查行索引是否大于2(因为你想从3开始写)。如果是:
- 获取第 3 个
Cell
或如果不存在则创建它。 - 将文件列表的第 n 个元素添加到
Cell
。 - 递增n
- 获取第 3 个
- 迭代文件列表中的剩余文件(因为文件可能多于原始文档中的行)。为每一个:
- 添加一个新的
Row
- 将新的
Cell
添加到Row
并将文件名作为单元格的值。
- 添加一个新的
将其放入您最终得到的代码中:
using (SpreadsheetDocument doc = SpreadsheetDocument.Open(@"C:\TouristRecord.xlsx", true))
{
WorksheetPart documents = GetWorksheetPart(doc.WorkbookPart, "Documents");
//get the she sheetdata as that's where we need to add rows
SheetData sheetData = documents.Worksheet.GetFirstChild<SheetData>();
IEnumerable<Row> documentsRows = sheetData.Descendants<Row>();
//get all of the files into an array
var filenames = Directory.GetFiles(@"C:\DocumentsFolder");
if (filenames.Length > 0)
{
int currentFileIndex = 0;
// keep the row index in case the rowindex property is null anywhere
// the spec allows for it to be null, in which case the row
// index is one more than the previous row (or 1 if this is the first row)
uint currentRowIndex = 1;
foreach (var documentRow in documentsRows)
{
if (documentRow.RowIndex.HasValue)
{
currentRowIndex = documentRow.RowIndex.Value;
}
else
{
currentRowIndex++;
}
if (currentRowIndex <= 2)
{
//this is row 1 or 2 so we can ignore it
continue;
}
AddCellToRow(documentRow, filenames[currentFileIndex], "C" + currentRowIndex);
currentFileIndex++;
if (filenames.Length <= currentFileIndex)
{
// there are no more files so we can stop
break;
}
}
// now output any files we haven't already output. These will need a new row as there isn't one
// in the document as yet.
for (int i = currentFileIndex; i < filenames.Length; i++)
{
//there are more files than there were rows in the directory, add more rows
Row row = new Row();
currentRowIndex++;
row.RowIndex = currentRowIndex;
AddCellToRow(row, filenames[i], "C" + currentRowIndex);
sheetData.Append(row);
}
}
}
上面假设当前工作sheet 有一组连续的行。这可能并不总是正确的,因为规范允许不将空行写入 XML。在这种情况下,您最终可能会在输出中出现空白。假设原始文件的第 1、2 和 5 行有数据;在那种情况下,foreach 会导致您跳过写入第 3 行和第 4 行。这可以通过检查循环内的 currentRowIndex
并为可能出现的任何间隙添加新的 Row
来解决。我没有添加该代码,因为它很复杂,有损于答案的基本原理。