一、从电脑管家理解文件操作
文件管家模型:
- 文件柜(Folder) → 文件夹与子文件夹
- 文件袋(File) → 各类文档
- 标签机(FileSystemObject) → 核心操作对象
- 操作手册 → VBA代码指令集
在VBA(Visual Basic for Applications)中,使用文件系统对象(FSO, FileSystemObject)是处理文件和文件夹的标准方式。无论是创建文件夹还是文件,使用FSO对象都是一个常见的做法,因为它提供了丰富的属性和方法来实现这些操作。
创建文件夹
要使用FSO创建文件夹,你需要首先创建一个FileSystemObject的实例,然后使用该实例的CreateFolder方法。
创建文件
创建文件(此处的文件是指文件文件.Txt)同样需要FileSystemObject,但使用CreateTextFile方法。
注意事项
- 引用FileSystemObject:在使用FSO之前,确保你的VBA项目已经引用了Microsoft Scripting Runtime库。在VBA编辑器中,可以通过“工具”->“引用”来添加。
- 路径和权限:确保你有权限在指定的路径上创建文件夹或文件。如果路径不存在,FSO将自动创建必要的上级目录。
- 错误处理:在实际应用中,考虑到各种可能的错误(如权限问题、路径无效等),建议添加适当的错误处理机制,例如使用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处理