如何在Excel中计算具有数据的行数?

49

列 A 的数据如下(即经常有空单元格):

HEADING  <-- this is A1
kfdsl
fdjgnm
fdkj

gdfkj
4353

fdjk  <-- this is A9

我希望能够获取具有数据的最后一个单元格的引用。因此,在上面的示例中,我想返回:A9

我已经尝试过这个方法,但它在第一个空单元格处停止(即返回 A4

numofrows = destsheet.Range("A2").End(xlDown).Row - 1

Dim lastRow As Long Dim ws As WorksheetSet ws = Application.ActiveSheet With ws If WorksheetFunction.CountA(Cells) > 0 Then lastRow = Cells.Find(what:="*", SearchOrder:=xlByRows, _ SearchDirection:=xlPrevious).Row End If End With - Ronnie Royston
10个回答

49
我喜欢这种方式:

ActiveSheet.UsedRange.Rows.Count

同样可以用于列数。 对我来说总是有效的。但是,如果您在另一列中有数据,则上面的代码也会将它们考虑在内,因为该代码正在查找工作表中的所有单元格范围。


17
如果第一行没有数据,这会导致计算出错误的答案 - 它会给出从第一个单元格到最后一个单元格的行数。如果a2:a4单元格中有数据,这个公式将结果为“3”,而不是“4”(使用Office 2010)。 - Floris
6
这种方法可能存在危险,因为它可以返回一个带有颜色但无数据的单元格,甚至可能是一个包含数据但未被正确清理的单元格。 - lcrmorin
5
这个答案是错误的,应该删除。.UsedRange.Rows.Count返回的是UsedRange中行数的数量,而不是最后一条数据的行号。所以如果你的第1行和第2行为空,这将会导致结果偏差了2个单位。 - Jean-François Corbett
如果您想获取使用范围中的最后一行,请正确操作--请参见newguy的答案。阅读sancho.s的答案以了解它返回的内容,如果您需要一个具有数据(而不是一些剩余格式)和/或在特定列中的行,请参见我的解决方案 - Nickolay

43

最安全的选择是

Lastrow =  Cells.Find("*", [A1], , , xlByRows, xlPrevious).Row
Lastcol =  Cells.Find("*", [A1], , , xlByColumns, xlPrevious).Column

不要使用UsedRangeSpecialCells(xlLastCell)或者End(xlUp)。如果您之前删除了一些行,所有这些方法可能会给出错误的结果。Excel仍会计算这些隐藏的单元格。

如果您删除单元格、保存工作簿、关闭并重新打开它,这些方法将再次起作用。


4
+1 进行了一些测试,似乎这是最可靠的方法,特别是当您不知道最后一行中数据所在的列时。 - Graham Anderson
4
这是找到最后一个包含数据的单元格的唯一安全方法。其他方法无法处理隐藏行/列或仅具有格式但没有数据或已被删除的单元格。 - Charles Williams
应该在一个范围内使用Set,并测试该范围是否存在。这里假定表格中存在数据——在空表格上将失败。 - brettdj
所以如果我理解正确的话,我可以使用“lastrow”变量来设置第一行,从而开始粘贴新数据。"Lastrow = Cells.Find("*", [A1], , , xlByRows, xlPrevious).Row"例如:"rnum = Lastrow +1"(这将是工作表中第一个空单元格) - haakonlu

26

这将适用于Excel的所有版本(2003、2007、2010)。其中第一个工作表有65536行,而后两个工作表有约一百万行。 Sheet1.Rows.Count 返回依赖于Excel版本的行数。

numofrows = Sheet1.Range("A1").Offset(Sheet1.Rows.Count - 1, 0).End(xlUp).Row

或者等效但更短的

numofrows = Sheet1.Cells(Sheet1.Rows.Count,1).End(xlUp)

这个代码从A列底部开始查找第一个非空单元格,并获取其行号。

如果你的数据在其他列中继续向下延伸,这个代码同样适用。例如,如果你在示例数据中的FY4763单元格中写入一些内容,以上代码仍会正确返回9(而使用UsedRange属性的任何方法都会错误地返回4763)。

请注意,如果你需要单元格引用,你只需要直接使用以下代码。你不必先获取行号,然后再构建单元格引用。

Set rngLastCell = Sheet1.Range("A1").Offset(Sheet1.Rows.Count - 1, 0).End(xlUp)

请注意,这种方法在某些边缘情况下会失败:

  • 最后一行包含数据
  • 最后一行(或多行)被隐藏或筛选掉

因此,如果您计划在第1,048,576行使用这些内容,请小心!


1
这对我起作用了,而 ActiveSheet.UsedRange.Rows.Count 失败了(这通常是我使用的)。 - thornomad
你在上面优秀回答里漏掉了.Row。这个缺失的语句可能会让新用户感到困惑。numofrows = Sheet1.Cells(Sheet1.Rows.Count,1).End(xlUp)这个代码段将提供最后一个非空单元格的值。如果在末尾加上.Row,则Sheet1.Cells(Sheet1.Rows.Count, 1).End(xlUp).Row将提供第一列中最后一个单元格的行号,这正是预期的结果。 - equalizer

19
我将所有可能性与一张长测试表进行了比较:

对于以下操作,所需时间为0.140625秒:

lastrow = calcws.Cells.Find("*", [A1], , , xlByColumns, xlPrevious).row

0秒完成

iLastRow = calcws.Cells(rows.count, "a").End(xlUp).row

并且

numofrows = calcws.Cells.SpecialCells(xlLastCell).row

0.0078125 秒

lastrow = calcws.UsedRange.rows.count
Do While 1
    If calcws.Cells(lastrow, 1).Value = "" Then
        lastrow = lastrow - 1
    Else
        Exit Do
    End If
Loop

我认为最喜欢的是显而易见的...


1
+1 - 这是我最喜欢的答案。并不站队,只是展示一些选项及其相对效率。应该有更多的赞! - Floris
8
@Floris:你认为速度是评判各种可能性应该成为首选的最重要标准吗?而不是可靠性表现如何?(因为它们在所有情况下并不总是返回相同的结果…) 你认为以速度作为判断各种可能性哪个更值得推荐的最重要标准,比起其可靠性表现如何更为重要吗? (因为它们在所有情况下并不一定都能得到相同的结果...) - Jean-François Corbett
@jeanfrancoiscorbett - 显然,得到正确的答案最重要。我是在评论这个答案的公正性 - 一个客观比较速度。我喜欢这一点,这也是我在我的回答中试图表达的。我可以看到很多事情可能会出错(例如当最后一行有一个值时...) - Floris
3
我没有看到其他代码的编译,作为答案,特别是那些暗示时间(对于未指定的测试)比实际答案的可靠性更重要的代码。最后,numofrows = calcws.Cells.SpecialCells(xlLastCell).row适用于工作表,而不是A列。 - brettdj
性能比较虽有用,但所有更快的方法在某些情况下返回不正确结果的事实却并非如此。特别是,第4个代码片段错误地假定calcws.UsedRange.rows.count是最后一行,但如果表格的前几行为空,则该假设不成立。 - Nickolay

6

Dim RowNumber As Integer
RowNumber = ActiveSheet.Range("A65536").End(xlUp).Row

在你的情况下,它应该返回 #9。


1
+1 ,对于 Excel 2007 及以后的版本,请使用 range("A" & activesheet.rows.count).end(xlup).row :) - Our Man in Bananas

5

在另一个网站上发现了这种方法。它适用于新的更大尺寸的Excel,而且不需要您硬编码最大行数和列数。

iLastRow = Cells(Rows.Count, "a").End(xlUp).Row
iLastCol = Cells(i, Columns.Count).End(xlToLeft).Column

感谢澳大利亚墨尔本的mudraker


3
这两种方法同样适用,让Excel定义它最后看到数据的时间。
numofrows = destsheet.UsedRange.SpecialCells(xlLastCell).row

numofrows = destsheet.Cells.SpecialCells(xlLastCell).row

4
这有几个问题。您的第一个建议,.UsedRange.Rows.count,将返回 UsedRange 中的行数,这与最后一条数据的行号不同。因此,如果第1和第2行为空,则会导致答案错误 2 行。此外,这包括整张工作表中最后一个非空单元格,而不仅是所研究的列。也许这就是 OP 想要的,但我认为不是;此外,如果有人意外在单元格 "FY54239" 中写入了内容,那么它很容易出错。 - Jean-François Corbett
你的第二个建议,destsheet.SpecialCells(xlLastCell).row甚至在Excel 2003中都无法编译通过:.SpecialCells不适用于Sheet对象。 - Jean-François Corbett
1
@Jean... 实际上是 destsheet.Cells.SpecialCells(xlLastCell).Row ... 这是我的疏忽,没有包含它。对于你的第一个观点,.SpecialCells(xlLastCell).Row 也可以应用于 UsedRange。我已经编辑了我的回复,并提供了可行的代码。 - Hari Seldon

2
  n = ThisWorkbook.Worksheets(1).Range("A:A").Cells.SpecialCells(xlCellTypeConstants).Count

1

我更喜欢使用CurrentRegion属性,它相当于Ctrl-*,可以将当前范围扩展到具有数据的最大连续范围。您可以从一个已知包含数据的单元格或范围开始,然后进行扩展。UsedRange属性有时会返回巨大的区域,只是因为某人在工作表底部进行了一些格式设置。

Dim Liste As Worksheet    
Set Liste = wb.Worksheets("B Leistungen (Liste)")     
Dim longlastrow As Long
longlastrow = Liste.Range(Liste.Cells(4, 1), Liste.Cells(6, 3)).CurrentRegion.Rows.Count

2
这对于原始问题不起作用,因为数据并不全部连续。 - Charles Williams
1
Charles,你说得很对。在所示的情况下,我的方法确实会失败。 - Andrew Magerman

1
为了更清晰,我想添加一个明确的示例和运行。
            openFileDialog1.FileName = "Select File"; 
            openFileDialog1.DefaultExt = ".xls"; 
            openFileDialog1.Filter = "Excel documents (.xls)|*.xls"; 


            DialogResult result = openFileDialog1.ShowDialog();


            if (result==DialogResult.OK)
            {

                string filename = openFileDialog1.FileName;


                Excel.Application xlApp;
                Excel.Workbook xlWorkBook;
                Excel.Worksheet xlWorkSheet;
                object misValue = System.Reflection.Missing.Value;

                xlApp = new Excel.Application();
                xlApp.Visible = false;
                xlApp.DisplayAlerts = false;



                xlWorkBook = xlApp.Workbooks.Open(filename, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);

                xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);

                var numRows = xlWorkSheet.Range["A1"].Offset[xlWorkSheet.Rows.Count - 1, 0].End[Excel.XlDirection.xlUp].Row;

                MessageBox.Show("Number of max row is : "+ numRows.ToString());

                xlWorkBook.Close(true, misValue, misValue);
                xlApp.Quit();

            }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接