VBA 操作 Range/Cells:定位最后一行、读写区域、查找与筛选

适用场景

用 VBA 批量填公式、把明细读进数组计算、找到最后一行再追加数据、按条件筛选后复制。Range 和 Cells 是 Excel VBA 里最常用的对象,写错引用范围或依赖 ActiveSheet,宏就会在别人的电脑上操作错表。

引用单元格

Range("A1").Value = 100
Cells(1, 1).Value = 100          ' 第 1 行第 1 列,等价于 A1
Range("A1:C10").Value = 0
Range(Cells(1, 1), Cells(10, 3)).Value = 0
写法 含义
Range("A1") 单个单元格
Range("A1:C10") 连续区域
Range("A1,A3,C1:C5") 多个不连续区域
Cells(row, col) 按行列号取单元格
Rows(1) / Columns("A") 整行/整列
Range("A1").Offset(1, 0) 向下偏移一行
Range("A1").Resize(5, 2) 从 A1 扩展为 5 行 2 列
Range("A1").EntireRow A1 所在的整行
Range("A1").EntireColumn A1 所在的整列

Cells(1, 1) 的行列号从 1 开始。Cells 不写工作表前缀时指当前活动工作表,正式代码里应写成 ws.Cells(...)。

定位最后一行/列

Dim ws As Worksheet
Dim lastRow As Long
Dim lastCol As Long

Set ws = ThisWorkbook.Worksheets("数据")
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column

End(xlUp) 等价于在 A 列按 Ctrl+↑,从工作表最底部往上找第一个非空单元格。注意:

更稳的写法是先判断 A 列是否有数据:

If Application.WorksheetFunction.CountA(ws.Columns("A")) = 0 Then
    lastRow = 0
Else
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
End If

读写值

ws.Range("A1").Value = "张三"
ws.Range("B1").Value = Date
ws.Range("C1").Formula = "=A1&B1"
ws.Range("D1").NumberFormat = "yyyy-mm-dd"
ws.Range("A1").Font.Bold = True
ws.Range("A1").Interior.Color = RGB(220, 230, 241)
属性 用途 注意
.Value 值 日期、货币保留类型
.Value2 值 日期/货币按 Double 处理,速度快
.Text 显示文本 列宽不够时可能是 ###
.Formula A1 样式公式 写入公式用这个
.FormulaR1C1 R1C1 样式公式 相对引用更直观
.NumberFormat 数字格式 只影响显示

用数组批量读写

逐格读写很慢。数据量大时先读到数组,计算完再一次性写回:

Sub CalcAmount()
    Dim ws As Worksheet
    Dim lastRow As Long
    Dim data As Variant
    Dim result As Variant
    Dim i As Long

    Set ws = ThisWorkbook.Worksheets("数据")
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
    data = ws.Range("A2:B" & lastRow).Value

    ReDim result(1 To UBound(data, 1), 1 To 1)
    For i = 1 To UBound(data, 1)
        result(i, 1) = data(i, 1) * data(i, 2)
    Next i

    ws.Range("C2:C" & lastRow).Value = result
End Sub

从区域读出的数组默认是 1 基、二维的,即 data(1, 1) 对应区域左上角。

查找与筛选

Find

Dim found As Range
Set found = ws.Range("A:A").Find( _
    What:="A001", _
    LookIn:=xlValues, _
    LookAt:=xlWhole)

If Not found Is Nothing Then
    MsgBox "找到:" & found.Address
End If

Find 找不到时返回 Nothing,必须先判断再使用。LookAt:=xlWhole 是整格匹配,xlPart 是包含匹配。

AutoFilter

With ws.Range("A1:D" & lastRow)
    .AutoFilter Field:=1, Criteria1:="华东"
    .Offset(1, 0).SpecialCells(xlCellTypeVisible).Copy _
        Destination:=ThisWorkbook.Worksheets("结果").Range("A1")
    .AutoFilter
End With

Field:=1 是区域内的第一列。复制筛选结果前确认目标表有足够空间;筛选后记得关闭筛选。

易错点

相关条目

参考链接

读完自测

合上页面,先回答,再展开对照。

  1. A 列完全为空时,End(xlUp).Row 返回什么?
  2. 为什么逐格读写几万行会很慢?
  3. 删除满足条件的行时,为什么要从最后一行往前循环?
答案
  1. 返回 1,不是 0;需要先用 CountA 判断是否有数据。
  2. 每次读写单元格都要和 Excel 对象模型交互;应读入数组、批量计算、一次写回。
  3. 正序删除后下面的行会上移,循环变量继续加一就会跳过下一行;倒序删除不会影响未处理的行。
微信小程序码:扫码打开命令速查小程序

小程序版

微信扫码,随时查命令