Share via


嗨,Scripting Guy!

Hey,Scripting Guy!

歡迎使用全新的 TechNet 專欄,Microsoft Scripting Guys 會在此為您解答有關系統管理指令碼的常見問題。您有關於系統管理指令碼方面的問題嗎?請將電子郵件傳送到 scripter@microsoft.com。我們無法保證能夠逐一回答每個問題,不過我們會盡力而為。

今天的問題:我是否能夠一次讀取完整的文字檔,而不需逐行讀取?


我是否能夠一次讀取完整的文字檔,而不需逐行讀取?

嗨,Scripting Guy!我目前是利用一段指令碼開啟一個包含電腦名稱的文字檔。這段指令碼會讀取檔案的第一行,然後連線至該部電腦,接著再讀取檔案的第二行,再連線至「同一部」電腦。是否有方法先將這些電腦名稱儲存在一個變數 (或是其他東西) 中,讓我不必反覆讀取這個文字檔?

-- KS

KS,您好。假設您的指令碼目前看起來像是這樣的。在以下這個範例指令碼中,我們會開啟一個文字檔 (servers.txt)、讀取第一行 (假設該檔案的每一行都是一個電腦名稱),然後呼叫第一行的電腦名稱。 (當然,在「您的」指令碼中,您在此時可能已經連線至該部遠端電腦了)。接著,我們會讀取文字檔的第二行、呼叫「這一部」電腦的名稱、回到迴圈的開頭、讀取文字檔的第三行,然後重複這個過程,直到讀完檔案中的每一行為止:
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile _
    ("c:\scripts\servers.txt", ForReading)
Do Until objTextFile.AtEndOfStream
    strComputer = objTextFile.ReadLine
    Wscript.Echo strComputer
Loop
objTextFile.Close

目前看來,用這種方法讀取文字檔似乎沒有錯誤;它的運作完全正常。然而,我們可以理解您為何想要一口氣讀完整個文字檔,然後在記憶體中處理這份清單。畢竟,如果這個文字檔位於遠端電腦上,則您不但必須一再跨越網路,只為了讀取文字檔中的一行文字,而且如果遠端電腦停機,您的指令碼也將隨之停擺。

因此,到底有沒有方法可以讓您一次讀完整個文字檔,並將資訊儲存在一個變數中,再從記憶體處理這份電腦清單?當然可以!

Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile _
    ("c:\scripts\servers.txt", ForReading)
strText = objTextFile.ReadAll
objTextFile.Close
arrComputers = Split(strText, vbCrLf)
For Each strComputer in arrComputers
    Wscript.Echo strComputer
Next

這段指令碼的運作原理如下:就像您目前的指令碼一樣,我們建立了一個常數 (ForReading),並將它的值指派為 1;對於使用 FileSystemObject 讀取文字檔而言,這麼做是必要的。接著,我們為 FileSystemObject 建立一個執行個體,再使用 OpenTextFile 方法開啟 C:\Scripts\Servers.txt 檔案。您早就知道這個方法,對吧?

接下來才是您真正感興趣的部份。我們將會使用 ReadAll 方法一口氣讀取整個文字檔,並將檔案內容儲存在 strText 變數中,以取代原本逐行讀取檔案的作法。strText 變數成為與文字檔一字不差的複本。假設您的文字檔內容如下:

atl-ws-01
atl-ws-02
atl-ws-03
atl-ws-04

如果我們呼叫 strText 的值,猜猜看螢幕上會顯示什麼?像這樣就對了:

atl-ws-01
atl-ws-02
atl-ws-03
atl-ws-04

目前為止,我們已經成功地讀取整個文字檔,並將其內容儲存在一個變數中。然而,這對我們而言可說毫無益處;畢竟,如果我們嘗試利用 strText 連線至某部電腦,我們將會連線至整個文字檔,而非單一一部電腦。這項操作勢必是行不通的。現在我們需要做的,就是將個別的電腦名稱區隔開來,好讓我們可以一次只連線至一部電腦。

這項工作是由這行程式碼負責完成的:

arrComputers = Split(strText, vbCrLf)

Split 指令會根據某筆資料 (在本範例中為 strText 變數) 建立一個陣列。然而,它是怎麼知道某個電腦名稱的結尾位置,以及下一個電腦名稱的開頭位置?在範例中,用來區隔電腦名稱的「分隔字元」是歸位換行字元;因為當我們在文字檔中輸入一個電腦名稱之後,我們會按下 ENTER 鍵,然後才輸入下一個電腦名稱。而 Split 函數使用的 VBScript 常數 vbCrLf 即代表 ENTER 鍵。假設 strText 看起來是這樣:

atl-ws-01,atl-ws-02,atl-ws-03,atl-ws-04

此情況下的分隔字元便會是逗號,而 Split 指令也應該要修改為:

arrComputers = Split(strText, ",")

換句話說,只要將變數名稱和分隔字元傳遞給 Split,接下來的工作交給 Split 就可以了。

現在我們已經將電腦名稱安全地儲存在陣列中了。接著,我們便能使用 For Each 迴圈重複陣列中的每個項目:

For Each strComputer in arrComputers
    Wscript.Echo strComputer
Next

再舉一個更實際的例子。以下這段範例指令碼將會示範如何使用 WMI 連線至文字檔中的每部電腦,再擷取該部電腦安裝的作業系統名稱:

Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile _
    ("c:\scripts\servers.txt", ForReading)
strText = objTextFile.ReadAll
objTextFile.Close
arrComputers = Split(strText, vbCrLf)
For Each strComputer in arrComputers
    Set objWMIService = GetObject _
        ("winmgmts:\\" & strComputer & "\root\cimv2")
    Set colItems = objWMIService.ExecQuery _
        ("Select * From Win32_OperatingSystem")
    For Each objItem in ColItems
        Wscript.Echo strComputer & ": " & objItem.Caption
    Next
Next

如需詳細資訊

查看嗨,Scripting Guy!- 過往文件

 

回到頁首 回到頁首