https://www.cnblogs.com/top5/archive/2009/10/29/1591937.html |
Excel-VBA操作文件四大方法 |
Excel-VBA操作文件四大方法之一 |
在我们日常使用Excel的时候,不仅会用到当前Excel文件的数据,还经常需要访问其他的数据文件。这些数据文件可能是Excel文件、文本文 件或数据库文件等。经常有朋友会问如何在vba代码里操作这些数据文件?本文就系统地介绍一下在Excel中应用VBA操作数据文件的方法。 |
本文主要介绍四种常用的方法: |
1、利用Excel对象来处理文件; |
2、利用VBA文件处理语句来处理文件; |
3、利用FileSystemObject对象来处理文件; |
4、利用API函数来处理文件。 |
当然对于数据库文件,还可以利用ADO+SQL的方法操作,不过论坛已经有前辈详细介绍过此类方法,本文就不再重复了。 |
一、利用Excel对象来处理文件 |
利用Excel对象自带的方法来操作文件是最方便,也是最简单的。 |
我们主要利用Workbooks集合和Workbook对象的方法来操作文件。 |
1、打开Excel文件 |
我们可以用Workbooks.Open方法打开一个Excel工作簿。 |
Workbooks.Open(FileName, UpdateLinks, ReadOnly , Format, Password, WriteResPassword, IgnoreReadOnlyRecommended, Origin, Delimiter, Editable, Notify, Converter, AddToMru, Local, CorruptLoad) |
其中FileName是必选的参数,表示要打开的工作簿名,如果没有指定路径,则代表当前路径。另外14个是可选参数,除了密码参数,其他的一般很少用。具体的含义可以参看VBA的帮助。 |
例: |
Workbooks.Open "F:\test.xls" |
可以打开F盘的test.xls文件。 |
2、打开文本文件 |
使用Open方法也可以打开文本文件,但建议使用OpenText方法。此方法是载入一个文本文件,并将其作为包含单个工作表的工作簿进行分列处理,然后在此工作表中放入经过分列处理的文本文件数据。完整语法如下: |
Workbooks.OpenText(FileName, Origin, StartRow, DataType, TextQualifier, ConsecutiveDelimiter, Tab, Semicolon, Comma, Space, Other, OtherChar, FieldInfo, TextVisualLayout, DecimalSeparator, ThousandsSeparator, TrailingMinusNumbers, Local) |
关于以上参数的具体含义可以参看VBA的帮助,这里就不重复了。在实际的编程中,一般无需对这些复杂的参数进行处理。可以通过录制宏来得到打开一个 文本文件的VBA代码。具体方法就是选择“文件——打开”,然后选择打开文本文件,就会出现文本导入向导,一步一步执行完,直到文本打开后,停止录制。 |
以下是录制宏得到的代码: |
Sub Macro1() |
' |
' Macro1 Macro |
' 宏由 MC SYSTEM 录制,时间: 2007-3-29 |
' |
' |
Workbooks.OpenText Filename:= "F:\CallWindowProc.txt" , Origin:=xlWindows, _ |
StartRow:=1, DataType:=xlDelimited, TextQualifier:=xlDoubleQuote, _ |
ConsecutiveDelimiter:= False , Tab:= True , Semicolon:= False , Comma:= False _ |
, Space:= False , Other:= False , FieldInfo:=Array(1, 1), _ |
TrailingMinusNumbers:= True |
End Sub |
在实际编程中只要做相应的修改就可以使用了。 |
3、打开其他文件 |
利用Excel对象还可以打开XML文件和一些数据库(如Access)文件,对应XML文件,需要Excel2003以上的版本。 |
OpenXML方法的语法如下: |
Workbooks.OpenXML(Filename, Stylesheets, LoadOption) |
FileName String 类型,必需。要打开的文件名。 |
Stylesheets Variant 类型,可选。单个值或值的数组,用于指定要应用哪些 XSL 转换 (XSLT) 样式表处理指令。 |
LoadOption Variant 类型,转换。指定 Excel 打开 XML 数据文件的方式。可为 XlXmlLoadOption 常量之一。 |
XlXmlLoadOption 可为以下 XlXmlLoadOption 常量之一: |
xlXmlLoadImportToList 将 XML 数据文件的内容置于 XML 列表中。 |
xlXmlLoadMapXml 在“XML 结构”任务窗格中显示 XML 数据文件的架构。 |
xlXmlLoadOpenXml 打开 XML 数据文件。文件的内容将展开。 |
xlXmlLoadPromptUser 提示用户选择打开文件的方式。 |
示例 |
下面的代码打开了 XML 数据文件“customers.xml”并在 XML 列表中显示了此文件的内容。 |
Sub UseOpenXML() |
Application.Workbooks.OpenXML _ |
Filename:= "customers.xml" , _ |
LoadOption:=xlXmlLoadImportToList |
End Sub |
OpenDatabase 方法语法如下: |
Workbooks.OpenDatabase(FileName, CommandText, CommandType, BackgroundQuery, ImportDataAs) |
FileName String 类型,必需。连接字符串。 |
CommandText Variant 类型,可选。查询的命令文本。 |
CommandType Variant 类型,可选。查询的命令类型。以下是可用的命令类型: Default 、SQL 和 Table。 |
BackgroundQuery Variant 类型,可选。查询的背景。 |
ImportDataAs Variant 类型,可选。确定查询的格式。 |
示例 |
本示例中,Excel 打开了“northwind.mdb”文件。 |
Sub OpenDatabase() |
Workbooks.OpenDatabase FileName:= "C:\northwind.mdb" |
End Sub |
4、保存文件 |
文件的保存使用Workbook对象的Save或SaveAs方法。 |
Save方法使用简单,语法为 |
expression.Save,expression是某个Workbook对象。 |
如:ActiveWorkbook.Save |
即保存当前活动工作簿。 |
如果是第一次保存工作簿或要另存为,请使用 SaveAs 方法为该文件指定文件名。 |
其语法为: |
expression.SaveAs(FileName, FileFormat, Password, WriteResPassword, ReadOnlyRecommended, CreateBackup, AccessMode, ConflictResolution, AddToMru, TextCodepage, TextVisualLayout, Local) |
具体参数含义可参看VBA帮助,使用都比较简单。 |
示例 |
本示例新建一个工作簿,提示用户输入文件名,然后保存该工作簿。 |
Set NewBook = Workbooks.Add |
Do |
fName = Application.GetSaveAsFilename |
Loop Until fName <> False |
NewBook.SaveAs Filename:=fName |
Application.GetSaveAsFilename为调出标准的“另存为”对话框,获取用户文件名,但并不真正保存任何文件,然后使用代码保存文件。还有Application.GetOpenFileName可以调出标准的“打开”对话框。 |
5、关闭文件 |
关闭文件可以使用Workbooks集合或Workbook对象的 Close 方法。前者是关闭所有打开的工作簿,后者关闭特定的工作簿。 |
Workbook对象的 Close 方法语法为: |
expression.Close(SaveChanges, Filename, RouteWorkbook) |
SaveChanges参数表示是否保存更改,对许多不需要更改的操作,可设置为 False 以免弹出保存更改提示的对话框。 |
FileName 可选。以此文件名保存所做的更改。 |
RouteWorkbook 可选。如果指定工作簿不需要传送给下一个收件人(没有传送名单或已经传送),则忽略该参数。 |
示例 |
本示例关闭 Book1.xls,并放弃所有对此工作簿的更改。 |
Workbooks( "BOOK1.XLS" ).Close SaveChanges:= False |
本示例关闭所有打开的工作簿。如果某个打开的工作簿有改变,Microsoft Excel 将显示询问是否保存更改的对话框和相应提示。 |
Workbooks.Close |
6、综合实例 |
假如F盘有一个Excel文件test.xls,现在有另一个Excel文件要访问test.xls的数据,我们来看用VBA代码如何操作。代码如下: |
Public Sub test() |
Application.ScreenUpdating = False |
Workbooks.Open "f:\test.xls" |
ThisWorkbook.Sheets(1).Range( "b1" ) = ActiveWorkbook.Sheets(1).Range( "a2" ) |
ActiveWorkbook.Close |
Application.ScreenUpdating = True |
End Sub |
首先关闭屏幕刷新,是为了防止test.xls在打开时被看见(有时候还是看的见)。打开后,见test.xls的Sheet1的单元格A2中的值赋给当前工作簿的Sheet1的单元格B2,然后关闭test.xls。 |
当要打开的工作簿不确定的时候,可以通过调用打开对话框来让用户自己选择。 |
可改为如下: |
Public Sub test() |
Application.ScreenUpdating = False |
Dim Filename as String |
Filename = Application.GetOpenFileName |
Workbooks.Open Filename |
ThisWorkbook.Sheets(1).Range( "b1" ) = ActiveWorkbook.Sheets(1).Range( "a2" ) |
ActiveWorkbook.Close |
Application.ScreenUpdating = True |
End Sub |
7、总结 |
利用Excel对象的方法进行文件操作是最简单,也是最方便的,适合初学者。对于Excel文件格式,如果我们仅仅是读取其表格中的内容,这种方法也是首选。对于文本文件的操作,使用第二种方法比较方便,若要将文本转换成表格,那么使用此方法也是合适的。 |
如何在d:\test.xls已打开的情况下不让以下的语句再去创建一个test.xls的实例(虽然它标识为只读), |
并给出文件已打开的提示. |
先做一个判断!判断该工作簿是否打开了? |
例如: |
Set xlexcel = CreateObject( "excel.application" ) |
dim wb as object |
set wb = xlexcel.workbooks( "test.xls" ) |
if wb is nothing then |
msgbox "工作簿未打开!" |
xlexcel.Workbooks.Open "d:\test.xls" |
xlexcel.Visible = True |
end if |
Excel-VBA操作文件四大方法之二 |
二、利用VBA文件处理语句来处理文件 |
VBA包含了许多用于文件操作的语句和函数,可以满足绝大多数情况下的文件操作要求。下面我们按照操作目的进行一一介绍。 |
(一)文件处理 |
1.Name 语句 |
语法:Name oldpathname As newpathname |
功能:重命名一个文件、目录、或文件夹,移动一个文件。 |
说明:在一个已打开的文件上使用 Name,将会产生错误。进行文件操作时,一定要注意错误处理。 |
示例: |
On Error Resume Next '错误处理 |
Name "f:\TEST.xls" As "f:\TEST123.xls" '重命名 |
Name "f:\TEST.xls" As "f:\dll\TEST.xls" '移动文件 |
Name "f:\TEST.xls" As "d:\TEST123.xls" '跨驱动器移动并重命名文件 |
注意:Name不能移动一个目录或文件夹。 |
2、FileCopy 语句 |
语法:FileCopy source, destination |
功能:复制一个文件。 |
说明:如果对一个已打开的文件使用 FileCopy 语句,则会产生错误。 |
示例: |
FileCopy "f:\TEST.xls" , "e:\TEST.xls" '从F盘复制TEST.xls到E盘 |
3、Kill 语句 |
语法:Kill pathname |
功能:从磁盘中删除文件。 |
说明:Kill 支持多字符 (*) 和单字符 (?) 的统配符来指定多重文件。如果使用 Kill 来删除一个已打开的文件,则会产生错误。 |
示例: |
Kill "f:\TEST.xls" ’删除F盘的TEST.xls文件 |
Kill "f:\*.xls" ' 删除F盘所有xls文件 |
4、GetAttr 函数 |
语法:GetAttr(pathname) |
功能:获取一个文件、目录、或文件夹的属性。返回一个 Integer 值。 |
返回值 |
由 GetAttr 返回的值,是下面这些属性值的总和: |
常数 值 描述 |
vbNormal 0 常规 |
vbReadOnly 1 只读 |
vbHidden 2 隐藏 |
vbSystem 4 系统文件 |
vbDirectory 16 目录或文件夹 |
vbArchive 32 存档文件 |
vbalias 64 指定的文件名是别名。只在Macintosh中可用。 |
说明:若要判断是否设置了某个属性,在 GetAttr 函数与想要得知的属性值之间使用 And 运算符与逐位比较。如果所得的结果不为零,则表示设置了这个属性值。 |
示例: |
Debug.Print GetAttr( "F:\test.txt" ) '若为存档文件,在立即窗口可看到值为32 |
Debug.Print GetAttr( "F:\test.txt" ) '将属性—高级—可存档文件的勾去掉后,值为0 |
为判断一个文件是否只读,可用下法: |
Debug.Print GetAttr( "F:\test.txt" ) And vbReadOnly |
若值非零,说明时只读的。 |
5、SetAttr 语句 |
语法:SetAttr pathname, attributes |
功能:为一个文件设置属性。 |
说明:如果想要给一个已打开的文件设置属性,则会产生运行时错误。 |
示例: |
SetAttr "F:\test.txt" , vbHidden ' 设置隐藏属性。 |
SetAttr "F:\test.txt" , vbHidden + vbReadOnly ' 设置隐藏并只读。 |
6、FileLen 函数 |
语法:FileLen(pathname) |
功能:获取一个文件的长度,单位是字节。 |
说明:当调用 FileLen 函数时,不需要打开文件,如果所指定的文件已经打开,则返回的值是这个文件在打开前的大小。 |
7、FileDateTime 函数 |
语法:FileDateTime(pathname) |
功能:获取一个文件被创建或最后修改后的日期和时间。 |
示例: |
Debug.Print FileDateTime( "F:\TEST.xls" ) '在立即窗口可看到2007-3-29 19:28:27 |
(二)目录处理 |
1、CurDir 函数 |
语法:CurDir[(drive)] |
功能:返回当前的路径。 |
说明:drive 参数是可选的,它指定一个存在的驱动器。如果没有指定驱动器,或 drive 是零长度字符串 ( "" ),则 CurDir 会返回当前驱动器的路径。 |
示例: |
Debug.Print CurDir ' 返回“C:\Documents and Settings\yc\My Documents”。 |
Debug.Print CurDir( "C" ) ' 返回“C:\Documents and Settings\yc\My Documents”。 |
Debug.Print CurDir( "D" ) ' 返回“D:\”。 |
2、ChDir 语句 |
语法:ChDir path |
功能:改变当前的目录或文件夹。 |
说明:ChDir 语句改变缺省目录位置,但不会改变缺省驱动器位置。缺省驱动器一般是C。 |
示例: |
ChDir "D:\temp" |
Debug.Print CurDir ' 返回“C:\Documents and Settings\yc\My Documents”。 |
Debug.Print CurDir( "D" ) ' 返回“D:\temp”。 |
与上例比较,此时D盘的当前目录已经变为“D:\temp”,但是缺省驱动器还是C。 |
3、ChDrive 语句 |
语法:ChDrive drive |
功能:改变当前的驱动器。 |
说明:如果使用零长度的字符串 ( "" ),则当前的驱动器将不会改变。如果 drive 参数中有多个字符,则 ChDrive 只会使用首字母。 |
示例: |
ChDrive "D" |
ChDir "D:\temp" |
Debug.Print CurDir ' 返回“D:\temp”。 |
Debug.Print CurDir( "D" ) ' 返回“D:\temp”。 |
与上例比较,用CurDir返回的是“D:\temp”,当前驱动器已经变为D了。 |
4、Dir 函数 |
语法:Dir[(pathname[, attributes])] |
两个参数都是可选的,attributes表示文件属性。 |
功能:返回一个文件名、目录名或文件夹名称,它必须与指定的模式或文件属性、或磁盘卷标相匹配。 |
说明:在第一次调用 Dir 函数时,必须指定 pathname,否则会产生错误。如果也指定了文件属性,那么就必须包括 pathname。 |
Dir 会返回匹配 pathname 的第一个文件名。若想得到其它匹配 pathname 的文件名,再一次调用 Dir,且不要使用参数。如果已没有合乎条件的文件,则 Dir 会返回一个零长度字符串 ( "" )。一旦返回值为零长度字符串,并要再次调用 Dir 时,就必须指定 pathname,否则会产生错误。不必访问到所有匹配当前 pathname 的文件名,就可以改变到一个新的 pathname 上。但是,不能以递归方式来调用 Dir 函数。以 vbDirectory 属性来调用 Dir 不能连续地返回子目录。 |
示例: |
Debug.Print Dir( "F:\TEST.xls" ) ’返回 "TEST.xls" |
Debug.Print Dir( "F:\*.xls" ) ’返回按条件第一个找到的文件名。 |
Debug.Print Dir( "F:\*.txt" ,vbReadOnly) ’返回第一个只读的txt文件 |
以下过程可显示C盘根目录下的所有目录. |
Sub DirC() |
MyPath = "c:\" |
MyName = dir(MyPath, vbDirectory) ' 找寻第一项。 |
Do While MyName <> "" ' 开始循环。 |
' 跳过当前的目录及上层目录。 |
If MyName <> "." And MyName <> ".." Then |
' 使用位比较来确定 MyName 代表一目录。 |
If (GetAttr(MyPath & MyName) And vbDirectory) = vbDirectory Then |
Debug.Print MyName ' 如果它是一个目录,将其名称显示出来。 |
End If |
End If |
MyName = dir ' 查找下一个目录。 |
Loop |
End Sub |
以下过程利用递归可以查找目录和子目录下的所有文件。 |
Public Sub FindFile(mPath As String , Optional sFile As String = "" ) |
On Error Resume Next |
Dim s As String , sDir() As String |
Dim i As Long , d As Long |
If Right(mPath, 1) <> "\" Then |
mPath = mPath & "\" |
End If |
'查找目录下的文件 |
s = dir(mPath & sFile, vbArchive + vbDirectory + vbHidden + vbNormal + vbReadOnly + vbSystem) |
Do While s <> "" |
Debug.Print mPath & s |
s = dir |
Loop |
'查找目录下的子目录 |
s = dir(mPath, vbArchive + vbDirectory + vbHidden + vbNormal + vbReadOnly + vbSystem) |
Do While s <> "" |
If s <> "." And s <> ".." Then |
If (GetAttr(mPath & s) And vbDirectory) = vbDirectory Then |
d = d + 1 |
ReDim Preserve sDir(d) |
sDir(d) = mPath & s |
End If |
End If |
s = dir |
Loop |
'开始递归 |
For i = 1 To d |
FindFile sDir(d) & "\" |
Next |
End Sub |
5、MkDir 语句 |
语法:MkDir path |
功能:创建一个新的目录或文件夹。 |
说明:path 可以包含驱动器。如果没有指定驱动器,则 MkDir 会在当前驱动器上创建新的目录或文件夹。 |
示例: |
MkDir "MYDIR" '在当前目录建立新的目录或文件夹。 |
6、RmDir 语句 |
语法:RmDir path |
功能:删除一个存在的目录或文件夹。 |
说明:如果想要使用 RmDir 来删除一个含有文件的目录或文件夹,则会发生错误。在试图删除目录或文件夹之前,先使用 Kill 语句来删除所有文件。 |
示例: |
RmDir "MYDIR" ' 将 MYDIR 删除。 |
(三)处理文本文件 |
1、Open 语句 |
语法:Open pathname For mode [Access access] [lock] As [#]filenumber [Len=reclength] |
其中access、lock、reclength为可选参数,一般不用。 |
mode 指定打开文件的方式。有5种: |
Input:以输入方式打开,即读取方式。 |
Output:以输出方式打开,即写入方式。 |
Append:以追加方式打开,即添加内容到文件末尾。 |
Binary:以二进制方式打开。 |
Random:以随机方式打开,如果未指定方式,则以 Random 方式打开文件。 |
filenumber 是一个有效的文件号,范围在 1 到 511 之间。可以指定,也可使用 FreeFile 函数可得到下一个可用的文件号。 |
说明:如果 pathname 指定的文件不存在,那么,在用 Append、Binary、Output、或 Random 方式打开文件时,可以建立这一文件。 |
示例: |
Open "F:\TEST.txt" For Input As #1 '以输入方式打开 |
Open "F:\TEST.xls" For Binary As #1 '以二进制方式打开 |
2、Close 语句 |
语法:Close [filenumberlist] |
filenumberlist 参数为一个或多个文件号,若省略 filenumberlist,则将关闭 Open 语句打开的所有活动文件。 |
说明:打开文件后,必须在使用完后关闭文件。 |
示例: |
Dim I, FileName |
For I = 1 To 3 |
FileName = "TEST" & I ' 创建文件名。 |
Open FileName For Output As #I ' 打开文件。 |
Print #I, "This is a test." ' 将字符串写入文件。 |
Next I |
Close ' 将三个已打开的文件全部关闭。 |
3、Reset 语句 |
语法:Reset |
功能:关闭所有用 Open 语句打开的磁盘文件。 |
说明:Reset 语句关闭 Open 语句打开的所有活动文件,并将文件缓冲区的所有内容写入磁盘。 |
示例: |
Dim FileNumber |
For FileNumber = 1 To 5 |
Open "TEST" & FileNumber For Output As #FileNumber |
Write #FileNumber, "Hello World" ' 将数据写入文件。 |
Next FileNumber |
Reset ' 关闭文件并将缓冲区内的数据写到磁盘中。 |
4、FreeFile 函数 |
语法:FreeFile[(rangenumber)] |
参数 rangenumber指定一个范围,以便返回该范围之内的下一个可用文件号。指定 0(缺省值)则返回一个介于 1 – 255 之间的文件号。指定 1 则返回一个介于 256 – 511 之间的文件号。 |
功能:提供一个尚未使用的文件号。 |
示例: |
Dim fnum As Integer |
fnum = FreeFile |
Open "F:\TEST.txt" For Input As #fnum |
Close #fnum |
5、EOF 函数 |
语法:EOF(filenumber) |
功能:返回一个 Integer ,它包含 Boolean 值 True ,表明已经到达为 Random 或顺序 Input 打开的文件的结尾。 |
6、LOF 函数 |
语法:LOF(filenumber) |
功能:返回一个 Long ,表示用 Open 语句打开的文件的大小,该大小以字节为单位。 |
7、Loc 函数 |
语法:LOc(filenumber) |
功能:返回一个 Long ,在已打开的文件中指定当前读/写位置。 |
8、Input # 语句 |
语法:Input #filenumber, varlist |
功能:从已打开的顺序文件中读出数据并将数据指定给变量。 |
说明:通常用 Write # 将 Input # 语句读出的数据写入文件。为了能够用 Input # 语句将文件的数据正确读入到变量中,在将数据写入文件时,要使用 Write # 语句而不使用 Print # 语句。使用 Write # 语句可以确保将各个单独的数据域正确分隔开。 |
示例: |
本示例使用 Input # 语句将文件内的数据读入两个变量中。本示例假设 TESTFILE文件内含数行以 Write # 语句写入的数据;也就是说,每一行数据中的字符串部分都是用双引号括起来,而与数字用逗号隔开,例如,( "Hello" , 234)。 |
Dim MyString, MyNumber |
Open "TESTFILE" For Input As #1 ' 打开输入文件。 |
Do While Not EOF(1) ' 循环至文件尾。 |
Input #1, MyString, MyNumber ' 将数据读入两个变量。 |
Debug.Print MyString, MyNumber ' 在立即窗口中显示数据。 |
Loop |
Close #1 ' 关闭文件。 |
9、Write # 语句 |
语法:Write #filenumber, [outputlist] |
功能:将数据写入顺序文件。 |
说明:通常用 Input # 从文件读出 Write # 写入的数据。 |
如果省略 outputlist,并在 filenumber 之后加上一个逗号,则会将一个空白行打印到文件中。多个表达式之间可用空白、分号或逗号隔开。空白和分号等效。 |
用 Write # 将数据写入文件时将遵循几个通用的约定,使得无论什么区域都可用 Input # 读出并正确解释数据: |
·在写入数值数据时总使用句号作为十进制分隔符。 |
·对于 Boolean 类型的数据,或者打印 #TRUE# 或者打印 #FALSE#。无论在什么地区,都不将 True 和 False 这两个关键字翻译出来。 |
·使用通用的日期格式将 Date 类型的数据写入文件中。当日期或时间的部件丢失或为零时,只将现有部分写入文件中。 |
·如果 outputlist 的数据为 Empty,则不将任何数据写入文件。但对 Null 数据,则要写入 #NULL#。 |
·如果 outputlist 数据为 Null 数据,则将 #NULL# 写入文件中。 |
·对于 Error 类型的数据,输出看起来与 #ERROR errorcode# 一样。无论在什么地区,都不将关键字 Error 翻译出来。 |
与 Print # 语句不同,当要将数据写入文件时,Write # 语句会在项目和用来标记字符串的引号之间插入逗号。没有必要在列表中键入明确的分界符。Write # 语句在将 outputlist 中的最后一个字符写入文件后会插入一个新行字符,即回车换行符,(Chr(13) + Chr(10))。 |
示例: |
Open "F:\test.txt" For Output As #1 ' 打开输出文件。 |
Write #1, "Hello World" , 1234 ' 写入以逗号隔开的数据。 |
Write #1, ' 写入空白行。 |
Dim MyBool, MyDate, MyNull, MyError |
' 赋值 Boolean、Date、Null 及 Error 等。 |
MyBool = False : MyDate = #February 12, 1969# : MyNull = Null |
MyError = CVErr(32767) |
' Boolean 数据以 #TRUE# 或 #FALSE# 的格式写入。 |
' 日期以通用日期格式写入,例如:#1994-07-13# 代表 |
' 1994 年 1 月 13 日。Null 数据以 #NULL# 格式写入。 |
' Error 数据以 #ERROR 错误代号# 的格式写入。 |
Write #1, MyBool; " is a Boolean value" |
Write #1, MyDate; " is a date" |
Write #1, MyNull; " is a null value" |
Write #1, MyError; " is an error value" |
Close #1 ' 关闭文件。 |
我们可以看到写入的内容为: |
"Hello World" ,1234 |
#FALSE#," is a Boolean value" |
#1969-02-12#," is a date" |
#NULL#," is a null value" |
#ERROR 32767#," is an error value" |
10、Line Input # 语句 |
语法:Line Input #filenumber, varname |
功能:从已打开的顺序文件中读出一行并将它分配给 String 变量。 |
说明:通常用 Print # 与 Line Input # 语句配合使用。 |
Line Input # 语句一次只从文件中读出一个字符,直到遇到回车符 (Chr(13)) 或回车–换行符 (Chr(13) + Chr(10)) 为止。回车–换行符将被跳过,而不会被附加到字符串上。 |
示例: |
Dim TextLine |
Open "TESTFILE" For Input As #1 ' 打开文件。 |
Do While Not EOF(1) ' 循环至文件尾。 |
Line Input #1, TextLine ' 读入一行数据并将其赋予某变量。 |
Debug.Print TextLine ' 在立即窗口中显示数据。 |
Loop |
Close #1 ' 关闭文件。 |
11、Input 函数 |
语法:Input(number, [#]filenumber) |
其中number 指定要返回的字符个数。 |
功能:返回 String ,它包含以 Input 或 Binary 方式打开的文件中的字符。 |
说明:通常用 Print # 或 Put 将 Input 函数读出的数据写入文件。Input 函数只用于以 Input 或 Binary 方式打开的文件。 |
与 Input # 语句不同,Input 函数返回它所读出的所有字符,包括逗号、回车符、空白列、换行符、引号和前导空格等。 |
示例: |
Dim MyChar |
Open "f:\test.txt" For Input As #1 |
Do While Not EOF(1) ' 循环至文件尾。 |
MyChar = Input(1, #1) ' 读入一个字符。 |
Debug.Print MyChar ' 显示到立即窗口。 |
Loop |
Close #1 |
下面这个函数可以将文本文件的数据一次读入到一个字符串(但是若包含中文时会出错,因为一个中文字占2个字节)。 |
Public Function ReadText(FileName As String ) |
Dim fnum%, isopen As Boolean |
On Error GoTo erro |
fnum = FreeFile() |
Open FileName For Input As #fnum |
isopen = True |
ReadText = Input(LOF(fnum), fnum) |
erro: |
If isopen Then Close #fnum |
If err Then Debug.Print err.Number, err.Description |
End Function |
12、Print # 语句 |
语法:Print #filenumber, [outputlist] |
outputlist 参数的设置如下: |
[{Spc(n) | Tab[(n)]}] [expression] [charpos] |
Spc(n) 用来在输出数据中插入空白字符,而 n 指的是要插入的空白字符数。 |
Tab(n) 用来将插入点定位在某一绝对列号上,这里,n 是列号。使用无参数的 Tab 将插入点定位在下一个打印区的起始位置。 |
expression 要打印的数值表达式或字符串表达式。 |
charpos 指定下一个字符的插入点。使用分号将插入点定位在上一个显示字符之后。用 Tab(n) 将插入点定位在某一绝对的列号上,用无参数的 Tab 将插入点定位在下一个打印区的起始处。如果省略 charpos,则在下一行打印下一个字符。 |
功能:将格式化显示的数据写入顺序文件中。 |
说明:通常用 Line Input # 或 Input 读出 Print # 在文件中写入的数据。 |
示例: |
Open "F:\test.txt" For Output As #1 ' 打开输出文件。 |
Print #1, "This is a test" ' 将文本数据写入文件。 |
Print #1, ' 将空白行写入文件。 |
Print #1, "Zone 1" ; Tab; "Zone 2" ' 数据写入两个区(print zones)。 |
Print #1, "Hello" ; " " ; "World" ' 以空格隔开两个字符串。 |
Print #1, Spc(5); "5 leading spaces " ' 在字符串之前写入五个空格。 |
Print #1, Tab(10); "Hello" ' 将数据写在第十列。 |
' 赋值 Boolean、Date、Null 及 Error 等。 |
Dim MyBool, MyDate, MyNull, MyError |
MyBool = False : MyDate = #2/12/1969#: MyNull = Null |
MyError = CVErr(32767) |
' True、False、Null 及 Error 会根据系统的地区设置自动转换格式。 |
' 日期将以标准的短式日期的格式显示。 |
Print #1, MyBool; " is a Boolean value" |
Print #1, MyDate; " is a date" |
Print #1, MyNull; " is a null value" |
Print #1, MyError; " is an error value" |
Close #1 |
以上代码写入的内容如下: |
This is a test |
Zone 1 Zone 2 |
Hello World |
5 leading spaces |
Hello |
False is a Boolean value |
1969-2-12 is a date |
Null is a null value |
Error 32767 is an error value |
13、Width # 语句 |
语法:Width #filenumber, width |
width 必要。范围在 0–255 之间的数值表达式,在新的一行开始之前,指出在该行上可出现多少字符。如果 width 等于 0,则行的长度不受限制。width 的缺省值为 0。 |
功能:将一个输出行的宽度指定给用 Open 语句打开的文件。 |
示例: |
Dim I |
Open "f:\TESTFILE.txt" For Output As #1 |
Width #1, 5 ' 设置输出行宽为 5。 |
For I = 0 To 9 ' 循环 10 次。 |
Print #1, Chr(48 + I); ' 每行输出五个字符。 |
Next I |
Close #1 |
以上代码写入的内容如下: |
01234 |
56789 |
(四)处理二进制文件 |
打开二进制文件可以使用Open语句的Random和Binary方式打开。二进制文件读写使用 Get 和Put语句。 |
1、Put 语句 |
语法:Put [#]filenumber, [recnumber], varname |
recnumber 可选。 Variant ( Long )。记录号(Random 方式的文件)或字节数(Binary 方式的文件),指明在此处开始写入。 |
说明:通常用 Get 将 Put 写入的文件数据读出来。 |
示例: |
Dim num As Long , text As String |
num = 12345 |
text = "a string" |
Open "f:\data.bin" For Binary As #1 '打开或创建一个二进制文件 |
Put #1, , num '写入4个字节 |
Put #1, , text '写入8个字节(字符串长为8) |
Close #1 |
2、 Get 语句 |
语法: Get [#]filenumber, [recnumber], varname |
recnumber 可选。 Variant ( Long )。记录号(Random 方式的文件)或字节数(Binary 方式的文件),以表示在此处开始读出数据。 |
功能:将一个已打开的磁盘文件读入一个变量之中。 |
说明:通常用 Put 将 Get 读出的数据写入一个文件。 |
示例:读取以上代码写入的内容 |
Dim num As Long , text As String |
Open "f:\data.bin" For Binary As #1 |
Get #1, , num |
text = Space$(8) '准备8个字节的字符串 |
Get #1, , text '读入 |
Debug.Print num, text |
Close #1 |
在立即窗口可以看到如下内容: |
12345 a string |
3、Seek 语句 |
语法:Seek [#]filenumber, position |
其中position 为介于 1~ 2,147,483,647(相当于 2^31 – 1)之间的数字,指出下一个读写操作将要发生的位置。 |
功能:在 Open 语句打开的文件中,设置下一个读/写操作的位置。 |
说明:可以用Seek语句指定 Get 语句的读取位置,但在 Get 及 Put 语句中指定的记录号将覆盖由 Seek 语句指定的文件位置。 |
示例: |
Dim MaxSize, NextChar, MyChar |
Open "TESTFILE" For Input As #1 |
MaxSize = LOF(1) ' 取得文件的总字符数。 |
' 用循环读入所有记录,但是从最后的记录开始往前读。 |
For NextChar = MaxSize To 1 Step -1 |
Seek #1, NextChar ' 设置读写位置。 |
MyChar = Input(1, #1) ' 读入一字符。 |
Next NextChar |
Close #1 |
4、Seek 函数 |
语法:Seek(filenumber) |
功能:返回一个 Long ,在 Open 语句打开的文件中指定当前的读/写位置。 |
说明:在使用 Get 语句读取文件时,必须用LOF函数来判断是否到达文件末尾,而不是用EOF函数。可以使用Seek函数判断当前位置,然后与LOF的值比较。 |
示例: |
Do While Seek(1) < LOF(1) |
'继续读取 |
...... |
Loop |
(五)总结 |
VBA语句的文件操作涵盖了文件操作的绝大部分内容,很多函数的使用也很简单,一般的文件读写也非常方便,特别是对文本文件。但对于复杂的文件读写,代码 的结构和维护性都不好。因此在VB6之后,微软引入了FileSystemObject对象模型,提供了面向对象的类库,来操作驱动器、文件夹和文件。但 对于二进制文件的操作,目前还只能用VBA语句。 |
Excel文件本身就是二进制文件,它使用的文件格式叫做BIFF(Binary Interchange File Format),即二进制可交换文件格式(但2007开始使用OOXML格式)。关于其内部的结构,本人也在研究中。以二进制结构打开Excel文件,不 但可以读取其表格中的数据,还可以读取其所有的信息(包括密码)。注意,以Open语句打开文件,并不是我们通常的双击一个文件打开显示到屏幕上,而是将 其存放在磁盘上的数据读入到缓冲区,不是可视化的打开。这种打开是不需要密码的,即使你的Excel文件设置了打开密码,还是照打开不误,这也正是 Excel文件不安全的根源所在。我以前发过一篇关于破解的文章,里面破解VBA工程密码的方法就是用二进制替换。由于论坛不让讨论破解的话题,这里就不 再详细分析代码了,感兴趣的请自行研究。当然,Excel的其他密码也是可类似破解的,前提是你必须十分了解Excel的内部结构,知道密码放在哪里,才 能替换。知道的解密的方法,自然可以针对性的改进加密的方法。好了,这里就不再罗嗦了,如果对Excel的内部结构感兴趣,可以先看这篇文章,看懂再说。 |
http://club.excelhome.net/dispbbs.asp?BoardID=2&ID=227502&replyID=&skin=0 |
Excel-VBA操作文件四大方法之三 |
三、利用FileSystemObject对象来处理文件 |
FileSystemObject对象模型,是微软提供的专门用来访问计算机文件系统的,具有大量的属性、方法和事件。其使 用面向对象的“object.method”语法来处理文件夹和文件,使用起来十分方便(需Office 2000以后版本)。FileSystemObject并不是VBA的一部分,它是以一个COM组件的形式提供的。因此,要使用先要创建 FileSystemObject对象。 |
FileSystemObject对象模型包含了下面的对象和集合: |
·FileSystemObject 主对象,包含用来创建、删除和获得有关信息,以及用来操作驱动器、文件夹和文件的方法和属性。 |
·Drive 对象,包含用来获得信息的方法和属性,这些信息是关于连接在系统上的驱动器的,如有多少可用空间等。驱动器不一定是硬盘,也可以是CD-ROM、U盘甚至是通过网络在逻辑上连接的硬盘(如公司里部门共享的服务器网络硬盘)。 |
·Drives 集合,提供驱动器的列表,这些驱动器以实物或在逻辑上与系统相连接。Drives集合包括所有驱动器,与类型无关。 |
·File 对象,包含用来创建、删除或移动文件的方法和属性。 |
·Files 集合,提供包含在文件夹内的所有文件的列表。 |
·Folder 对象,包含用来创建、删除或移动文件夹的方法和属性。 |
·Folders 集合,提供包含在文件夹内的所有文件夹的列表。 |
·TextStream 对象,用来读写文本文件。 |
(一)准备工作 |
要使用FileSystemObject对象,先要创建它。创建FileSystemObject对象要使用CreatObject函数。CreateObject 函数用来创建并返回一个对 ActiveX 对象的引用。 |
语法:CreateObject(class,[servername]) |
class 是要创建的应用程序名称和类。 |
servername 要在其上创建对象的网络服务器名称。(如果要在远程计算机上创建对象才用) |
class 参数使用 appname.objecttype 这种语法,包括以下部分: |
appname 必需的;提供该对象的应用程序名。 |
objecttype 必需的;待创建对象的类型或类。 |
因此,我们用下面的代码创建FileSystemObject对象: |
Dim fso As Object |
Set fso = CreateObject( "Scripting.FileSystemObject" ) |
Scripting是类型库的名称,FileSystemObject就是要创建的对象的名字。 |
同样我们可以创建Dictionary 对象如下: |
Dim d |
Set d = CreateObject( "Scripting.Dictionary" ) |
(二)FileSystemObject对象的方法 |
FileSystemObject对象模型中有些功能是重复的,如可用FileSystemObject对象的CpoyFile方法,也可用File对象的Copy方法来复制文件。下面先介绍FileSystemObject对象的方法。 |
1、GetDrive 方法 |
语法:object.GetDrive drivespec |
drivespec参数可以是一个驱动器字符(c)、一个驱动器字符加一个冒号(c:)、一个驱动器字符加冒号和路径分隔符(c:\)或任何网络共享的说明(\\computer2\share1)。 |
作用:返回一个与指定路径中的驱动器相对应的 Drive 对象。 |
示例: |
Dim d |
Set d = fso.GetDrive( "D:" ) '变量d就代表了驱动器D对象 |
如果 drivespec 不符合任何一种可以接受的形式或者不存在,则发生一个错误。 |
注意:为简洁,示例中都假定fso是已经创建的FileSystemObject对象 |
2、GetDriveName 方法 |
语法:object.GetDriveName(path) |
作用:返回一个包含指定路径的驱动器名字的字符串。 |
示例: |
Debug.Print fso.GetDriveName( "c:\test.txt" ) '立即窗口显示"c:" |
3、GetExtensionName 方法 |
语法:object.GetExtensionName(path) |
作用:返回一个包含路径中最后部件扩展名的字符串。 |
示例: |
Debug.Print fso.GetExtensionName( "c:\test.txt" ) '立即窗口显示"txt" |
4、GetBaseName 方法 |
语法:object.GetBaseName(path) |
作用:返回一个包含路径中最后部件的基本名字(去掉任何文件扩展名)的字符串。 |
示例: |
Debug.Print fso.GetBaseName( "c:\abc\test.txt" ) '立即窗口显示"test" |
5、GetAbsolutePathName 方法 |
语法:object.GetAbsolutePathName(pathspec) |
作用:从提供的路径说明中返回一个完整、明确的路径。 |
示例: |
如果pathspec为空字符串 "" ,则返回当前路径。假设当前路径为C:\Documents and Settings\yc\My Documents |
Debug.Print fs.GetAbsolutePathName( "" ) '显示C:\Documents and Settings\yc\My Documents |
Debug.Print fs.GetAbsolutePathName( "c:.." ) '显示C:\Documents and Settings\yc,即上层目录 |
Debug.Print fs.GetAbsolutePathName( "abc" ) '显示C:\Documents and Settings\yc\My Documents\abc |
Debug.Print fs.GetAbsolutePathName( "c:\test.txt" ) '显示C:\test.txt |
6、GetFile 方法 |
语法:object.GetFile(filespec) |
作用:返回一个和指定路径中文件相对应的 File 对象。 |
示例: |
Dim f |
Set f = fso.GetFile( "c:\test.txt" ) '变量f就代表了文件test.txt对象 |
注意:如果指定的文件不存在,则发生一个错误。 |
7、GetFileName 方法 |
语法:object.GetFileName(pathspec) |
作用:返回指定路径中的最后部件,该路径不是驱动器说明的一部分。 |
示例: |
Debug.Print fso.GetFileName( "c:\abc\test.txt" ) '立即窗口显示"test.txt" |
8、GetFolder 方法 |
语法:object.GetFolder(folderspec) |
作用:返回一个和指定路径中文件夹相对应的 Folder 对象。 |
示例: |
Dim fd |
Set fd = fso.GetFolder( "c:\windows" ) '变量f就代表了文件夹windows对象 |
注意:如果指定的文件夹不存在,则发生一个错误。 |
9、GetSpecialFolder 方法 |
语法:object.GetSpecialFolder(folderspec) |
作用:返回指定的特殊文件夹。 |
说明: |
folderspec 参数可为任何的下列值: |
WindowsFolder 0 Windows 文件夹,包含由 Windows 操作系统安装的文件。 |
SystemFolder 1 系统文件夹,包含库、字体、设备驱动程序。 |
TemporaryFolder 2 Temp 文件夹,用于存储临时文件。它的路径在 TMP 环境变量中。 |
10、GetParentFolderName 方法 |
语法:object.GetParentFolderName(path) |
作用:返回一个包含指定路径最后部件父文件夹名字的字符串。 |
示例: |
Debug.Print fso.GetParentFolderName( "c:\tmp\test.txt" ) '显示"c:\tmp" |
11、GetTempName 方法 |
语法:object.GetTempName |
作用:返回一个随机产生的临时文件或文件夹的名字,该名字在执行需要临时文件或文件夹的操作时有用。 |
说明:GetTempName 方法不产生一个文件,它仅提供一个临时文件名字,该名字可被 CreateTextFile 用于创建一个文件。 |
示例: |
Debug.Print fso.GetTempName '显示"radB0208.tmp",每次都会变。 |
12、BuildPath 方法 |
语法:object.BuildPath(path, name) |
作用:追加一个名字到一个已经存在的路径。 |
示例: |
Debug.Print fso.BuildPath( "c:\tmp" , "abc" ) '显示"c:\tmp\abc" |
13、CreateFolder 方法 |
语法:object.CreateFolder(foldername) |
作用:创建一个文件夹。 |
注意:如果指定的文件夹已经存在,则发生一个错误。 |
示例: |
fso.CreateFolder( "c:\myfolder" ) '在C盘创建一个myfolder文件夹 |
14、CopyFolder 方法 |
语法:object.CopyFolder source, destination[, overwrite] |
source 必需的。指明一个或多个被复制文件夹的字符串文件夹说明,可以包括通配符。 |
destination 必需的。指明 source 中被复制文件夹和子文件夹的接受端的字符串,不允许有通配符。 |
overwrite 可选的。 Boolean 值,它表示已存在的文件夹是否被覆盖。如果为 True ,文件被覆盖。如果为 False ,文件不被覆盖。缺省值为 True 。 |
作用:复制一个文件夹到另一个地方。 |
说明: |
① 通配符仅可用于 source 参数的最后一个路径部件。 |
例如:fso.CopyFolder "c:\mydocuments\letters\*" , "c:\tempfolder\" 这是可以的。 |
但不能这样:fso.CopyFolder "c:\mydocuments\*\*" , "c:\tempfolder\" |
② 如果 source 包含通配符或 destination 以路径分隔符(\)为结尾,则认为 destination 是一个已存在的文件夹,在其中复制相匹配的文件夹和子文件夹。否则认为 destination 是一个要创建的文件夹的名字。 |
例如:fso.copyfolder "c:\tmp" , "f:\abc\" |
如果F盘没有abc文件夹,将发生错误。如果存在,可看到abc文件夹里有tmp文件夹。 |
假如写成这样:fso.copyfolder "c:\tmp" , "f:\abc" |
此时若abc不存在,将创建abc文件夹,且将tmp文件夹里的内容复制到abc文件夹里,而不是tmp文件夹,只有abc是一个已经存在的文件夹时,才复制整个tmp文件夹到abc文件夹里。 |
③如果 destination 是一个已存在的文件,则发生一个错误。 |
④如果 destination 是一个目录,它将尝试复制文件夹和它所有的内容。如果一个包含在 source 的文件已在 destination 中存在,当 overwrite 为 False 时发生一个错误,否则它将尝试覆盖这个文件。 |
⑤如果 destination 是一个只读目录,当尝试去复制一个已存在的只读文件到此目录并且 overwrite为 False 时,则发生一个错误。 |
⑥如果 source 不存在或使用的通配符不能和任何文件夹匹配,也发生一个错误。 |
⑦CopyFolder 方法停止在它遇到的第一个错误上,之前所做的操作是不会消失的,所以要注意。 |
15、MoveFolder 方法 |
语法:object.MoveFolder source, destination |
参数与CopyFolder的前两个一样。 |
作用:将一个或多个文件夹从一个地方移动到另一个地方。 |
说明: |
①只有在操作系统支持的情况下,这个方法才允许文件夹在卷之间移动。Windows是不允许的,将C盘的文件夹移到D盘是不行的。 |
②如果 source 包含通配符或 destination 以路径分隔符 (\) 为结尾,则认为 destination 指定了一个已存在的文件夹,在此文件夹中移动相匹配的文件。否则,认为 destination 是一个要创建的目标文件夹名字。这点与CopyFolder是一样的。 |
③如果 destination 是一个已存在的文件,则发生一个错误。 |
④如果 destination 是一个目录,则发生一个错误。 |
例如: |
fso.movefolder "c:\tmp" , "c:" '发生错误。 |
⑤如果 source 不存在或使用的通配符不能和任何文件夹匹配,也发生一个错误。 |
⑥MoveFolder 方法停止在它遇到的第一个错误上。不要尝试回卷在错误发生前所做的任何改变。 |
16、DeleteFolder 方法 |
语法:object.DeleteFolder folderspec[, force] |
folderspec 必需的。要删除的文件夹的名字。 Folderspec 可以在最后的路径部件中包含通配符。 |
force 可选的。 Boolean 值,如果要删除具有只读属性设置的文件夹,其值为 True ,如果值为 False (缺省),则不能删除具有只读属性设置的文件夹。 |
作用:删除一个指定的文件夹和它的内容。 |
说明:如果没有发现相匹配的文件夹,则发生一个错误。DeleteFolder 方法停止在它遇到的第一个错误上,不要尝试回卷或撤消错误发生前所做的任何改变。 |
示例: |
fso.DeleteFolder( "c:\tmp" ) |
17、FolderExists 方法 |
语法:object.FolderExists(folderspec) |
作用:如果指定的文件夹存在返回 True ,不存在返回 False 。 |
18、DriveExists 方法 |
语法:object.DriveExists(drivespec) |
作用:如果指定的驱动器存在,返回 True ,如果不存在返回 False 。 |
19、FileExists 方法 |
语法:object.FileExists(filespec) |
作用:如果指定的文件存在,返回 True ,若不存在,则返回 False 。 |
20、CreateTextFile 方法 |
语法:object.CreateTextFile(filename[, overwrite[, unicode]]) |
overwrite 可选的。 Boolean 值,表示一个已存在文件是否可被覆盖。如果可被覆盖其值为 True ,其值为 False 时不能覆盖。如果它被省略,则已存在文件不能覆盖。 |
unicode 可选的。 Boolean 值,表示文件是作为一个 Unicode 文件创建的还是作为一个ASCII 文件创建的。如果作为一个 Unicode 文件创建,其值为 True ,作为一个 ASCII 文件创建,其值为 False 。如果省略的话,则认为是一个 ASCII 文件。 |
作用:创建一个指定的文件名并且返回一个用于该文件读写的 TextStream 对象。 |
示例: |
Dim f |
Set f = fso.CreateTextFile( "c:\testfile.txt" , True ) |
21、OpenTextFile 方法 |
语法:object.OpenTextFile(filename[, iomode[, create[, format]]]) |
作用:打开一个指定的文件并返回一个 TextStream 对象,该对象可用于对文件进行读、写、追加操作。 |
说明: |
·iomode 参数可为下面设置值中的任何值: |
ForReading 1 打开一个只读文件,不能对此文件进行写操作。 |
ForWriting 2 打开一个用于写操作的文件。如果和此文件同名的文件已存在,则覆盖以前内容。 |
ForAppending 8 打开一个文件并写到文件的尾部。 |
注意:在VBA帮助里是没有ForWriting的,其实是有的,VBA帮助也是有错误的。另外,这些常数在使用前要先声明,或者直接用数值。 |
·create 可选的,它表示如果指定的 filename 不存在是否可以创建一个新文件。如果创建新文件,其值为 True 。若不创建文件其值为 False 。缺省值为 False 。 |
·Format 参数可为下面设置值中的任何值: |
TristateUseDefault –2 使用系统缺省打开文件。 |
TristateTrue –1 以 Unicode 格式打开文件。 |
TristateFalse 0 以 ASCII 格式打开文件。 |
示例: |
Dim f |
Set f = fso.OpenTextFile( "c:\testfile.txt" , 2, True ) |
或者: |
Const ForWriting = 2 |
Set f = fso.OpenTextFile( "c:\testfile.txt" , ForWriting, True ) |
这两者功能是一样的,一个声明了常量,一个直接用数值。都是在C盘创建文件testfile.txt(如不存在),或以写的方式打开(如存在)。 |
22、CopyFile 方法 |
语法:object.CopyFile source, destination[, overwrite] |
作用:把一个或多个文件从一个地方复制到另一个地方。 |
说明:需要注意的地方与CopyFolder是完全类似的。 |
示例: |
fso.copyfile "c:\testfile.txt" , "f:\abc\" '若abc不存在则出错。 |
fso.copyfile "c:\testfile.txt" , "f:\abc" '若abc不存在则复制testfile.txt到F盘文件名变为abc,若abc存在,出错,因为是一个目录。 |
23、MoveFile 方法 |
语法:object.MoveFile source, destination |
作用:将一个或多个文件从一个地方移动到另一个地方。 |
说明:需要注意的地方与MoveFolder是完全类似的。 |
24、DeleteFile 方法 |
语法:object.DeleteFile filespec[, force] |
作用:删除一个指定的文件。 |
说明:force 可选的。如果要删除具有只读属性设置的文件,其值为 True 。如果其值为 False (缺省),则不能删除具有只读属性设置的文件。 |
(三)处理驱动器 |
可以利用Drive对象来获取有关各种驱动器的信息,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:\。 |
这些属性的使用都十分简单,直接用“对象.属性”就可以了。在使用前要先用GetDrive获得一个Drive对象,注意不能创建一个驱动器对象。下面举个例子: |
Sub ShowFreeSpace(drvPath) |
Dim fs, d, s |
Set fs = CreateObject( "Scripting.FileSystemObject" ) |
Set d = fs.Getdrive(fs.GetDriveName(drvPath)) |
s = "Drive " & UCase(drvPath) & "-" |
s = s & d.VolumeName & vbCrLf |
s = s & "Free Space: " & FormatNumber(d.FreeSpace / 1024, 0) |
s = s & " Kbytes" |
MsgBox s |
End Sub |
利用 Call ShowFreeSpace( "c:" ),即可获得C盘的卷标名和可用空间。 |
(四)处理文件夹 |
1、获取文件夹的信息 |
可以利用Folder对象来获取有关文件夹的信息,Folder对象的属性有: |
Attributes 属性 文件夹的属性。可为下列值中的任意一个或任意的逻辑组合: |
Normal 0 一般文件。未设置属性。 |
ReadOnly 1 只读文件。属性为读/写。 |
Hidden 2 隐藏文件。属性为读/写。 |
System 4 系统文件。属性为读/写。 |
Volume 8 磁盘驱动器卷标。属性为只读。 |
Directory 16 文件夹或目录。属性为只读。 |
Archive 32 自上次备份后已经改变的文件。属性为读/写。 |
Alias 64 链接或快捷方式。属性为只读。 |
Compressed 128 压缩文件。属性为只读。 |
Name 属性 文件夹名字。 |
ShortName 属性 较早的 8.3 命名约定的程序所使用的短名字。 |
Type 属性 文件夹类型。 |
Files 属性 所有 File 对象组成的 Files 集合,这些 File 对象包含在指定的文件夹中 |
──包括设置了隐藏和系统文件属性的那些文件。 |
Drive 属性 文件夹所在的驱动器符号。 |
IsRootFolder 属性 文件夹是否是根文件夹。 |
ParentFolder 属性 文件夹的父文件夹对象。 |
SubFolders 属性 文件夹的子文件夹集合。 |
Path 属性 文件夹的路径。 |
ShortPath 属性 较早的 8.3 文件命名约定的程序所使用的短路径。 |
Size 属性 文件夹的大小,以字节为单位。 |
DateCreated 属性 文件夹的创建日期和时间。 |
DateLastModified 属性 最后一次修改文件夹的日期和时间。 |
DateLastAccessed 属性 最后一次访问文件夹的日期和时间。 |
属性的使用和Drive对象是一样的,可以用GetFolder获取一个Folder对象,也可以用FileSystemObject对象的CreateFolder 方法创建一个Folder对象。 |
2、Folder对象的方法 |
⑴Copy 方法 |
语法:object.Copy destination[, overwrite] |
作用:把一个指定的文件夹从一个地方复制到另一个地方。 |
说明:Copy 方法的作用与FileSystemObject对象的CopyFolder 方法是一样的,不同在于后者可一次复制多个文件夹。 |
⑵Move 方法 |
语法:object.Move destination |
作用:将一个指定的文件夹从一个地方移动到另一个地方。 |
说明:Move 方法的作用与FileSystemObject.MoveFolder 是一样的。不同在于后者可一次移动多个文件夹。 |
⑶Delete 方法 |
语法:object.Delete force |
作用:删除一个指定的文件夹。 |
说明:Delete 方法的作用与FileSystemObject.DeleteFolder 是一样的。 |
⑷CreateTextFile 方法 |
语法:object.CreateTextFile(filename[, overwrite[, unicode]]) |
作用:与FileSystemObject对象的CreateTextFile 方法是一样的。 |
示例: |
Set fd = fs.getfolder( "c:\tmp" ) |
Set f = fd.CreateTextFile( "testfile.txt" , True ) |
可在C盘tmp文件夹下创建testfile.txt文件。 |
(五)处理文件 |
1、获取文件的信息 |
可以利用File对象来获取有关文件的信息,File对象的属性和Folder的属性是完全一样的,只是少了Files 属性、IsRootFolder 属性、SubFolders 属性这3个属性。这里就不列了。 |
2、File对象的方法 |
⑴Copy 方法 |
⑵Move 方法 |
⑶Delete 方法 |
以上三种方法与Folder的是完全类似的,语法也一样,同样也可用FileSystemObject对象相应的方法代替。 |
⑷OpenAsTextStream 方法 |
语法:object.OpenAsTextStream([iomode, [format]]) |
作用:打开一个指定的文件并返回一个 TextStream 对象,该对象可用来对文件进行读、写、追加操作。 |
说明:此方法与FileSystemObject对象的 OpenTextFile 方法相同的功能。参数也是一致的。 |
(六)处理文本文件 |
1、打开或创建文本文件 |
打开现有的文本文件,可以使用FileSystemObject对象的 OpenTextFile 方法或File对象的OpenAsTextStream 方法。 |
创建文件可以使用FileSystemObject对象的 CreatTextFile 方法或在OpenTextFile 方法中将iomode参数设为ForWriting=2,create参数设为 True 。 |
例如: |
Set f = fso.OpenTextFile( "c:\test1.xls" , 2, True ) '如果不存在test1.xls将自动创建。 |
2、读取文件 |
打开文件后,将返回一个TextStream 对象,我们可以利用TextStream 对象的属性及方法来对文件进行读写操作。 |
先看TextStream 对象的几个属性。 |
·AtEndOfLine 属性 文件指针是否正好在行尾标记的前面 |
·AtEndOfStream 属性 文件指针是否在 TextStream 文件末尾 |
·Column 属性 TextStream 文件中当前字符位置的列号 |
·Line 属性 TextStream 文件中的当前行号 |
利用TextStream 对象读取文件有三种方法。 |
·Read 方法 |
语法:object.Read(characters) |
功能:从一个 TextStream 文件中读取指定数量的字符并返回得到的字符串。 |
示例: |
Sub du() |
Dim fso, a, retstring |
Const ForReading = 1 |
Set fso = CreateObject( "Scripting.FileSystemObject" ) |
Set a = fso.OpenTextFile( "c:\testfile.txt" , ForReading, False ) |
Do While a.AtEndOfLine <> True '是否到行末 |
retstring = retstring & a.Read(1) '读取一个字符 |
Loop |
a.Close |
Debug.Print retstring '可看到读取了第一行的字符 |
End Sub |
·ReadLine 方法 |
语法:object.ReadLine |
功能:从一个 TextStream 文件读取一整行(到换行符但不包括换行符)并返回得到的字符串。 |
示例: |
Sub du_line() |
Dim fso, a, retstring |
Const ForReading = 1 |
Set fso = CreateObject( "Scripting.FileSystemObject" ) |
Set a = fso.OpenTextFile( "c:\testfile.txt" , ForReading, False ) |
Do While a.AtEndOfStream <> True '是否在 TextStream 文件末尾 |
retstring = a.ReadLine '读取一行 |
Debug.Print retstring '显示在立即窗口 |
Loop |
a.Close |
End Sub |
·ReadAll 方法 |
语法:object.ReadAll |
功能:读取整个的 TextStream 文件并返回得到的字符串。 |
说明:对于大的文件,使用ReadAll方法浪费内存资源。应使用其它的技术去输入一个文件,比如按行读取文件。 |
示例: |
Sub du_all() |
Dim fso, a, retstring |
Const ForReading = 1 |
Set fso = CreateObject( "Scripting.FileSystemObject" ) |
Set a = fso.OpenTextFile( "c:\testfile.txt" , ForReading, False ) |
retstring = a.Readall '全部读取 |
Debug.Print retstring |
a.Close |
End Sub |
还有两个辅助读取的方法: |
·Skip 方法 |
语法:object.Skip(characters) |
功能:当读一个 TextStream 文件时跳过指定数量的字符。 |
示例: |
Sub duskip() |
Dim fso, a, retstring |
Const ForReading = 1 |
Set fso = CreateObject( "Scripting.FileSystemObject" ) |
Set a = fso.OpenTextFile( "c:\testfile.txt" , ForReading, False ) |
Do While a.AtEndOfLine <> True '是否到行末 |
retstring = retstring & a.Read(1) '读取一个字符 |
a.Skip (1) '跳过一个字符 |
Loop |
a.Close |
Debug.Print retstring '可看到读取了第一行的奇数位的字符 |
End Sub |
·SkipLine 方法 |
语法:object.SkipLine |
功能:当读一个 TextStream 文件时跳过下一行。 |
3、写入数据到文件 |
写入数据到文件也有三种方法。 |
·Write 方法 |
语法:object.Write(string) |
功能:写一个指定的字符串到一个 TextStream 文件。 |
示例: |
Sub xie() |
Const ForWriting = 2, ForAppending = 8 |
Dim fs, f |
Set fs = CreateObject( "Scripting.FileSystemObject" ) |
Set f = fs.OpenTextFile( "c:\testfile.txt" , ForAppending,TristateFalse) |
f.Write "Hello world!" '写入字符串 |
f.Close |
End Sub |
·WriteLine 方法 |
语法:object.WriteLine([string]) |
功能:写入一个指定的字符串和换行符到一个 TextStream 文件中。 |
示例: |
f.WriteLine( "Hello world!" ) '写入字符串,加一个换行符。 |
·WriteBlankLines 方法 |
语法:object.WriteBlankLines(lines) |
功能:写入指定数量的换行符到一个 TextStream 文件中。 |
示例: |
f.WriteBlankLines(3) '相当于按3次回车。 |
4、关闭文件 |
利用TextStream 对象的Close方法,上面的示例中已经有了,很简单。 |
(七)总结 |
从上面的介绍,我们看到使用FileSystemObject对象处理文件、文件夹比使用VBA语句的方法具有更容易存在的特点。这是因为 FileSystemObject对象使用了面向对象的语法。另外FileSystemObject对象处理文本文件毫不逊色于VBA语句,非常值得推 荐。唯一的问题是不能处理二进制文件,微软在有关文档中称计划将来支持二进制文件,不过应该只是计划而已,呵呵。 |
之四 |
四、利用API函数来处理文件 |
通过前面三种方法的介绍,你是否已经觉得足够了?是的,前面的方法完全可以应付几乎所有的文件操作。但是为了普及一下API,展示一下API的魅力,最后向大家介绍一下如何利用API函数来处理文件。另一方面也是本人对API情有独钟,为她做一下广告,呵呵。 |
大家对API的强大也是有所耳闻了,在文件操作方面,API自然毫不逊色。 |
说明:为了文章简洁,我们先给出API函数的名称及功能,其完整的声明及常数就不再一一细诉,只在示例中给出其完整用法。 |
(一)处理驱动器及目录 |
下面是windows中提供的对于目录进行操作的API函数及其功能: |
CreateDirectory,CreateDirectoryEx 创建一个新目录 |
GetCurrentDirectory 在一个缓冲区中装载当前目录 |
GetDiskFreeSpace,GetDiskFreeSpaceEx 获取与一个磁盘的组织有关的信息,以及了解剩余空间的容量 |
GetDriveType 判断一个磁盘驱动器的类型 |
GetFullPathName 获取指定文件的完整路径名 |
GetLogicalDrives 判断系统中存在哪些逻辑驱动器字母 |
GetLogicalDriveStrings 获取一个字串,其中包含了当前所有逻辑驱动器的根驱动器路径 |
GetSystemDirectory 这个函数能取得Windows系统目录(System目录)的完整路径名。在这个目录中,包含了所有必要的系统文件。根据微软的标准,其他定制控件和一 些共享组件也可放到这个目录。通常应避免在这个目录里创建文件。在网络环境中,往往需要管理员权限才可对这个目录进行写操作 |
GetTempPath 获取为临时文件指定的路径 |
GetVolumeInformation 获取与一个磁盘卷有关的信息 |
GetWindowsDirectory 这个函数能获取Windows目录的完整路径名。在这个目录里,保存了大多数windows应用程序文件及初始化文件 |
RemoveDirectory 删除指定目录 |
SetCurrentDirectory 设置当前目录 |
SetVolumeLabel 设置一个磁盘的卷标(Label) |
下面通过几个例子来详细的了解一下其中主要的几个函数及其用法: |
1、GetLogicalDrives |
作用:判断系统中存在哪些逻辑驱动器字母 |
声明: Declare Function GetLogicalDrives Lib "kernel32" Alias "GetLogicalDrives" () As Long |
说明:此函数的返回值类型为 Long ,这个结构中的二进制位标志着存在哪些驱动器。其中,位0设为1表示驱动器A:存在于系统中;位1设为1表示存在B:驱动器;以次类推 |
示例: |
Public Sub Get_LogicalDrives() |
Dim LDs As Long , Cnt As Long , sDrives As String |
LDs = GetLogicalDrives |
sDrives = "Available drives:" |
For Cnt = 0 To 25 |
If (LDs And 2 ^ Cnt) <> 0 Then |
sDrives = sDrives + " " + Chr$(65 + Cnt) |
End If |
Next Cnt |
MsgBox sDrives |
End Sub |
上面的示例中,我们通过二进制运算,将返回值转换成字符。如果你的机上有C,D,E,F,G,H这几个驱动器,那么LDs的值就是252,转成二进制为11111100,从右往左,依次代表A,B,C,D,...,为0的说明没有此驱动器字母。大家可以自己试一试。 |
2、GetDriveType |
作用:判断一个磁盘驱动器的类型 |
声明: Declare Function GetDriveType Lib "kernel32" Alias "GetDriveTypeA" ( ByVal nDrive As String ) As Long |
说明:此函数的返回值类型为 Long ,如驱动器不能识别,则返回零。如指定的目录不存在,则返回1。如执行成功,则用下述任何一个常数指 定驱动器类型:DRIVE_REMOVABLE(表示磁盘可以从驱动器上移走,通常是软驱), DRIVE_FIXED(磁盘不能从驱动器上移走,通常为本地硬盘), DRIVE_REMOTE(驱动器是远程网络驱动器), DRIVE_CDROM(驱动器是CD-ROM驱动器) 或 DRIVE_RAMDISK(驱动器是RAM驱动器) |
参数为 String 类型,包含了驱动器根目录路径的一个字串 |
此函数的功能与FSO的Drive对象的DriveType属性是一样的。 |
示例: |
'定义常数变量 |
Private Const DRIVE_CDROM = 5 '表示光盘驱动器 |
Private Const DRIVE_FIXED = 3 '表示硬盘驱动器 |
Private Const DRIVE_RAMDISK = 6 '表示RAM驱动器 |
Private Const DRIVE_REMOTE = 4 '表示网络驱动器 |
Private Const DRIVE_REMOVABLE = 2 '表示软盘驱动器 |
Private Sub Get_DriveType() |
Dim temp As Long |
temp = GetDriveType("d:\") '取的d:盘驱动器类型 |
Select Case temp |
Case DRIVE_CDROM |
MsgBox "DRIVE_CDROM: 光盘驱动器" |
Case DRIVE_FIXED |
MsgBox "DRIVE_FIXED: 硬盘驱动器" |
Case DRIVE_RAMDISK |
MsgBox "DRIVE_RAMDISK: RAM驱动器" |
Case DRIVE_REMOTE |
MsgBox "DRIVE_REMOTE: 网络驱动器" |
Case DRIVE_REMOVABLE |
MsgBox "DRIVE_REMOVABLE: 软盘驱动器" |
End Select |
End Sub |
3、GetDiskFreeSpaceEx |
作用:获取与一个磁盘的组织以及剩余空间容量有关的信息 |
声明: Declare Function GetDiskFreeSpaceEx Lib "kernel32" Alias "GetDiskFreeSpaceExA" ( ByVal lpRootPathName As String , lpFreeBytesAvailableToCaller As LARGE_INTEGER, lpTotalNumberOfBytes As LARGE_INTEGER, lpTotalNumberOfFreeBytes As LARGE_INTEGER) As Long |
说明:此函数的返回值类型为 Long ,非零表示成功,零表示失败。会设置GetLastError. |
在采用FAT16格式的windows95系统中,如一个驱动器(分区)的容量超过了2GB,则不应使用这个函数。此时,这个函数能识别的最大分区容量只有2GB |
参数说明: |
lpRootPathName String ,不包括卷名的磁盘根路径名 |
lpFreeBytesAvailableToCaller LARGE_INTEGER,指定一个变量,用于容纳调用者可用的字节数量 |
lpTotalNumberOfBytes LARGE_INTEGER,指定一个变量,用于容纳磁盘上的总字节数 |
lpTotalNumberOfFreeBytes LARGE_INTEGER,指定一个变量,用于容纳磁盘上可用的字节数 |
LARGE_INTEGER结构用来代表一个64位带符号的整数值,它的定义如下: |
Type LARGE_INTEGER ' 8 Bytes |
lowpart As Long |
highpart As Long |
End Type |
其中lowpart为 Long ,指定低32位,highpart 为 Long ,指定高32位。 |
示例:虽然此函数能识别的最大分区容量只有2GB,但通过调整,对大于2G的仍然能得出正确容量。以下的调整公式是本人通过逆向推算出来的,至于其中的原理也不是很清楚,大家可一测试一下。 |
Private Sub Get_DiskFreeSpaceEx() |
Dim temp As Long , Dms$ |
Dim tempa, tempb, tempc |
Dim RootPathName As String |
Dim FreeBytesAvailabletoCaller As LARGE_INTEGER |
Dim TotalNumberOfBytes As LARGE_INTEGER |
Dim TotalNumberOfFreeBytes As LARGE_INTEGER |
RootPathName = "d:" |
'取得磁盘空间 |
temp = GetDiskFreeSpaceEx(RootPathName, FreeBytesAvailabletoCaller, TotalNumberOfBytes, TotalNumberOfFreeBytes) |
Dms = Dms + "磁盘容量:" + vbCrLf |
tempa = TotalNumberOfBytes.highpart * 2 ^ 32 + IIf(TotalNumberOfBytes.lowpart > 0, TotalNumberOfBytes.lowpart, TotalNumberOfBytes.lowpart + 2 ^ 32) '计算容量 |
Dms = Dms + CStr (tempa) + "字节" + vbCrLf |
tempa = Format(tempa / 1024 / 1024 / 1024, "0.00" ) |
Dms = Dms + tempa + "G" + vbCrLf |
'取得磁盘可用空间 |
Dms = Dms + "磁盘可用空间:" + vbCrLf |
tempb = TotalNumberOfFreeBytes.highpart * 2 ^ 32 + IIf(TotalNumberOfFreeBytes.lowpart > 0, TotalNumberOfFreeBytes.lowpart, TotalNumberOfFreeBytes.lowpart + 2 ^ 32) '计算 |
Dms = Dms + CStr (tempb) + "字节" + vbCrLf |
tempb = Format(tempb / 1024 / 1024 / 1024, "0.00" ) |
Dms = Dms + tempb + "G" + vbCrLf |
'取得磁盘已用空间 |
Dms = Dms + "磁盘已用空间:" + vbCrLf |
tempc = tempa - tempb |
Dms = Dms + CStr (tempc) + "G" + vbCrLf |
MsgBox Dms |
End Sub |
4、CreateDirectory, CreateDirectoryEx |
作用:创建一个新目录 |
声明: |
Declare Function CreateDirectory& Lib "kernel32" Alias "CreateDirectoryA" ( ByVal lpNewDirectory As String , lpSecurityAttributes As SECURITY_ATTRIBUTES) |
Declare Function CreateDirectoryEx& Lib "kernel32" Alias "CreateDirectoryExA" ( ByVal lpTemplateDirectory As String , ByVal lpNewDirectory As String , lpSecurityAttributes As SECURITY_ATTRIBUTES) |
说明:此函数的返回值类型为 Long ,非零表示成功,零表示失败。会设置GetLastError |
参数说明: |
lpTemplateDirectory String ,指定一个模板目录的名字,从中复制默认属性(比如目录中文件的默认压缩方式)。如设为vbNullString,则表示不使用模板 |
lpNewDirectory String ,新目录的名字 |
lpSecurityAttributes SECURITY_ATTRIBUTES,这个结构定义了目录的安全特性——如果操作系统支持的话 |
示例: |
Private Sub Create_Directory() |
Dim Security As SECURITY_ATTRIBUTES |
'创建目录 |
Ret& = CreateDirectory( "C:\Directory" , Security) |
'若返回0,则失败。 |
If Ret& = 0 Then MsgBox "Error : 创建失败!" , vbCritical + vbOKOnly |
End Sub |
5、RemoveDirectory |
作用:移除一个目录 |
声明: Declare Function RemoveDirectory Lib "kernel32" Alias "RemoveDirectoryA" ( ByVal lpPathName As String ) As Long |
说明:此函数的返回值类型为 Long ,非零表示成功,零表示失败。会设置GetLastError. |
在调用这个函数前,目录必须为空 |
参数说明: |
lpPathName 为 String 类型,要删除的那个目录的名字 |
示例: |
Private Sub Remove_Directory() |
Dim Security As SECURITY_ATTRIBUTES |
CreateDirectoryEx "C:\Windows" , "C:\Temp" , Security |
'移除目录 |
RemoveDirectory "C:\Temp" |
End Sub |
6、SetCurrentDirectory |
作用:设置当前目录,与VBA语句ChDir类似。 |
声明: Declare Function SetCurrentDirectory Lib "kernel32" Alias "SetCurrentDirectoryA" ( ByVal lpPathName As String ) As Long |
说明:此函数的返回值类型为 Long ,非零表示成功,零表示失败。会设置GetLastError |
参数说明: |
LpPathName String ,新当前目录的路径 |
示例: |
SetCurrentDirectory "d:\" '设置D:为当前目录 |
7、GetSystemDirectory |
作用:这个函数能取得Windows系统目录(System目录)的完整路径名。在这个目录中,包含了所有必要的系统文件。根据微软的标 准,其他定制控件和一些共享组件也可放到这个目录。通常应避免在这个目录里创建文件。在网络环境中,往往需要管理员权限才可对这个目录进行写操作 |
声明: Declare Function GetSystemDirectory Lib "kernel32" Alias "GetSystemDirectoryA" ( ByVal lpBuffer As String , ByVal nSize As Long ) As Long |
说明:此函数的返回值类型为 Long ,装载到lpBuffer缓冲区的字符数量。如lpBuffer不够大,不能容下文件名,则返回要求的缓冲区长度 |
参数说明: |
lpBuffer String ,用于装载系统目录路径名的一个字串缓冲区。它应事先初始化成nSize+1个字符的长度。通常至少要为这个缓冲区分配MAX_PATH个字符的长度 |
nSize Long ,lpBuffer字串的最大长度 |
示例: |
Private Sub Get_SystemDirectory() |
Dim sSave As String , Ret As Long |
'创建缓冲区 |
sSave = Space(255) |
'获取系统目录 |
Ret = GetSystemDirectory(sSave, 255) |
'移除多余的0 |
sSave = Left$(sSave, Ret) |
'显示路径 |
MsgBox "系统目录: " + sSave |
End Sub |
(二)处理文件 |
下面是windows中提供的对于文件进行操作的API函数及其功能: |
CloseHandle 关闭一个内核对象。其中包括文件、文件映射、进程、线程、安全和同步对象等。 |
CompareFileTime 根据FILETIME结构的信息,对比两个文件的时间 |
CopyFile 复制文件。注意:只能复制文件,而不能复制目录 |
CreateFile 这是一个全功能的函数,可打开和创建文件、管道、邮槽、通信服务、设备以及控制台 |
DeleteFile 删除指定文件 |
FindClose 关闭由FindFirstFile函数创建的一个搜索句柄 |
FindFirstFile 根据文件名查找文件 |
FindNextFile 根据调用FindFirstFile函数时指定的一个文件名查找下一个文件 |
FlushFileBuffers 针对指定的文件句柄,刷新内部文件缓冲区 |
GetBinaryType 判断文件是否可以执行 |
GetFileAttributes 判断指定文件的属性 |
GetFileInformationByHandle 该函数能够获取上面所有函数所能够获取的信息,如大小、属性等,同时还包括一些其他地方无法获取的信息,比如:文件卷标、索引和链接信息。 |
GetFileSize 判断文件长度 |
GetFileTime 取得指定文件的时间信息,有三个文件时间:创建时间、最后访问时间、最后写时间。 |
GetFileType 在给出文件句柄的前提下,判断文件类型 |
GetFileVersionInfo 从支持版本标记的一个模块里获取文件版本信息 |
GetFileVersionInfoSize 针对包含了版本资源的一个文件,判断容纳文件版本信息需要一个多大的缓冲区 |
GetFullPathName 获取文件路径,该函数获取文件的完整路径名。注意:只有当该文件在当前目录下, |
结果才正确。如果要得到真正的路径。应该用GetModuleFileName函数。 |
GetShortPathName 获取指定文件的短路径名 |
GetTempFileName 这个函数包含了一个临时文件的名字,它可由应用程序使用 |
GetTempPath 获取Windows临时目录路径 |
lclose 关闭指定的文件,请参考CloseHandle函数,了解进一步的情况 |
lcreat 创建一个文件。如文件已经存在,就会将其缩短成零长度,并将其打开,以便读写 |
llseek 设置文件中进行读写的当前位置。该函数与vba的seek语句类似。 |
LockFile 在windows中,文件可用共享模式打开——在这种情况下,多个进程可同时访问该文件。 |
利用这个函数,要对文件进行读写的一个应用程序可将文件的某一部分锁定起来,使其 |
不能由其他应用程序访问。这样便避免了同时读写时发生的冲突 |
LockFileEx 与LockFile相似,只是它提供了更多的功能 |
lopen 以二进制模式打开指定的文件 |
lread 将文件中的数据读入内存缓冲区 |
lwrite 将数据从内存缓冲区写入一个文件 |
MoveFile, MoveFileEx 移动文件。如dwFlags设为零,则MoveFile完全等价于MoveFileEx |
OpenFile 这个函数能执行大量不同的文件操作。和这个函数相比,请优先考虑CreateFile函数 |
(它能打开命名管道和控制 Unicode 文件名,同时不受128个字符的路径名称的限制) |
ReadFile 从文件中读出数据。与lread函数相比,这个函数要明显灵活的多。该函数能够操作 |
通信设备、管道、套接字以及邮槽 |
ReadFileEx 与ReadFile相似,只是它只能用于异步读操作,并包含了一个完整的回调 |
SearchPath 查找指定文件 |
SetEndOfFile 针对一个打开的文件,将当前文件位置设为文件末尾 |
SetFileAttributes 设置文件属性 |
SetFilePointer 在一个文件中设置当前的读写位置 |
SetFileTime 设置文件的创建、访问及上次修改时间 |
UnlockFile 解除对一个文件的锁定 |
UnlockFileEx 解除对一个文件的锁定 |
WriteFile 将数据写入一个文件。该函数比lwrite函数要灵活的多。也可将这个函数应用于对 |
通信设备、管道、套接字以及邮槽的处理 |
WriteFileEx 与WriteFile类似,只是它只能用于异步写操作,并包括了一个完整的回调 |
文件的压缩和解压缩 |
LZOpenFile 打开压缩文件以读取 |
LZSeek 查找压缩文件中的一个位置 |
LZRead 读一个压缩文件 |
LZClose 关闭一个压缩文件 |
LZCopy 复制压缩文件并在处理过程中展开 |
GetExpandedName 从压缩文件中返回文件名称。 |
下面通过几个例子来详细的了解一下其中主要的几个函数及其用法: |
1、CreateFile |
作用:这是一个全功能的例程,可打开和创建文件、管道、邮槽、通信服务、设备以及控制台 |
声明: |
Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" ( ByVal lpFileName As String , ByVal dwDesiredAccess As Long , ByVal dwShareMode As Long , lpSecurityAttributes As SECURITY_ATTRIBUTES, ByVal dwCreationDisposition As Long , ByVal dwFlagsAndAttributes As Long , ByVal hTemplateFile As Long ) As Long |
说明: |
此函数的返回值类型为 Long ,如执行成功,则返回文件句柄。INVALID_HANDLE_VALUE表示出错,会设置 GetLastError。即使函数成功,但若文件存在,且指定了CREATE_ALWAYS 或 OPEN_ALWAYS,GetLastError也会设为ERROR_ALREADY_EXISTS |
打开一个通信端口时(如COM1),无论如何都要设置成 OPEN_EXISTING。 |
这个函数代替了lOpen 和 lCreate函数,应该是我们的首选 |
参数说明: |
·lpFileName String ,要打开的文件的名字 |
·dwDesiredAccess Long ,如果为 GENERIC_READ 表示允许对设备进行读访问;如果为 GENERIC_WRITE 表示允许对设备进行写访问(可组合使用);如果为零,表示只允许获取与一个设备有关的信息 |
·dwShareMode Long ,零表示不共享; FILE_SHARE_READ 和/或 FILE_SHARE_WRITE 表示允许对文件进行共享访问 |
·lpSecurityAttributes SECURITY_ATTRIBUTES,指向一个SECURITY_ATTRIBUTES结构的指针,定义了文件的安全特性(如果操作系统支持的话) |
·dwCreationDisposition |
Long ,下述常数之一: |
CREATE_NEW 创建文件;如文件存在则会出错 |
CREATE_ALWAYS 创建文件,会改写前一个文件 |
OPEN_EXISTING 文件必须已经存在。由设备提出要求 |
OPEN_ALWAYS 如文件不存在则创建它 |
TRUNCATE_EXISTING 讲现有文件缩短为零长度 |
·dwFlagsAndAttributes |
Long ,一个或多个下述常数 |
FILE_ATTRIBUTE_ARCHIVE 标记归档属性 |
FILE_ATTRIBUTE_COMPRESSED 将文件标记为已压缩,或者标记为文件在目录中的默认压缩方式 |
FILE_ATTRIBUTE_NORMAL 默认属性 |
FILE_ATTRIBUTE_HIDDEN 隐藏文件或目录 |
FILE_ATTRIBUTE_READONLY 文件为只读 |
FILE_ATTRIBUTE_SYSTEM 文件为系统文件 |
FILE_FLAG_WRITE_THROUGH 操作系统不得推迟对文件的写操作 |
FILE_FLAG_OVERLAPPED 允许对文件进行重叠操作 |
FILE_FLAG_NO_BUFFERING 禁止对文件进行缓冲处理。文件只能写入磁盘卷的扇区块 |
FILE_FLAG_RANDOM_ACCESS 针对随机访问对文件缓冲进行优化 |
FILE_FLAG_SEQUENTIAL_SCAN 针对连续访问对文件缓冲进行优化 |
FILE_FLAG_DELETE_ON_CLOSE 关闭了上一次打开的句柄后,将文件删除。特别适合临时文件 |
也可在Windows NT下组合使用下述常数标记: |
SECURITY_ANONYMOUS, SECURITY_IDENTIFICATION, SECURITY_IMPERSONATION, SECURITY_DELEGATION, SECURITY_CONTEXT_TRACKING, SECURITY_EFFECTIVE_ONLY |
·hTemplateFile Long ,如果不为零,则指定一个文件句柄。新文件将从这个文件中复制扩展属性 |
示例如下: |
lngHandle = CreateFile( "c:\text.txt" , GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0&, OPEN_ALWAYS, 0, 0) |
'上面代码以写方法打开文件,如文件不存在则创建它。 |
2、lcreat |
作用:创建一个文件。如文件已经存在,就会将其缩短成零长度,并将其打开,以便读写 |
声明: Declare Function lcreat Lib "kernel32" Alias "_lcreat" ( ByVal lpPathName As String , ByVal iAttribute As Long ) As Long |
说明:此函数的返回值类型为 Long ,如执行成功,返回打开文件的句柄。如果出错,则返回HFILE_ERROR |
该函数会打开已由其他应用程序打开的文件,所以使用它时要小心。win32的CreateFile函数已取代了这个函数。这个函数与vb的open语句作用相同 |
参数说明: |
lpPathName String ,欲创建的文件的名字 |
iAttribute Long ,下述值之一: |
0——文件能够读写 |
1——创建只读文件 |
2——创建隐藏文件 |
3——创建系统文件 |
示例: |
下面的语句打开c:\test.txt文件 |
lcreat “c:\test.txt”,0 |
3、lopen |
作用:以二进制模式打开指定的文件 |
声明: Declare Function lopen Lib "kernel32" Alias "_lopen" ( ByVal lpPathName As String , ByVal iReadWrite As Long ) As Long |
说明:此函数的返回值类型为 Long ,如执行成功,返回打开文件的句柄。HFILE_ERROR表示出错。会设置GetLastError |
参数说明: |
lpPathName String ,欲打开文件的名字 |
iReadWrite Long ,访问模式和共享模式常数的一个组合,如下所示: |
1、访问模式 |
READ 打开文件,读取其中的内容 |
READ_WRITE 打开文件,对其进行读写 |
WRITE 打开文件,在其中写入内容 |
2、共享模式(参考OpenFile函数的标志常数表) |
OF_SHARE_COMPAT, OF_SHARE_DENY_NONE, OF_SHARE_DENY_READ, OF_SHARE_DENY_WRITE, OF_SHARE_EXCLUSIVE |
示例: |
lopen “c:\test.txt”,READ |
4、GetFileTime |
作用:取得指定文件的时间信息 |
声明: Declare Function GetFileTime Lib "kernel32" Alias "GetFileTime" ( ByVal hFile As Long , lpCreationTime As FILETIME, lpLastAccessTime As FILETIME, lpLastWriteTime As FILETIME) As Long |
说明: Long ,非零表示成功,零表示失败。会设置GetLastError |
如果不需要特定的信息,那么lpCreationTime,lpLastAccessTime,lpLastWriteTime都可以设置为零(用 ByVal As Long )。这个函数返回的文件时间采用UTC格式 |
参数说明: |
hFile Long ,文件的句柄 |
lpCreationTime FILETIME,用于装载文件的创建时间 |
lpLastAccessTime FILETIME,用于装载文件上一次访问的时间(FAT文件系统不支持这一特性) |
lpLastWriteTime FILETIME,用于装载文件上一次修改的时间 |
示例: |
Dim file As Long |
Dim CreationTime As FileTime |
Dim lastaccesstime As FileTime |
Dim lastaccesstime As FileTime |
'定义结构 |
Private Type FileTime |
dwLowDateTime As Long |
dwHighDateTime As Long |
End Type |
str1 = "c:\text.txt" |
file = lopen(str1, READ_WRITE) '打开文件 |
temp = GetFileTime(file, CreationTime, lastaccesstime, lastwritetime)’得到文件相关信息 |
以上代码获取的时间信息是 Long 型的,还需要时间转换函数进行转换,完整的示例见附件。 |
5、CopyFile |
作用:复制文件。与vb的filecopy命令相似 |
声明: Declare Function CopyFile Lib "kernel32" Alias "CopyFileA" ( ByVal lpExistingFileName As String , ByVal lpNewFileName As String , ByVal bFailIfExists As Long ) As Long |
说明: Long ,非零表示成功,零表示失败。会设置GetLastError |
参数说明: |
lpExistingFileName String ,源文件名 |
lpNewFileName String ,目标文件名 |
bFailIfExists Long ,如果设为TRUE(非零),那么一旦目标文件已经存在,则函数调用会失败。否则目标文件被改写 |
示例: |
CopyFile "c:\test1.txt" , "c:\test2.txt" , 1 |
以上代码将c:\test1.txt 拷贝到c:\test2.txt,完整的示例见附件。 |
6、MoveFile, MoveFileEx |
作用:移动文件。如dwFlags设为零,则MoveFile完全等价于MoveFileEx |
声明: |
Declare Function MoveFile Lib "kernel32" Alias "MoveFileA" ( ByVal lpExistingFileName As String , ByVal lpNewFileName As String ) |
Declare Function MoveFileEx Lib "kernel32" Alias "MoveFileExA" ( ByVal lpExistingFileName As String , ByVal lpNewFileName As String , ByVal dwFlags As Long ) |
说明: Long ,非零表示成功,零表示失败。会设置GetLastError |
这两个函数通常不能将文件从一个卷移动到另一个卷。但如设置了MOVEFILE_COPY_ALLOWED标记,MoveFileEx可以做到这一点. |
参数说明: |
lpExistingFileName String ,欲移动的文件名 |
lpNewFileName String ,新文件名 |
dwFlags Long ,一个或多个下述常数 |
MOVEFILE_REPLACE_EXISTING 如目标文件存在,则将其替换 |
MOVEFILE_COPY_ALLOWED 如移动到一个不同的卷,则复制文件并删除原来的文件 |
MOVEFILE_DELAY_UNTIL_REBOOT 移动操作在系统下次重新启动时正式进行。这样便可在Windows NT中改换系统文件 |
示例: |
Private Const MOVEFILE_COPY_ALLOWED = &H2 |
Private Const MOVEFILE_DELAY_UNTIL_REBOOT = &H4 |
Private Const MOVEFILE_REPLACE_EXISTING = &H1 |
MoveFile "c:\test.txt" , "d:\test1.txt" '移动文件 |
MoveFileEx "d:\test1.txt" , "c:\test.txt" , MOVEFILE_COPY_ALLOWED '再一次移动 |
以上代码实现了文件的移动,两次移动後,文件不变 |
7、DeleteFile |
作用:删除指定文件 |
声明: Declare Function DeleteFile Lib "kernel32" Alias "DeleteFileA" ( ByVal lpFileName As String ) As Long |
说明: Long ,非零表示成功,零表示失败。会设置GetLastError |
与vba的kill语句相似,在windows 95下使用这个函数要小心——即使文件当前正由一个应用程序打开,该函数也会将其删除. |
参数说明: |
lpFileName String ,欲删除文件的名字 |
示例: |
DeleteFile "c:\test.txt" '删除c:\test.txt文件 |
完整的示例见附件。 |
8、ReadFile |
作用:从文件中读出数据。与lread函数相比,这个函数要明显灵活的多。该函数能够操作通信设备、管道、套接字以及邮槽 |
声明: Private Declare Function ReadFile Lib "kernel32" Alias "ReadFile" ( ByVal hFile As Long , lpBuffer As Any, ByVal nNumberOfBytesToRead As Long , lpNumberOfBytesRead As Long , lpOverlapped As OVERLAPPED) As Long |
说明: Long ,非零表示成功,零表示失败。会设置GetLastError。如启动的是一次异步读操作,则函数会返回零值,并将 ERROR_IO_PENDING设置成GetLastError的结果。如结果不是零值,但读入的字节数小于nNumberOfBytesToRead 参数指定的值,表明早已抵达了文件的结尾 |
参数: |
hFile ---- Long ,文件的句柄 |
lpBuffer --- Any,用于保存读入数据的一个缓冲区 |
nNumberOfBytesToRead - Long ,要读入的字符数 |
lpNumberOfBytesRead - Long ,从文件中实际读入的字符数 |
lpOverlapped --- OVERLAPPED,如文件打开时指定了FILE_FLAG_OVERLAPPED,那么必须用这个参数引用一个特殊的结构。那个结构定义了一次异步读 取操作。否则,应将这个参数设为NULL(将函数声明成 ByVal As Long ,并传递零值) |
示例:完整的示例见附件。 |
9、WriteFile |
作用:将数据写入一个文件。该函数比lwrite函数要灵活的多。也可将这个函数应用于对通信设备、管道、套接字以及邮槽的处理 |
声明: Declare Function WriteFile Lib "kernel32" Alias "WriteFile" ( ByVal hFile As Long , lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long , lpNumberOfBytesWritten As Long , lpOverlapped As OVERLAPPED) As Long |
说明: Long ,TRUE(非零)表示成功,否则返回零。会设置GetLastError |
参数: |
hFile --- Long ,一个文件的句柄 |
lpBuffer --- Any,要写入的一个数据缓冲区 |
nNumberOfBytesToWrite - Long ,要写入数据的字节数量。如写入零字节,表示什么都不写入,但会更新文件的“上一次修改时间”。针对位于远程系统的命名管道,限制在65535个字节以内 |
lpNumberOfBytesWritten - Long ,实际写入文件的字节数量 |
lpOverlapped --- OVERLAPPED,倘若在指定FILE_FLAG_OVERLAPPED的前提下打开文件,这个参数就必须引用一个特殊的结构。那个结构定义了一次异 步写操作。否则,该参数应置为空(将声明变为 ByVal As Long ,并传递零值) |
示例:完整的示例见附件。 |
10、SHFileOperation |
作用:此函数的功能很强大,能对文件或文件夹进行复制、移动、重命名、删除的全部操作。 |
声明: Declare Function SHFileOperation Lib "shell32.dll" Alias "SHFileOperationA" (lpFileOp As SHFILEOPSTRUCT) As Long |
说明: Long ,TRUE(非零)表示成功,否则返回零。 |
参数: |
lpFileOp --SHFILEOPSTRUCT类型,指定文件的操作。 |
Type SHFILEOPSTRUCT |
hwnd As Long |
wFunc As Long '对文件的操作指令 |
pFrom As String '源文件或路径 |
pTo As String '目的文件或路径 |
fFlags As Integer '操作标志 |
fAnyOperationsAborted As Long |
hNameMappings As Long |
lpszProgressTitle As String |
End Type |
示例:见附件。 |
(三)总结 |
通过以上的介绍,我们可以看到API在文件操作方面功能十分强大,能够完成一些前面方法所不能完成的任务。FileSystemObject对象模 型的内部可能就是用API写的,即便不是我们也可以用API写出一个FSO类来。API是一个巨大的宝库,当你为实现某个功能而愁眉不展的时候,查查 API可能就能找到满意的答案。 |
写的这么多,希望对大家有所帮助,至少操作文件是没有什么问题了。 |
附件:API函数示例,代码有注释,应该都看的懂,可以按F8逐行运行,查看结果。 |