Yah*_*ufi 29 c# vb.net excel ssis etl
我试图使用Interop Library从excel文件中删除所有额外的空白行和列.
我按照这个问题使用Interop从Excel文件中删除空行和列的最快方法,我发现它很有帮助.
但我有excel文件包含一小组数据,但有很多空行和列(从最后一个非空行(或列)到工作表的末尾)
我尝试在Rows和Columns上循环,但是循环需要几个小时.
我试图得到最后一个非空的行和列索引,所以我可以删除一行中的整个空范围
XlWks.Range("...").EntireRow.Delete(xlShiftUp)
Run Code Online (Sandbox Code Playgroud)
注意:我正在尝试获取包含数据的最后一行以删除所有额外的空格(在此行或列之后)
有什么建议?
Had*_*adi 12
如果你的目标是使用c#导入excel数据,假设你已经确定了工作表中使用率最高的索引(在你发布的图像中是Col = 10,Row = 16),你可以将最大使用的索引转换为字母所以它将J16
使用和仅选择使用的范围OLEDBCommand
SELECT * FROM [Sheet1$A1:J16]
Run Code Online (Sandbox Code Playgroud)
否则,我认为找到更快的方法并不容易.
您可以参考这些文章将索引转换为字母表并使用OLEDB连接到excel:
正如你所说,你从以下问题开始:
并且您正在尝试"获取包含数据的最后一行以删除所有额外的空格(在此行或列之后)"
因此,假设您正在使用接受答案(由@JohnG提供),因此您可以添加一些代码行以获取最后使用的行和列
空行存储在整数列表中 rowsToDelete
您可以使用以下代码获取索引小于最后一个空行的最后一个非空行
List<int> NonEmptyRows = Enumerable.Range(1, rowsToDelete.Max()).ToList().Except(rowsToDelete).ToList();
Run Code Online (Sandbox Code Playgroud)
如果NonEmptyRows.Max() < rowsToDelete.Max()
最后一个非空行是NonEmptyRows.Max()
Else,那么worksheet.Rows.Count
在最后一次使用之后没有空行.
获取最后一个非空列可以做同样的事情
代码编辑DeleteCols
和DeleteRows
功能:
private static void DeleteRows(List<int> rowsToDelete, Microsoft.Office.Interop.Excel.Worksheet worksheet)
{
// the rows are sorted high to low - so index's wont shift
List<int> NonEmptyRows = Enumerable.Range(1, rowsToDelete.Max()).ToList().Except(rowsToDelete).ToList();
if (NonEmptyRows.Max() < rowsToDelete.Max())
{
// there are empty rows after the last non empty row
Microsoft.Office.Interop.Excel.Range cell1 = worksheet.Cells[NonEmptyRows.Max() + 1,1];
Microsoft.Office.Interop.Excel.Range cell2 = worksheet.Cells[rowsToDelete.Max(), 1];
//Delete all empty rows after the last used row
worksheet.Range[cell1, cell2].EntireRow.Delete(Microsoft.Office.Interop.Excel.XlDeleteShiftDirection.xlShiftUp);
} //else last non empty row = worksheet.Rows.Count
foreach (int rowIndex in rowsToDelete.Where(x => x < NonEmptyRows.Max()))
{
worksheet.Rows[rowIndex].Delete();
}
}
private static void DeleteCols(List<int> colsToDelete, Microsoft.Office.Interop.Excel.Worksheet worksheet)
{
// the cols are sorted high to low - so index's wont shift
//Get non Empty Cols
List<int> NonEmptyCols = Enumerable.Range(1, colsToDelete.Max()).ToList().Except(colsToDelete).ToList();
if (NonEmptyCols.Max() < colsToDelete.Max())
{
// there are empty rows after the last non empty row
Microsoft.Office.Interop.Excel.Range cell1 = worksheet.Cells[1,NonEmptyCols.Max() + 1];
Microsoft.Office.Interop.Excel.Range cell2 = worksheet.Cells[1,NonEmptyCols.Max()];
//Delete all empty rows after the last used row
worksheet.Range[cell1, cell2].EntireColumn.Delete(Microsoft.Office.Interop.Excel.XlDeleteShiftDirection.xlShiftToLeft);
} //else last non empty column = worksheet.Columns.Count
foreach (int colIndex in colsToDelete.Where(x => x < NonEmptyCols.Max()))
{
worksheet.Columns[colIndex].Delete();
}
}
Run Code Online (Sandbox Code Playgroud)
几年前,我创建了一个MSDN代码示例,允许开发人员从工作表中获取最后使用的行和列.我对其进行了修改,将所有需要的代码放入带有Windows窗体前端的类库中以演示操作.
基础代码使用Microsoft.Office.Interop.Excel.
微软一个驱动器上的位置 https://1drv.ms/u/s!AtGAgKKpqdWjiEGdBzWDCSCZAMaM
在这里,我获得Excel文件中的第一个工作表,获取最后使用的行和col并显示为有效的单元格地址.
Private Sub cmdAddress1_Click(sender As Object, e As EventArgs) Handles cmdAddress1.Click
Dim ops As New GetExcelColumnLastRowInformation
Dim info = New UsedInformation
ExcelInformationData = info.UsedInformation(FileName, ops.GetSheets(FileName))
Dim SheetName As String = ExcelInformationData.FirstOrDefault.SheetName
Dim cellAddress = (
From item In ExcelInformationData
Where item.SheetName = ExcelInformationData.FirstOrDefault.SheetName
Select item.LastCell).FirstOrDefault
MessageBox.Show($"{SheetName} - {cellAddress}")
End Sub
Run Code Online (Sandbox Code Playgroud)
在演示项目中,我还获得了excel文件的所有工作表,将它们显示在ListBox中.从列表框中选择工作表名称,并获取该工作表在有效单元格地址中的最后一行和列.
Private Sub cmdAddress_Click(sender As Object, e As EventArgs) Handles cmdAddress.Click
Dim cellAddress =
(
From item In ExcelInformationData
Where item.SheetName = ListBox1.Text
Select item.LastCell).FirstOrDefault
If cellAddress IsNot Nothing Then
MessageBox.Show($"{ListBox1.Text} {cellAddress}")
End If
End Sub
Run Code Online (Sandbox Code Playgroud)
乍一看从上面的链接打开解决方案时,您会注意到有很多代码.代码是最佳的,将立即释放所有对象.
我正在使用ClosedXml,它具有有用的'LastUsedRow'和'LastUsedColumn'方法.
var wb = new XLWorkbook(@"<path>\test.xlsx", XLEventTracking.Disabled);
var sheet = wb.Worksheet("Sheet1");
for (int i = sheet.LastRowUsed().RowNumber() - 1; i >= 1; i--)
{
var row = sheet.Row(i);
if (row.IsEmpty())
{
row.Delete();
}
}
wb.Save();
Run Code Online (Sandbox Code Playgroud)
这个简单的循环在38秒内删除了10000行中的5000行.不快,但比'小时'好很多.这取决于你当然要处理多少行/列,当然你没有说.但是,在进一步测试50000中的25000个空行后,大约需要30分钟来删除循环中的空行.清楚地删除行不是一个有效的过程.
更好的解决方案是创建一个新工作表,然后复制要保留的行.
第1步 - 创建包含50000行和20列的工作表,每隔一行和每列都为空.
var wb = new XLWorkbook(@"C:\Users\passp\Documents\test.xlsx");
var sheet = wb.Worksheet("Sheet1");
sheet.Clear();
for (int i = 1; i < 50000; i+=2)
{
var row = sheet.Row(i);
for (int j = 1; j < 20; j += 2)
{
row.Cell(j).Value = i * j;
}
}
Run Code Online (Sandbox Code Playgroud)
第2步 - 将包含数据的行复制到新工作表.这需要10秒钟.
var wb = new XLWorkbook(@"C:\Users\passp\Documents\test.xlsx", XLEventTracking.Disabled);
var sheet = wb.Worksheet("Sheet1");
var sheet2 = wb.Worksheet("Sheet2");
sheet2.Clear();
sheet.RowsUsed()
.Where(r => !r.IsEmpty())
.Select((r, index) => new { Row = r, Index = index + 1} )
.ForEach(r =>
{
var newRow = sheet2.Row(r.Index);
r.Row.CopyTo(newRow);
}
);
wb.Save();
Run Code Online (Sandbox Code Playgroud)
第3步 - 这将是对列进行相同的操作.
Find
可以使用Excel函数.见GetLastIndexOfNonEmptyCell
.CountA
是用来确定该电池是空的和联合的全部行/列到一个行/列的范围内.public void Yahfoufi(string excelFile)
{
var exapp = new Microsoft.Office.Interop.Excel.Application {Visible = true};
var wrb = exapp.Workbooks.Open(excelFile);
var sh = wrb.Sheets["Sheet1"];
var lastRow = GetLastIndexOfNonEmptyCell(exapp, sh, XlSearchOrder.xlByRows);
var lastCol = GetLastIndexOfNonEmptyCell(exapp, sh, XlSearchOrder.xlByColumns);
var target = sh.Range[sh.Range["A1"], sh.Cells[lastRow, lastCol]];
Range deleteRows = GetEmptyRows(exapp, target);
Range deleteColumns = GetEmptyColumns(exapp, target);
deleteColumns?.Delete();
deleteRows?.Delete();
}
private static int GetLastIndexOfNonEmptyCell(
Microsoft.Office.Interop.Excel.Application app,
Worksheet sheet,
XlSearchOrder searchOrder)
{
Range rng = sheet.Cells.Find(
What: "*",
After: sheet.Range["A1"],
LookIn: XlFindLookIn.xlFormulas,
LookAt: XlLookAt.xlPart,
SearchOrder: searchOrder,
SearchDirection: XlSearchDirection.xlPrevious,
MatchCase: false);
if (rng == null)
return 1;
return searchOrder == XlSearchOrder.xlByRows
? rng.Row
: rng.Column;
}
private static Range GetEmptyRows(
Microsoft.Office.Interop.Excel.Application app,
Range target)
{
Range result = null;
foreach (Range r in target.Rows)
{
if (app.WorksheetFunction.CountA(r.Cells) >= 1)
continue;
result = result == null
? r.EntireRow
: app.Union(result, r.EntireRow);
}
return result;
}
private static Range GetEmptyColumns(
Microsoft.Office.Interop.Excel.Application app,
Range target)
{
Range result = null;
foreach (Range c in target.Columns)
{
if (app.WorksheetFunction.CountA(c.Cells) >= 1)
continue;
result = result == null
? c.EntireColumn
: app.Union(result, c.EntireColumn);
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
获取空行范围的行/列的两个函数可以重构为一个函数,如下所示:
private static Range GetEntireEmptyRowsOrColumns(
Microsoft.Office.Interop.Excel.Application app,
Range target,
Func<Range, Range> rowsOrColumns,
Func<Range, Range> entireRowOrColumn)
{
Range result = null;
foreach (Range c in rowsOrColumns(target))
{
if (app.WorksheetFunction.CountA(c.Cells) >= 1)
continue;
result = result == null
? entireRowOrColumn(c)
: app.Union(result, entireRowOrColumn(c));
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
然后打电话给它:
Range deleteColumns = GetEntireEmptyRowsOrColumns(exapp, target, (Func<Range, Range>)(r1 => r1.Columns), (Func<Range, Range>)(r2 => r2.EntireColumn));
Range deleteRows = GetEntireEmptyRowsOrColumns(exapp, target, (Func<Range, Range>)(r1 => r1.Rows), (Func<Range, Range>)(r2 => r2.EntireRow));
deleteColumns?.Delete();
deleteRows?.Delete();
Run Code Online (Sandbox Code Playgroud)
注意:有关更多信息,请查看此SO问题.
编辑
尝试简单地清除最后使用过的单元格之后的所有单元格的内容.
public void Yahfoufi(string excelFile)
{
var exapp = new Microsoft.Office.Interop.Excel.Application {Visible = true};
var wrb = exapp.Workbooks.Open(excelFile);
var sh = wrb.Sheets["Sheet1"];
var lastRow = GetLastIndexOfNonEmptyCell(exapp, sh, XlSearchOrder.xlByRows);
var lastCol = GetLastIndexOfNonEmptyCell(exapp, sh, XlSearchOrder.xlByColumns);
// Clear the columns
sh.Range(sh.Cells(1, lastCol + 1), sh.Cells(1, Columns.Count)).EntireColumn.Clear();
// Clear the remaining cells
sh.Range(sh.Cells(lastRow + 1, 1), sh.Cells(Rows.Count, lastCol)).Clear();
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4501 次 |
最近记录: |