达永编程网

程序员技术分享与交流平台

Excel常用技能分享与探讨(5-宏与VBA简介 VBA的文件操作三)

一、从电脑管家理解文件操作

文件管家模型

  • 文件柜(Folder) → 文件夹与子文件夹
  • 文件袋(File) → 各类文档
  • 标签机(FileSystemObject) → 核心操作对象
  • 操作手册 → VBA代码指令集

在VBA(Visual Basic for Applications)中,使用文件系统对象(FSO, FileSystemObject)是处理文件和文件夹的标准方式。无论是创建文件夹还是文件,使用FSO对象都是一个常见的做法,因为它提供了丰富的属性和方法来实现这些操作。

创建文件夹

要使用FSO创建文件夹,你需要首先创建一个FileSystemObject的实例,然后使用该实例的CreateFolder方法。

创建文件

创建文件(此处的文件是指文件文件.Txt)同样需要FileSystemObject,但使用CreateTextFile方法。

注意事项

  1. 引用FileSystemObject:在使用FSO之前,确保你的VBA项目已经引用了Microsoft Scripting Runtime库。在VBA编辑器中,可以通过“工具”->“引用”来添加。
  2. 路径和权限:确保你有权限在指定的路径上创建文件夹或文件。如果路径不存在,FSO将自动创建必要的上级目录。
  3. 错误处理:在实际应用中,考虑到各种可能的错误(如权限问题、路径无效等),建议添加适当的错误处理机制,例如使用On Error GoTo语句。

面两章是使用FSO对象处理文件及文件夹的方法,以下是关于使用传统方法处理文件及文件夹的一些操作。


二、什么是“传统方法”?

在 VBA 中,“传统方法”指的是 无需依赖外部库,直接使用 VBA 内置的语句和函数(如 Open、Close、Kill、MkDir 等)进行文件操作的方式。这些方法源于早期的 BASIC 语言,特点是语法简洁但功能较为基础。

核心语句和函数:

  • Open:打开文件(支持多种模式)
  • Close:关闭文件
  • Print # / Write #:写入数据
  • Input / Line Input:读取数据
  • Kill:删除文件
  • MkDir / RmDir:创建/删除文件夹
  • FileCopy:复制文件
  • Name:重命名文件或移动文件

三、传统方法与 FSO 的对比

3.1. 语法区别

操作

传统方法

FileSystemObject (FSO)

创建文件

Open "路径" For Output As #1

fso.CreateTextFile("路径")

写入文件

Print #1, "内容"

ts.WriteLine "内容"

读取文件

Line Input #1, text

ts.ReadAll

删除文件

Kill "路径"

fso.DeleteFile "路径"

检查文件存在

If Dir("路径") <> "" Then

fso.FileExists("路径")

创建文件夹

MkDir "路径"

fso.CreateFolder("路径")

删除文件夹

RmDir "路径"(仅限空文件夹)

fso.DeleteFolder "路径", True(强制删除)

3.2. 功能区别

特性

传统方法

FSO

面向对象

无,基于语句和函数

支持对象模型(如 File、Folder 对象)

路径兼容性

需手动处理路径分隔符(\)

自动处理路径分隔符

错误处理

需手动检查文件存在性

提供 FileExists、FolderExists 方法

非空文件夹删除

不支持

支持强制删除(DeleteFolder 的第二个参数)

性能

适合小文件操作

适合批量操作和大文件处理

3.3. 使用场景

  • 选择传统方法:适合简单、轻量级的文件操作(如快速读写小文件),无需添加外部引用。
    • 轻量级任务(如快速读写小文件)。
    • 无需处理复杂文件夹结构。
    • 兼容性要求高(避免依赖外部库)。
  • 选择 FSO:适合复杂操作(如递归遍历文件夹、操作文件属性、处理大文件),需要更现代的 API 和面向对象支持。
    • 需要递归遍历文件夹树。
    • 操作文件属性(如修改时间、大小)。
    • 处理非空文件夹删除。

四、传统方法的核心语法详解

4.1. Open 语句

Open 文件路径 For 模式 As [#]文件号
Open pathname For mode [Access access] [lock] As [#]filenumber [Len=reclength]
  • 参数说明
    • pathname:文件路径(支持绝对路径和相对路径)。
    • mode:打开模式(详见下表)。
    • access:访问权限(Read、Write、Read Write)。
    • lock:文件锁定(Shared、Lock Read、Lock Write、Lock Read Write)。
    • filenumber:文件号(1~511 的整数,唯一标识文件句柄)。
    • reclength:记录长度(仅 Random 模式需要)。
  • 模式

模式(mode)

描述

Input

只读模式打开文本文件(文件必须存在)。

Output

覆盖写入模式,若文件不存在则创建。

Append

追加写入模式,保留原内容,写入到文件末尾。

Binary

二进制模式,可读写任意字节数据(如图片、视频等)。

Random

随机访问模式,需定义固定长度记录(Len=reclength)。


  • 文件号

1. 文件号的作用

  • 唯一标识符:每个打开的文件通过文件号(1~511)进行引用。
  • 资源管理:未关闭的文件号可能导致内存泄漏或文件锁定。
Open "C:\Test.txt" For Output As #1 ' 打开文件并分配文件号1

2. 文件号的最佳实践

  • 显式关闭:操作完成后立即使用 Close #1。
  • 动态分配:可用 FreeFile 函数自动获取未使用的文件号:
Dim fileNo As Integer
fileNo = FreeFile()
Open "C:\Test.txt" For Output As #fileNo
Close #fileNo示例:

4.2. 文件号的作用

  • 文件号是 VBA 用于跟踪已打开文件的句柄。
  • 必须唯一:同一文件号不能重复使用,否则会引发错误。
  • 自动释放:程序结束时,未关闭的文件号会被自动释放,但显式使用 Close #文件号 更安全。

4.3. 写入数据

  • Print #:按原始格式写入,不添加引号或分隔符。
Print #1, "Hello", 123 ' 输出:Hello 123
  • Write #:自动添加引号和逗号,适合生成结构化数据(如 CSV)。
Write #1, "Hello", 123  ' 输出:"Hello",123

4.4. 读取数据

  • Line Input:逐行读取文本,忽略换行符。
Line Input #1, textLine ' 读取一行到变量 textLine

示例

Dim lineText As String
Open "C:\Data\file.txt" For Input As #1
Do Until EOF(1)
    Line Input #1, lineText
    Debug.Print lineText
Loop
Close #1
  • Input:按字段读取(需明确数据格式)。
Input #1, var1, var2     ' 读取逗号分隔的数据到变量

4.5. Close 语句
关闭已打开的文件:

Close [#filenumber]  ' 关闭指定文件号,省略则关闭所有打开的文件

4.6. 文件管理函数

4.6.1. Kill 语句
删除文件(不可恢复):

Kill 文件路径  ' 支持通配符(如 "*.tmp")

4.6.2. FileCopy 语句
复制文件:

FileCopy source, destination  ' 文件必须未打开

4.6.3. Name 语句
重命名或移动文件:

Name oldPath As newPath  ' 可实现移动文件到新路径

4.7. 文件夹操作

4.7.1 MkDir 语句
创建文件夹:

MkDir path  ' 如路径不存在会报错,需先创建父文件夹

参数说明:

  • path(必需): 要创建的文件夹路径,可以是绝对路径(如 "C:\Test\NewFolder")或相对路径(如 "..\Data")。

注意事项:

  • 路径层级必须存在: 若父文件夹不存在(如 C:\Test 不存在时创建 C:\Test\NewFolder),会触发错误 76: Path not found。
  • 路径分隔符: 使用反斜杠 \(需手动处理,VBA 不会自动转换 /)。
  • 重复创建: 若文件夹已存在,会触发错误 75: Path/File access error。

4.7.2. RmDir 语句
删除空文件夹:

RmDir path  ' 仅能删除空文件夹

参数说明:

  • path(必需): 要删除的空文件夹路径。

限制与错误:

  • 只能删除空文件夹: 若文件夹非空,触发错误 75: Path/File access error。
  • 路径不存在: 若路径无效,触发错误 76: Path not found。

4.7.3. ChDir 与 ChDrive
切换当前工作目录和驱动器:

ChDir path       ' 更改当前工作目录
ChDrive drive    ' 更改当前驱动器

参数说明:

  • path(必需): 目标目录路径(如 "D:\Data")。
  • drive(必需): 驱动器字母(如 "D:")。

注意事项:

  • 相对路径影响: ChDir 会影响后续相对路径的解析(如 Open "file.txt" 会指向新目录)。
  • 驱动器有效性: ChDrive 必须指定已存在的驱动器,否则触发错误 68: Device unavailable。

4.8. 文件属性与信息

4.8.1. Dir 函数
检查文件/文件夹是否存在或遍历文件:

Dir([pathname[, attributes]])

参数说明:

  • pathname(可选): 文件或文件夹路径,支持通配符(如 "C:\Test\*.txt")。
  • attributes(可选): 指定搜索属性,支持以下常量(可组合使用):
  • 常量值描述vbNormal0默认,普通文件vbHidden2包含隐藏文件vbSystem4包含系统文件vbVolume8返回卷标(忽略其他属性)vbDirectory16返回子文件夹名
    示例
' 检查文件是否存在
If Dir("C:\Test.txt") <> "" Then
    MsgBox "文件存在"
End If

' 遍历所有 .txt 文件
Dim fileName As String
fileName = Dir("C:\Data\*.txt")
Do While fileName <> ""
    Debug.Print fileName
    fileName = Dir()
Loop

4.8.2. GetAttr 与 SetAttr

获取或设置文件属性(如只读、隐藏):

语法:

GetAttr(path)         ' 返回文件属性值(整数)
SetAttr path, attributes  ' 设置文件属性

属性常量:

常量

描述

vbNormal

0

普通文件(无属性)

vbReadOnly

1

只读文件

vbHidden

2

隐藏文件

vbSystem

4

系统文件

vbArchive

32

存档文件(已修改)


组合属性:

' 检查文件是否为隐藏且只读
If (GetAttr("C:\Test.txt") And (vbHidden + vbReadOnly)) = (vbHidden + vbReadOnly) Then
    Debug.Print "文件是隐藏且只读的"
End If

' 设置文件为隐藏和只读
SetAttr "C:\Test.txt", vbHidden + vbReadOnly

4.8.3. FileDateTime 函数
获取文件创建或修改时间:

语法:

FileDateTime(path)  ' 返回 Date 类型值

返回值:

  • 文件的最后修改时间(非创建时间)。

示例:

Sub ShowFileModifyTime()
    Dim filePath As String
    filePath = "C:\Test\Data.txt"
    
    If Dir(filePath) <> "" Then
        Debug.Print "最后修改时间: " & FileDateTime(filePath)
    End If
End Sub

4.8.4. LOF 与 EOF 函数

  • LOF(filenumber):返回打开文件的长度(字节数)。
  • EOF(filenumber):检查是否到达文件末尾。

语法:

LOF(filenumber)  ' 返回打开文件的字节数
EOF(filenumber)  ' 返回 Boolean,表示是否到达文件末尾

示例: 逐字符读取文件内容

Sub ReadFileByChar()
    Dim fileNo As Integer, char As String, content As String
    fileNo = FreeFile()
    
    Open "C:\Test.txt" For Input As #fileNo
    Do While Not EOF(fileNo)
        char = Input(1, #fileNo)  ' 读取一个字符
        content = content & char
    Loop
    Close #fileNo
    
    Debug.Print content
End Sub

五、高级技巧与注意事项

5.1. 错误处理

On Error Resume Next
Kill "C:\Test.txt"
If Err.Number <> 0 Then
    MsgBox "删除失败:" & Err.Description
End If
On Error GoTo 0

5.2. 路径处理

  • 使用 Application.PathSeparator 代替硬编码的 \:
filePath = "C:" & Application.PathSeparator & "Test.txt"

5.3. 性能优化

  • 传统方法:避免频繁打开/关闭文件,可一次性读取或写入。
  • FSO:使用 ReadAll 快速读取小文件,ReadLine 逐行处理大文件。

5.4. . 二进制文件操作

Dim byteData() As Byte
Open "C:\image.png" For Binary As #1
ReDim byteData(LOF(1) - 1)
Get #1, , byteData  ' 读取二进制数据到数组
Close #1

5.5. 随机访问文件(定长记录)

Type Person
    Name As String * 20  ' 固定长度20字符
    Age As Integer
End Type

Dim p As Person
Open "C:\Data.dat" For Random As #1 Len = Len(p)
p.Name = "John"
p.Age = 30
Put #1, 1, p  ' 写入第一条记录
Get #1, 1, p  ' 读取第一条记录
Close #1

5.6. 如何递归删除非空文件夹(传统方法)

传统方法无法直接删除非空文件夹,需手动遍历删除文件:

Sub DeleteFolderRecursively(folderPath As String)
    Dim filePath As String
    
    ' 删除所有文件
    filePath = Dir(folderPath & "\*.*")
    Do While filePath <> ""
        Kill folderPath & "\" & filePath
        filePath = Dir()
    Loop
    
    ' 删除所有子文件夹(需递归)
    Dim subFolder As String
    subFolder = Dir(folderPath & "\*", vbDirectory)
    Do While subFolder <> ""
        If subFolder <> "." And subFolder <> ".." Then
            DeleteFolderRecursively folderPath & "\" & subFolder
        End If
        subFolder = Dir()
    Loop
    
    ' 删除空文件夹
    RmDir folderPath
End Sub

5.7. 处理长路径问题

VBA 传统方法对长路径(>260字符)支持有限,需使用 API 或 FSO。


六、完整示例:文件备份工具

Sub BackupFiles(sourceFolder As String, backupFolder As String)
    On Error GoTo ErrorHandler
    Dim fileName As String
    
    ' 创建备份文件夹(若不存在)
    If Dir(backupFolder, vbDirectory) = "" Then MkDir backupFolder
    
    ' 遍历所有文件并复制
    fileName = Dir(sourceFolder & "\*.*")
    Do While fileName <> ""
        FileCopy sourceFolder & "\" & fileName, backupFolder & "\" & fileName
        fileName = Dir()
    Loop
    Exit Sub

ErrorHandler:
    MsgBox "备份失败:" & Err.Description, vbCritical
End Sub

七、总结

  • 传统方法:轻量、无需依赖,适合简单操作,但功能有限。
  • FSO:功能强大、面向对象,适合复杂需求,但需引用库。

选择建议

  • 快速读写少量数据 → 传统方法。
  • 操作文件夹树、处理文件属性 → FSO。

通过掌握两种方法,可以在不同场景下灵活选择,提升代码效率和可维护性。

下章预告:VBA的XML处理

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言