文件系统是平时任务中用到的相当多的一个方面,所以这里专门给总结一下文件系统方面的操作。数据库文件(例如Access文件) 其实也是一种特殊的文件格式,也可以通过这里介绍的方式处理,但是作为特殊的数据格式文件,VBA中有特别的方式处理它,这个会在后面数据处理中总结。这里的文件指的就是普通的Excel文件、文本文件、二进制文件、XML文件等。
在VBA中操作文件主要是通过以下几种方式:
一、使用Excel中的对象处理文件
Excel中代表Excel文件的对象是Workbook,所以操作文件的主要手段也就是利用Workbook或者Workbooks集合的相关方法。主要的方法总结如下:
1、打开文件
打开Excel文件:Workbooks.Open。
打开文本文件:Workbooks.OpenText。
打开XML文件:Workbooks.OpenXML。
打开数据库文件:Workbooks.OpenDatabase。
注意:使用Open方法也可以打开文本文件,但建议使用OpenText方法。此方法是载入一个文本文件,并将其作为包含单个工作表的工作簿进行分列处理,然后在此工作表中放入经过分列处理的文本文件数据。
2、保存文件
文件的保存可以通过几种方式实现:
- 使用Workbook对象的Save或SaveAs方法。
- 使用Application.Dialogs,显示标准的“另存为”对话框。
- 使用Application.GetSaveAsFilename可以调出标准的“另存为”对话框,获取用户文件名,但并不真正保存任何文件,然后可以使用代码保存文件。还有Application.GetOpenFileName也可以调出标准的“打开”对话框,返回用户选中或填写的文件名,但是返回后并不真打开选中文件。
3、关闭文件
关闭文件可以使用Workbooks集合或Workbook对象的 Close 方法。前者是关闭所有打开的工作簿,后者关闭特定的工作簿。
总结:利用Excel对象的方法进行Excel文件的操作是最简单,也是最方便的。虽然利用Workbook对象也可以打开其他的一些文件,但是都不是最佳的手段,而且这个对象对文件的操控性很弱,无法实现很多文件系统的操作,所以一般操作文件的时候,都要结合其他的集中手动来共同协作完成任务。
二、使用VBA内置的文件处理函数处理文件
VBA内置了很多用于文件操作的语句和函数,可以满足大多数情况下的文件的相关操作。下面我总结一下。
(一)文件处理
打开文件:Open…For…AS…
For后面的打开模式不同,决定了后面的内容处理方式也不同,常用的有打开成读入模式,写入模式,追加模式,二进制模式,随机模式等等。如果要打开二进制文件,则可以选择后两种模式。As后面可以指定打开后的文件号(1到511),指定了文件号以后,VBA几乎所有内置的文件处理函数就都使用这个文件号处理文件。一般可以用FreeFile函数获得没有使用的文件号。
以Open语句打开文件,并不是我们通常的双击一个文件打开显示到屏幕上,而是将其存放在磁盘上的数据读入到缓冲区,不是可视化的打开。这种打开是不需要密码的,即使你的Excel文件设置了打开密码,还是照打开不误,这也正是Excel文件不安全的根源所在。
辅助函数:
FreeFile函数:获得没有使用的文件号
Width函数:设置文档中每行的宽度(0~255)。如果 width 等于 0,则行的长度不受限制。width 的缺省值为 0。
关闭文件:Close,Reset
说明:打开文件后,必须在使用完后关闭文件,这里的文件名可以传入打开时指定的文件号。如果使用Close语句,但是关闭的文件名省略,则会关闭所有使用Open语句打开的文件。使用Reset函数会关闭所有Open语句打开的文件,并将文件缓冲区的数据全部写入磁盘。
重命名文件:Name
拷贝文件:FileCopy
移动文件:Name函数也可以,修改全路径即可。
判断文件是否存在:Dir
删除文件:Kill
读取文件内容
读取文件的内容通常需要的辅助函数(一般用于标识读取的位置):
EOF 函数:EOF(filenumber)
功能:返回一个 Integer,它包含 Boolean 值 True,表明已经到达为 Random 或顺序 Input 打开的文件的结尾。
LOF 函数:LOF(filenumber)
功能:返回一个 Long,表示用 Open 语句打开的文件的大小,该大小以字节为单位。
Loc 函数:LOc(filenumber)
功能:返回一个 Long,在已打开的文件中指定当前读/写位置。
Seek#语句
功能:可以用Seek语句指定Get/Input语句的读取位置;一般结合使用LOF函数,使用循环读取所有数据。
Seek函数
功能:返回一个Long值,在用Open 语句打开的文件中指定当前的读/写位置。
说明:在使用Get语句读取文件时,必须用LOF函数来判断是否到达文件末尾,而不是用EOF函数。可以使用Seek函数判断当前位置,然后与LOF的值比较。
例如:Do While Seek(1) < LOF(1)
'继续读取
......
Loop
读取文本文件内容:
Input #语句
功能:从已打开的顺序文件中读出数据并将数据指定给变量。
Line Input函数
功能:从已打开的顺序文件中读出一行并将它分配给 String 变量。
Input函数
功能:返回包含指定数目的字符的字符串,它包含以 Input 或 Binary 方式打开的文件中的字符。
说明:通常用 Print # 或 Put 将 Input 函数读出的数据写入文件。Input 函数只用于以 Input 或 Binary 方式打开的文件。与 Input # 语句不同,Input 函数返回它所读出的所有字符,包括逗号、回车符、空白列、换行符、引号和前导空格等。
读取二进制文件内容:
Get语句
功能:将一个已打开的磁盘文件读入一个变量之中。
写入文件内容
写入文本文件内容:
Write # 语句
功能:将数据写入顺序文件。
如果省略写入的内容,并在文件号之后加上一个逗号,则会将一个空白行打印到文件中。多个表达式之间可用空白、分号或逗号隔开。空白和分号等效。与 Print # 语句不同,当要将数据写入文件时,Write # 语句会在项目和用来标记字符串的引号之间插入逗号。没有必要在列表中键入明确的分界符。Write # 语句在将 outputlist 中的最后一个字符写入文件后会插入一个新行字符,即回车换行符,(Chr(13) + Chr(10))。
Print # 语句
功能:将格式化显示的数据写入顺序文件中。
说明:通常用 Line Input # 或 Input 读出 Print # 在文件中写入的数据。
说明:通常用 Write # 将 Input # 语句读出的数据写入文件。为了能够用 Input # 语句将文件的数据正确读入到变量中,在将数据写入文件时,要使用 Write # 语句而不使用 Print # 语句。使用 Write # 语句可以确保将各个单独的数据域正确分隔开。
写入二进制文件内容
Put 语句
说明:通常用Put 把二进制内容写入到文件。
获取和设置文件/文件夹属性:GetAttr,SetAttr
返回文件长度(字节):FileLen
获取文件的创建或最后修改时间:FileDateTime
Name不能移动一个目录或文件夹。
如果对一个已打开的文件使用 FileCopy 语句,则会产生错误。
Kill 支持多字符 (*) 和单字符 (?) 的统配符来指定多重文件。如果使用 Kill 来删除一个已打开的文件,则会产生错误。
若要判断是否设置了某个属性,在 GetAttr 函数与想要得知的属性值之间使用 And 运算符与逐位比较。如果所得的结果不为零,则表示设置了这个属性值。
如果想要使用SetAttr给一个已打开的文件设置属性,则会产生运行时错误。可以一次设置多个属性,属性值相加即可。例如设置文件为隐藏和只读
SetAttr "F:\test.txt", vbHidden + vbReadOnly ' 设置隐藏并只读。
当调用 FileLen 函数时,不需要打开文件,如果所指定的文件已经打开,则返回的值是这个文件在打开前的大小。
重量级选手:Dir语法:Dir[(pathname[, attributes])] ,两个参数都是可选的,attributes表示文件属性。
功能:返回一个文件名、目录名或文件夹名称,它必须与指定的模式或文件属性、或磁盘卷标相匹配。
说明:在第一次调用 Dir 函数时,必须指定 pathname,否则会产生错误。如果也指定了文件属性,那么就必须包括 pathname。
Dir 会返回匹配 pathname 的第一个文件名。若想得到其它匹配 pathname 的文件名,再一次调用 Dir,且不要使用参数。如果已没有合乎条件的文件,则 Dir 会返回一个零长度字符串 ("")。一旦返回值为零长度字符串,并要再次调用 Dir 时,就必须指定 pathname,否则会产生错误。不必访问到所有匹配当前 pathname 的文件名,就可以改变到一个新的 pathname 上。但是,不能以递归方式来调用 Dir 函数。以 vbDirectory 属性来调用 Dir 不能连续地返回子目录。
(二)目录处理
1、返回当前的路径:CurDir
说明:drive 参数是可选的,它指定一个存在的驱动器。如果没有指定驱动器,或 drive 是零长度字符串 (""),则 CurDir 会返回当前驱动器的路径。
2、改变当前的目录或文件夹:ChDir
说明:ChDir 语句改变缺省目录位置,但不会改变缺省驱动器位置。缺省驱动器一般是C。
3、改变当前的驱动器:ChDrive
说明:如果使用零长度的字符串 (""),则当前的驱动器将不会改变。如果 drive 参数中有多个字符,则 ChDrive 只会使用首字母。
4、判断文件夹是否存在:Dir
5、重命名文件夹:Name
6、创建一个新的目录或文件夹:MkDir
说明:path 可以包含驱动器。如果没有指定驱动器,则 MkDir 会在当前驱动器上创建新的目录或文件夹。
7、删除一个存在的目录或文件夹:RmDir
说明:如果想要使用 RmDir 来删除一个含有文件的目录或文件夹,则会发生错误。在试图删除目录或文件夹之前,先使用 Kill 语句来删除所有文件。
函数的具体使用可以参考人气链接:http://club.excelhome.net/forum.php?mod=viewthread&tid=230215
三、使用FileSystemObject对象处理文件
FileSystemObject(简称为FSO,需Office 2000以后版本)对象模型,是微软提供的专门用来访问计算机文件系统的,具有大量的属性、方法和事件。
FileSystemObject对象模型
FileSystemObject主对象,包含用来创建、删除和获得有关信息,以及用来操作驱动器、文件夹和文件的方法和属性。
Drive对象,包含用来获得和操作驱动器的方法和属性。驱动器不一定是硬盘,也可以是CD-ROM、U盘甚至是网络硬盘。
Drives 集合,提供驱动器的列表,这些驱动器以实物或在逻辑上与系统相连接。Drives集合包括所有驱动器,与类型无关。
File对象,包含用来创建、删除或移动文件的方法和属性。
Files集合,提供包含在文件夹内的所有文件的列表。
Folder对象,包含用来创建、删除或移动文件夹的方法和属性。
Folders集合,提供包含在文件夹内的所有文件夹的列表。
TextStream对象,用来读写文本文件。
FileSystemObject对象的创建
FSO模型并不是VBA的一部分,它是以一个COM组件的形式提供的,包含在脚本类型库 (Scrrun.dll) 中。在FSO对象模型中,最高层的对象FileSystemObject,而且是唯一需要直接创建的对象,其它的对象都可以通过它的属性或方法得到。与所有的COM组件使用方式一样,创建FileSystemObject对象可以使用两种方式:
前期绑定:项目需要先引用C:\Windows\System32\Scrrun.dll(在VBA编辑器中,选择"Tools"菜单下"References...",在出现的对话框中选择"Browser..."选中这个Dll即可),然后直接New就可以了。例如:Dim fso As New FileSystemObject。
后期绑定:使用CreatObject函数。CreateObject 函数用来创建并返回一个对 ActiveX 对象的引用。
Set fso = CreateObject("Scripting.FileSystemObject")
- 参数中Scripting是类型库的名称,FileSystemObject就是要创建的对象的名字。
- FileSystemObject对象模型中有许多功能是重复的,如可用FileSystemObject对象的CpoyFile方法,也可用File对象的Copy方法来复制文件。
- 由于VBA编辑器还是有一点Intellisense的支持,所以使用前期绑定,可以很方便的查看每个对象的成员。
FileSystemObject对象的方法
GetDrive - 返回一个与指定路径中的驱动器相对应的 Drive 对象。
GetDriveName - 返回一个包含指定路径的驱动器名字的字符串。
GetExtensionName - 返回一个包含路径中最后部件扩展名的字符串。
GetBaseName - 返回一个包含路径中最后部件的基本名字(去掉任何文件扩展名)的字符串。
GetAbsolutePathName - 从提供的路径说明中返回一个完整、明确的路径。
GetFile - 返回一个和指定路径中文件相对应的 File 对象。如果指定的文件不存在,则发生一个错误。
GetFileName - 返回指定路径中的最后文件名。
GetFolder - 返回一个和指定路径中文件夹相对应的 Folder 对象。如果指定的文件夹不存在,则发生一个错误。
GetSpecialFolder - 返回指定的特殊文件夹,例如Windows文件夹,System文件夹,Temp文件夹等。
GetParentFolderName - 返回一个包含指定路径最后部件父文件夹名字的字符串。
GetTempName - 返回一个随机产生的临时文件或文件夹的名字。
BuildPath - 追加一个名字到一个已经存在的路径。
CreateFolder - 创建一个文件夹。如果指定的文件夹已经存在,则发生一个错误。
CopyFolder - 复制一个文件夹到另一个地方。源文件参数可以包含通配符,但是目标文件(可以是文件夹)参数不允许有通配符。
MoveFolder - 将一个或多个文件夹从一个地方移动到另一个地方。源文件参数可以包含通配符。Windows不允许的移动(例如移动C盘)是不支持的。
DeleteFolder - 删除一个指定的文件夹和它的内容。
FolderExists - 如果指定的文件夹存在返回 True,不存在返回 False。
DriveExists - 如果指定的驱动器存在,返回 True,如果不存在返回 False。
FileExists - 如果指定的文件存在,返回 True,若不存在,则返回 False。
CreateTextFile - 创建一个指定的文件名并且返回一个用于该文件读写的 TextStream 对象。
OpenTextFile - 打开一个指定的文件并返回一个 TextStream 对象,该对象可用于对文件进行读、写、追加操作;文件不存在时自动创建。
CopyFile - 把一个或多个文件从一个地方复制到另一个地方。
MoveFile - 将一个或多个文件从一个地方移动到另一个地方。
DeleteFile - 删除一个指定的文件。
处理驱动器
1.获取驱动器对象
使用FileSystemOBject的GetDrive方法获得一个Drive对象;不能直接创建一个驱动器对象。
2.Drive对象的属性
TotalSize - 驱动器的总容量,以字节为单位。
AvailableSpace - 驱动器的可用空间容量,以字节为单位。
FreeSpace - 驱动器的剩余空间容量,和 AvailableSpace 属性是相同的。对于支持限额的计算机系统来说,二者之间可能有所不同。
DriveLetter - 驱动器字母,即盘符。
DriveType - 驱动器的类型。如"Removable"、"Fixed"、"Network"、"CD-ROM"、"RAM Disk"
SerialNumber - 驱动器的序列号。
FileSystem - 驱动器所使用的文件系统类型。如FAT、FAT32、NTFS、以及 CDFS。
IsReady - 驱动器是否可用。
ShareName - 驱动器的网络共享名。
VolumeName - 驱动器的卷标名。
Path - 驱动器的路径。C驱动器的路径是 C:,而不是 C:\。
RootFolder - 驱动器的根文件夹。C驱动器的根文件夹是 C:\。
处理文件夹
1.获取文件夹对象
可以用FileSystemObject的GetFolder获取一个Folder对象,也可以用FileSystemObject对象的CreateFolder方法创建一个Folder对象。
2.Folder对象的属性
Attributes - 文件夹的属性。可为任意一个合法值或它们的逻辑组合(常用的几个值:Normal=0;ReadOnly=1;Hidden=2;System=4;Volume=8;Directory=16)
Name - 文件夹名字。
ShortName - 较早的命名约定的程序所使用的短名字。
Type - 文件夹类型。
Files - 文件夹下包括的所有 File 对象组成的 Files 集合,包括隐藏文件和系统文件。
Drive - 文件夹所在的驱动器符号。
IsRootFolder - 文件夹是否是根文件夹。
ParentFolder - 文件夹的父文件夹对象。
SubFolders - 文件夹的子文件夹集合。
Path - 文件夹的路径。
ShortPath - 较早的文件命名约定的程序所使用的短路径。
Size - 文件夹的大小,以字节为单位。
DateCreated - 文件夹的创建日期和时间。
DateLastModified - 最后一次修改文件夹的日期和时间。
DateLastAccessed - 最后一次访问文件夹的日期和时间。
3.Folder对象的方法
Copy、Move - 与FileSystemObject对应的方法是一样的。不同在于后者可一次处理多个文件夹。
Delete - 删除一个指定的文件夹。Delete 方法的作用与FileSystemObject.DeleteFolder是一样的。
CreateTextFile - 创建Text文件。与FileSystemObject对象的CreateTextFile方法是一样的。
处理文件
1.获取文件对象
可以使用FileSystemObject对象或者Folder对象的相关方法获得或创建File对象。
2.File对象的属性
File对象的属性和Folder的属性是完全一样的,只是少了Files、IsRootFolder、SubFolders这3个属性。
3.File对象的方法
Copy、Move、Delete - 除了FileSystemObject对象相应的方法支持处理多个文件外,基本没区别。
Delete - 删除指定文件;与FileSystemObject.DeleteFile是一样的。
OpenAsTextStream - 打开一个指定的文件并返回一个TextStream 对象,该对象可用来对文件进行读、写、追加操作;它与FileSystemObject对象的OpenTextFile方法一样。
文本文件与TextStream对象
1、打开或创建文本文件
打开现有的文本文件,可以使用FileSystemObject对象的 OpenTextFile 方法或File对象的OpenAsTextStream 方法。
创建文件可以使用FileSystemObject对象的 CreatTextFile 方法或在OpenTextFile 方法中将iomode参数设为ForWriting=2,create参数设为True。
例如:Set f = fso.OpenTextFile("c:\test1.txt", 2, True) '如果不存在test1.txt将自动创建。
2、读取文件
打开文件后,将返回一个TextStream 对象,我们可以利用TextStream 对象的属性及方法来对文件进行读写操作。
TextStream对象的属性:
AtEndOfLine - 文件指针是否正好在行尾标记的前面
AtEndOfStream - 文件指针是否在 TextStream 文件末尾
Column - TextStream 文件中当前字符位置的列号
Line - TextStream 文件中的当前行号
利用TextStream 对象读取文件有的方法:
Read - 从一个TextStream 文件中读取指定数量的字符并返回得到的字符串。
ReadLine - 从一个TextStream 文件读取一整行(到换行符但不包括换行符)并返回得到的字符串。
ReadAll - 读取整个的TextStream文件并返回得到的字符串。如果文本为空,可能会出错,大的文件也不适合使用该方法。
还有两个辅助读取的方法:
Skip- 当读一个TextStream文件时跳过指定数量的字符。
SkipLine - 当读一个TextStream文件时跳过下一行。
3、写入数据到文件
Write - 写一个指定的字符串到一个 TextStream 文件。
WriteLine - 写入一个指定的字符串和换行符到一个TextStream文件中。
WriteBlankLines - 写入指定数量的换行符到一个TextStream文件中。
4、关闭文件
利用TextStream 对象的Close方法。
总结:FSO模型使应用程序能够非常方便的创建、更改、移动和删除文件和文件夹,也可以很方便的获取文件/文件夹/驱动器的几乎所有有用信息。特别的,使用FSO去处理文本文件毫不逊色于VBA语句,值得推荐。但是FSO模型目前不支持二进制文件,若要操作二进制文件,还是要使用VBA函数。
四、使用Windows API处理文件
Windows编程的核心便是利用API开发,VBA自然也是要分一杯羹的。利用API之前,需要使用语句申明,语法如下所示:Declare Function GetLogicalDrives Lib "kernel32" Alias "GetLogicalDrives" () As Long。
下面只介绍一下常用的几个API,更多的函数请参看相关资料,此外推荐一个这方面总结比较好的链接:http://club.excelhome.net/forum.php?mod=viewthread&tid=230694。
创建文件或文件夹
CreateDirectory,CreateDirectoryEx - 创建一个新目录。
CreateFile - 这是一个全功能的函数,可打开和创建文件、管道、邮槽、通信服务、设备以及控制台。它能打开命名管道和控制Unicode文件名,同时不受128个字符的路径名称的限制。
OpenFile - 这个函数能执行大量不同的文件操作,但是有一些限制。相比之下,请优先考虑CreateFile函数。
lcreat - 创建一个文件。如文件已经存在,就会将其缩短成零长度,并将其打开,以便读写。
获取文件或文件夹信息
GetCurrentDirectory - 在一个缓冲区中装载当前目录。
SetCurrentDirectory - 设置当前目录。
GetFullPathName - 获取指定文件的完整路径名。
GetSystemDirectory - 这个函数能取得System目录的完整路径名。
GetWindowsDirectory - 这个函数能获取Windows目录的完整路径名。
GetTempPath - 获取临时文件路径。
GetBinaryType - 判断文件是否可以执行。
GetFileAttributes - 获取指定文件的属性。
GetFileInformationByHandle - 该函数能够获取文件的所有信息,如大小、属性等,同时还包括一些其他地方无法获取的信息,比如:文件卷标、索引和链接信息。
GetFileSize - 获取文件长度。
GetFileTime - 取得指定文件的时间信息,有三个文件时间:创建时间、最后访问时间、最后写时间。
GetFileType - 在给出文件句柄的前提下,判断文件类型。
GetFileVersionInfo - 从支持版本标记的一个模块里获取文件版本信息。
GetFileVersionInfoSize - 针对包含了版本资源的一个文件,判断容纳文件版本信息需要一个多大的缓冲区。
GetFullPathName - 获取文件路径,该函数获取文件的完整路径名。注意:只有当该文件在当前目录下,结果才正确。如果要得到真正的路径。应该用GetModuleFileName函数。
SetFileAttributes - 设置文件属性。
SetFilePointer - 在一个文件中设置当前的读写位置。
SetFileTime - 设置文件的创建、访问及上次修改时间。
LockFile,LockFileEx - 在windows中,文件可用共享模式打开——在这种情况下,多个进程可同时访问该文件,避免冲突。
UnlockFile,UnlockFileEx - 解除对一个文件的锁定。
文件外操作
CompareFileTime - 根据FILETIME结构的信息,对比两个文件的时间。
CopyFile - 复制文件。只能复制文件,而不能复制目录。
MoveFile, MoveFileEx - 移动文件。如dwFlags设为零,则MoveFile完全等价于MoveFileEx。
查找文件
FindClose - 关闭由FindFirstFile函数创建的一个搜索句柄。
FindFirstFile - 根据文件名查找文件。
FindNextFile - 根据调用FindFirstFile函数时指定的一个文件名查找下一个文件。
SearchPath - 查找指定文件。
处理文件内容
lopen - 以二进制模式打开指定的文件
llseek - 设置文件中进行读写的当前位置。该函数与vba的seek语句类似。
lread - 将文件中的数据读入内存缓冲区。
lwrite - 将数据从内存缓冲区写入一个文件。
ReadFile,ReadFileEx - 从文件中读出数据。该函数比lread函数要灵活的多。该函数能够操作通信设备、管道、套接字等。
WriteFile,WriteFileEx - 将数据写入一个文件。该函数比lwrite函数要灵活的多。也可将这个函数应用于对通信设备、管道、套接字等。
SetEndOfFile - 针对一个打开的文件,将当前文件位置设为文件末尾。
FlushFileBuffers - 针对指定的文件句柄,刷新内部文件缓冲区。
关闭文件
CloseHandle - 关闭一个内核对象。其中包括文件、文件映射、进程、线程、安全和同步对象等。
lclose - 关闭指定的文件,请参考CloseHandle函数,了解进一步的情况。
删除文件或文件夹
RemoveDirectory - 删除指定目录。
DeleteFile - 删除指定文件。
善待自己,不要想着记住所有东西,该出手时就Google。