書名: Office VBA開發(fā)經典:中級進階卷作者名: 劉永富 劉行本章字數: 3504字更新時間: 2019-11-22 18:29:00
1.1 使用傳統(tǒng)方式
使用傳統(tǒng)方式可以訪問文件和路徑,對文本文件和二進制文件進行讀寫。最常用的函數和命令如下。
Dir:用于列舉路徑下的文件和子文件夾名稱。
GetAttr和SetAttr:獲取和設置屬性。
FileCopy、Name、MkDir等:對文件和路徑復制、移動等。
Open...Write...Close:對文本文件、二進制文件進行打開、讀寫、關閉。
1.1.1 獲取文件或路徑的屬性
右擊文件、文件夾,在彈出菜單中選擇屬性命令,打開屬性窗口后,可以設置只讀屬性和隱藏屬性等。
GetAttr函數用來獲取和判斷文件或路徑的屬性,該函數的參數是一個路徑字符串,返回值是由多個2的整數冪的組合相加的總和,如表1-1所示。
表1-1 文件、路徑的屬性常量

這里假定磁盤下的TE.txt文本文件已設置為“只讀”并且“隱藏”,如圖1-1所示。

圖1-1 查看文件屬性
此時,GetAttr("C:\temp\abcd\TE.txt")會返回一個整數35。其實,35=32(vbArchive)+2(vbHidden)+1(vbReadOnly)。
因此,把GetAttr函數的計算結果拆分為多個枚舉常量值之和,就可以得知該文件的屬性。
下面的過程用來把任何一個正整數拆分為多個2的乘方。

運行上述過程,可以看到13被拆分為8+4+1。根據這個思路,可以設計一個用來判斷文件是否被設置為只讀的自定義函數。

這個函數的原理就是把GetAttr的結果拆分為多個數字,拆分的過程中,看看是否有一個拆分恰好等于枚舉常量vbReadOnly,如果有就提前退出函數,返回True。
運行Debug.Print IsReadOnly("C:\temp\abcd\TE.txt"),在立即窗口返回結果True,表明這是一個只讀文件。
同理,把上述函數中的ReadOnly這個單詞替換為Hidden,就形成了可以判斷文件或路徑是否設置了隱藏屬性。

這里假定C:盤下的Build文件夾被設置了隱藏屬性,那么Debug.Print IsHidden("C:\Build\")返回結果True。
下面的函數可以判斷一個路徑是否為文件夾。

Debug.Print IsDirectory("C:\Build\")返回True。Debug.Print IsDirectory("C:\Build\Hello.csv")返回False。
1.1.2 設置文件或路徑的屬性
與GetAttr相對應的函數是SetAttr,該函數可以設置文件、路徑的屬性。
SetAttr "C:\Build\", vbHidden + vbReadOnly
這條代碼把Build文件夾的屬性設置為只讀,并且隱藏。
SetAttr "C:\Build\", vbNormal
這句代碼去掉只讀和隱藏屬性,恢復為正常屬性。
1.1.3 判斷文件或路徑是否存在
使用Dir函數可以列舉出當前路徑下所有文件和子文件夾的名稱,從而間接地判斷一個文件或文件夾是否存在。
Dir函數的語法為:
Dir(PathName,Attributes)
PathName是一個用來描述文件、路徑的字符串,可以使用*、?通配符。Attributes可以使用如表1-2所示的值。
表1-2 Dir函數用的篩選常量

如果不規(guī)定Attributes屬性,則默認為vbNormal。

代碼分析:如果計算機中不存在Test.txt這個文件,那么Dir函數會返回空字符串;如果文件存在,則返回第一個符合模式的文件名稱(不包含所在路徑),據此可以判斷磁盤或文件夾中是否有某個文件。此外,還可以使用Dir函數判斷是否有某磁盤分區(qū),或者是否有某個文件夾。
如果上述過程中的Path賦值為Path="M:"或者Path="M:\",則可以用來判斷是否存在M:盤。
如果要判斷是否存在某文件夾(路徑),結尾必須加反斜杠。例如Dir("C:\build")用來判斷C:盤下是否有build這個文件,而Dir("C:\build\")用來判斷C盤下是否有build文件夾。
1.1.4 遍歷文件和子文件夾
利用Dir函數和不帶參數的Dir,可以遍歷一個路徑下的所有文件和子文件夾的名稱。現在假定C:\CTEX文件夾中的內容如圖1-2所示。

圖1-2 文件夾中的內容
可以看到有7個子文件夾,4個文件。運行如下的過程,打印出所有的子文件夾名稱和文件名稱。

上述程序的打印結果如圖1-3所示。
可以看出,第一行打印出一個小數點,第二行打印出兩個小數點,從第三行起才是正式的內容。
如果把代碼中的Path = Dir(parent, vbDirectory)修改為Path = Dir(parent),則只遍歷文件,不遍歷子文件夾。
那么如何只遍歷子文件夾呢?這就需要在循環(huán)體中加入If語句來選擇性地遍歷。

圖1-3 遍歷子文件夾和文件

上述過程中,用集合Col來裝載所有的文件和子文件夾的名稱,最后,遍歷Col的時候,首先過濾出所有的子文件夾,然后排除小數點,最后輸出純粹的子文件夾,共7個,如圖1-4所示。
如果要遍歷C:\Ctex下面的所有擴展名為.txt的文本文件,代碼可以修改為如下形式。

圖1-4 只列舉子文件夾名稱

注意,Dir函數中用到了通配符,*.txt可以匹配所有的文本文件,如圖1-5所示。

圖1-5 只遍歷文本文件
1.1.5 文件的復制、移動和刪除
文件的復制、移動和刪除操作,分別用FileCopy、Name As和Kill語句。
FileCopy的語法為:
FileCopy Source, Destination
Source表示原文件,Destination表示復制的目標。
例如FileCopy Source:="C:\temp\a.xlsx", Destination:="D:\dist\goal.xlsx",表示把文件C:\temp\a.xls復制到D:\dist文件夾下,并且重命名為goal.xlsx。
文件的移動操作就是文件的剪切,也可以理解為文件的重命名。與復制文件的區(qū)別是,原文件不在原位置了。
Name "C:\temp\a.xlsx" As "D:\dist\b.xlsx",就相當于把a文件從原位置剪切到D:\dist文件夾中,并且設置名稱為b.xlsx。
注意 針對文件的移動操作,如果D:\dist\下面原先就有一個b.xlsx文件,那么運行上述的Name語句會導致出錯。也就是說,必須保證目標文件夾中還沒有這個文件,才能進行移動操作。
Kill語句用于刪除文件,如果文件處于打開、占用狀態(tài),運行該語句會出錯。另外,用Kill語句刪除掉的文件,不能通過回收站還原,要謹慎操作。
圖1-6所示的代碼連續(xù)兩次刪除同一個文件,第一句不會出錯,但是運行到第二句時彈出“文件未找到”的錯誤。

圖1-6 重復刪除同一文件的錯誤
1.1.6 文件夾的創(chuàng)建和刪除
文件夾的創(chuàng)建和刪除分別用MkDir和RmDir語句,Mk是Make的縮寫,Rm是Remove的縮寫。
MkDir語句的語法很簡單。
MkDir Path:="C:\temp\2017",會在temp文件夾下創(chuàng)建一個名為2017的文件夾。
RmDir語句用來刪除一個空文件夾。
RmDir Path:="C:\temp\picture",表示刪除picture文件夾,如果該文件夾不是空的,包含其他的文件和子文件夾,那么RmDir會提示錯誤,如圖1-7所示。
也就是說,要刪除一個文件夾,必須先把里面的內容清空后,才能使用RmDir語句刪除。
文件夾的重命名也使用Name…As語句。例如Name "C:\temp\picture" As "C:\temp\pic",表示把文件夾picture重命名為pic。

圖1-7 文件夾中有內容則不能刪除
1.1.7 文本文件的讀寫
編程過程中,經常需要把程序運行的結果數據保存到文本文件,也需要從文本文件中讀取數據供程序使用,這就涉及文本文件的讀寫操作了。
本節(jié)介紹一下用于文件讀寫的Open語句。
Open語句的語法如下。
Open textFile For mode As fileNum
參數textFile是一個表示文本文件路徑的字符串。
參數mode表示Open語句的讀寫模式,使用最多的模式如下。
Append:追加模式。
Output:擦寫模式。
Input:讀取模式。
如果要把程序運行的結果輸出到文本文件中,那么使用Append模式會把輸出結果追加到文件已有內容之后,而使用Output模式,則會先清空文件原先的內容,再寫入輸出結果。
如果要從文本文件中讀取內容,而不破壞文件,可以使用Input模式。
要注意的是,在使用Output或Append模式時,如果計算機中textFile文件不存在,則會自動創(chuàng)建一個文本文件;如果使用Input模式讀取一個文本文件,文本文件不存在會導致出錯。
參數fileNum是一個文件號,可以是#1到#511中的任何一個。讀寫文件操作結束后,一定要用Close fileNum關閉文件。
下面講述一下導出數據到文本文件中的方法。

上述過程把三個字符串寫入文本文件中,使用Print語句寫入時,在末尾自動換行,如圖1-8所示。
使用Print在同一行輸出多個字符串時,每個字符串之間用半角分號隔開。

上述程序的運行結果如圖1-9所示。

圖1-8 向文件寫入內容

圖1-9 同一行輸出多個結果
除了使用Print語句輸出外,還可以使用Write語句輸出內容到文本文件。

程序的運行結果如圖1-10所示。
可以看出文本文件中的內容都帶有雙引號,這和Print語句有很大不同。
如果把Open "C:\temp\abc.txt" For Output As #1這句中的Output換成Append,則每次寫入文件時,不刪除文件原有內容。請讀者自行測試。
接下來講述如何從已有文本文件中讀取內容,供程序調用。
讀入文件內容涉及的常用術語有:
v=Input(c,fileNum),表示從文件當前位置讀取c個字符,賦給字符串變量v。

圖1-10 使用Write輸出內容
Seek fileNum, c,把當前位置重設為c,c的最小值是1。
LOF(fileNum),返回文件的長度,也就是文件中字符總數。
EOF(fileNum),返回一個布爾值,當讀取到文件尾部,返回True。經常使用EOF來判斷是否讀取完成。
現在假設文本文件auto.txt中的內容如圖1-11所示。

圖1-11 文本文件內容

代碼分析:a = Input(1, #1),表示從文件的開頭處讀取1個字符,賦給a,因此變量a的取值為字符串h。
b = Input(2, #1),表示從上次讀取的位置起,讀入2個字符賦給變量b,因此b的取值為el。以此類推。
Seek #1, 1表示把讀取位置重設為1,也就是文件開頭,接下來d = Input(3, #1)表示從文件開頭處讀取3個字符,因此d的取值為Hel。
上述程序的運行結果如圖1-12所示。

圖1-12 從文件中讀取字符
根據這個特點,可以把文本文件中的所有字符分發(fā)到字符串數組中。

代碼分析:上述過程,打開文本文件后,根據文件字符總數重新定義數組的上下界,使得數組能恰好容納文本中的字符,然后使用For循環(huán),遍歷文本文件中的每個字符,并分發(fā)到數組的每個元素。
運行到Stop那句,通過本地窗口可以清晰地看到數組s的各元素取值情況,如圖1-13所示。

圖1-13 本地窗口查看數組
可以看出,每個元素恰好取得文件中的一個字符。最后通過Join把數組用*重新連接并輸出,如圖1-14所示。

圖1-14 數組連接為字符串
此外,還可以使用Line Input語句,每次讀取一整行。
假設文件b.txt中有4行古詩,下面用Line Input讀取內容。

代碼分析:本例直接把讀取到的每行打印到立即窗口,因此可以使用Do循環(huán),利用EOF函數來判斷是否讀到文件尾部,如果到了尾部,就結束循環(huán)。
上述程序的運行結果如圖1-15所示。

圖1-15 使用Line Input讀取內容
如果要一次性讀取文本文件的所有內容,可以使用下面的自定義函數。

運行下面的Test過程,即可把文件中的所有內容打印到立即窗口。

上述代碼的源文件為“實例文檔01.xlsm”。
- 程序員修煉之道:程序設計入門30講
- 造個小程序:與微信一起干件正經事兒
- Hadoop+Spark大數據分析實戰(zhàn)
- Linux環(huán)境編程:從應用到內核
- Integrating Facebook iOS SDK with Your Application
- Java實戰(zhàn)(第2版)
- Multithreading in C# 5.0 Cookbook
- MySQL從入門到精通(軟件開發(fā)視頻大講堂)
- Scratch趣味編程:陪孩子像搭積木一樣學編程
- ASP.NET 4.0 Web程序設計
- Data Science Algorithms in a Week
- Web前端開發(fā)技術:HTML、CSS、JavaScript
- Xamarin Cross-Platform Development Cookbook
- Raspberry Pi Blueprints
- Learning Shiny