Centrum Skryptów - Microsoft Office

Jak dodać ostatnie wiersze kilku plików tekstowych do dokumentu Word?

Udostępnij na: Facebook

Skrypciarze odpowiadają na Wasze pytania

Cześć Skrypciarze!

Witamy w rubryce TechNet, w której Skrypciarze z firmy Microsoft odpowiadają na częste pytania dotyczące używania skryptów w administracji systemu. Jeśli macie jakieś pytania z tej dziedziny, zachęcamy do wysłania e-maila na adres: scripter@microsoft.com. Nie możemy zagwarantować odpowiedzi na każde otrzymane pytanie, ale staramy się jak możemy.

Jak dodać ostatnie wiersze kilku plików tekstowych do dokumentu Word?

Cześć Skrypciarze! Pytanie

Cześć, Skrypciarze! Jak skopiować ostatnie wiersze z kilku plików tekstowych i wkleić je do dokumentu Word?

-- JV

Cześć Skrypciarze! Odpowiedź

Cześć, JV. W artykułach z tej serii staramy się poruszać przede wszystkim kwestie, które mogą się przydać w rzeczywistej pracy administratora. Od czasu do czasu zajmujemy się czym innym, ale koncentrujemy się na takich pytaniach, które, jak sądzimy, zainteresują jak najwięcej czytelników. Szczerze mówiąc, z początku myśleliśmy, że Twoje pytanie nie należy do tej grupy.

Ale potem zaczęliśmy się zastanawiać i przypomnieliśmy sobie, że pliki dziennika często zawierają mnóstwo szczegółowych informacji, a w ostatnim wierszu mają ich posumowanie. Tak więc mając kilka czy kilkanaście plików dziennika można by sporządzić ogólny raport, kopiując ich ostatnie wiersze do dokumentu Word. Nie wiemy, czy o to właśnie Ci chodzi, ale cieszymy się, że udało się nam opracować praktyczne zastosowanie poniższego skryptu:

Const ForReading = 1



Set objFSO = CreateObject("Scripting.FileSystemObject")



strComputer = "."



Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")



Set colFileList = objWMIService.ExecQuery _

    ("ASSOCIATORS OF {Win32_Directory.Name='C:\Logs'} Where " _

        & "ResultClass = CIM_DataFile")



For Each objFile In colFileList

    strFilePath = objFile.Name

    Set objTextFile = objFSO.OpenTextFile(strFilePath, ForReading)

    Do Until objTextFile.AtEndOfStream

        strLine = objTextFile.ReadLine

    Loop

    strMessage = strMessage & strLine & vbCrLf

    objTextFile.Close

Next



Set objWord = CreateObject("Word.Application")

objWord.Visible = True

Set objDoc = objWord.Documents.Add()



Set objSelection = objWord.Selection

objSelection.TypeText strMessage

No tak, jest odrobinkę za długi, ale pamiętajcie, że mamy tu sporo do zrobienia: musimy pobrać wszystkie pliki zapisane w folderze, otworzyć je, pobrać ich ostatnie wiersze, uruchomić program Microsoft Word, a w końcu wkleić wiersze do pliku .doc. W gruncie rzeczy upchnięcie tego wszystkiego w dwudziestu kilku linijkach to nie taki zły wynik.

Skrypt rozpoczyna się od zdefiniowania zmiennej o nazwie ForReading i przypisania jej wartości 1; użyjemy tej zmiennej za każdym razem, kiedy będziemy otwierać plik tekstowy do odczytu. Następnie łączymy się z usługą WMI na lokalnym komputerze, z czym wiąże się ciekawe pytanie: czy skrypt można uruchomić na komputerze zdalnym? Można: WMI może pobrać kolekcję plików z komputera zdalnego z taką samą łatwością, co z lokalnego.

Niestety jednak FileSystemObject – obiekt, którego używamy do odczytywania plików tekstowych – nie współpracuje z komputerami zdalnymi z taką samą łatwością. Możemy go użyć zdalnie, ale pod warunkiem odwołania się do udziału zdalnego podczas otwierania pliku. I tak, aby otworzyć plik Log1.txt w katalogu C:\Logs na zdalnym komputerze atl-fs-01 powinniśmy użyć takiej ścieżki:

\\atl-fs-01\C$\Logs\Log1.txt

Da się to zrobić, ale utworzenie takiej ścieżki wymaga napisania dodatkowego kodu.

Uwaga. Niech będzie. W dzisiejszym artykule się to już nie zmieści, ale w najbliższych dniach się tym zajmiemy.

Po połączeniu z usługą WMI używamy poniższej kwerendy do pobrania listy wszystkich plików znajdujących się w folderze C:\Logs:

Set colFileList = objWMIService.ExecQuery _

    ("ASSOCIATORS OF {Win32_Directory.Name='C:\Logs'} Where " _

        & "ResultClass = CIM_DataFile")

Dodajmy, że zakładamy, iż zależy nam na odczytaniu wszystkich plików w folderze. Jeśli tak nie jest, trzeba dopisać wiersz czy dwa wiersze kodu, by odfiltrować pliki, które chcemy pominąć (można np. sprawdzić rozszerzenia i odczytać tylko pliki z rozszerzeniem .log).

Jak się zapewne spodziewaliście, kwerenda WMI zwraca kolekcję wszystkich plików znajdujących się w folderze C:\Logs; następnie uruchamiamy pętlę For Each, która przejdzie przez całą kolekcję. Dla każdego pliku użyjemy poniższego wiersza kodu, w którym pobieramy jego nazwę (która w WMI obejmuje całą ścieżkę dostępu):

strFilePath = objFile.Name

Następnie wywołujemy metodę OpenTextFile, za pomocą której otwieramy plik do odczytu. Potem mamy taki fragment kodu:

Do Until objTextFile.AtEndOfStream

    strLine = objTextFile.ReadLine

Loop

Co w nim robimy? No cóż, FileSystemObject nie jest szczególnie wyrafinowanym parserem tekstu. Odczytanie zawartości pliku jest możliwe tylko z góry na dół – nie można po prostu polecić odczytania tylko ostatniego wiersza. Dlatego musimy odczytywać pliki linijka po linijce. Za każdym razem zapisujemy zawartość odczytanego wiersza w zmiennej o nazwie strLine (zastępując jej poprzednią zawartość). Kiedy dojdziemy do ostatniego wiersza (czyli tego, który nas interesuje), zmienna strLine będzie zawierała właśnie jego treść.

Uwaga. No tak, wygląda to nieco niezgrabnie. Jednak FileSystemObject na całe szczęście działa bardzo szybko. Odczytanie pliku wiersz po wierszu nie zajmuje dłużej niż byłoby to w wypadku przeskoczenia do końca i odczytania tylko ostatniego wiersza.

Mając ostatni wiersz zapisany w zmiennej strLine, możemy uruchomić poniższy kod:

strMessage = strMessage & strLine & vbCrLf

Kod ten zapisuje ostatni wiersz pliku w zmiennej o nazwie strMessage. Zwróćmy uwagę na równanie: przypisujemy zmiennej strMessage wartość dotychczasową, powiększoną o wartość zmiennej strLine, plus znak powrotu karetki (vbCrLf). Innymi słowy, załóżmy, że ostatni wiersz pierwszego pliku wygląda tak:

File 1

Po pierwszym zapętleniu, wartość zmiennej strMessage będzie taka sama. Jeśli ostatni wiersz drugiego pliku to File 2, strMessage po drugim zapętleniu będzie mieć taką wartość:

File 1

File 2

Jak widać, tworzymy w pamięci listę ostatnich wierszy.

Po dodaniu zawartości strLine do zmiennej strMessage zamykamy pierwszy plik, uruchamiamy pętlę od nowa i powtarzamy cały proces z kolejnym plikiem.

Po odczytaniu wszystkich plików możemy uruchomić program Word. Poniższe trzy wiersze kodu uruchamiają wystąpienie obiektu Word.Application, sprawiają, że będzie ono widoczne na ekranie, a w końcu otwierają nowy, pusty dokument:

Set objWord = CreateObject("Word.Application")

objWord.Visible = True

Set objDoc = objWord.Documents.Add()

Pozostało już tylko utworzyć wystąpienie obiektu programu Word Selection i użycie metody TypeText, która wpisze tekst do dokumentu:

Set objSelection = objWord.Selection

objSelection.TypeText strMessage

Jaki tekst wpisujemy? To oczywiste – wartość strMessage, czyli zmiennej, w której przechowaliśmy ostatnie wiersze wszystkich plików tekstowych. Czyli właściwie nie wklejamy informacji do dokumentu, chociaż ostateczny rezultat jest taki sam.

Uwaga. Testując ten skrypt natknęliśmy się na plik, który po umieszczeniu w programie Word wstawił znak niedrukowany pomiędzy każdy znak tekstu. Szczerze mówiąc, nie mieliśmy czasu na sprawdzenie, czemu się tak stało. Gdyby ktoś z Was miał podobny problem, powinno się udać go rozwiązać za pomocą poniższego, nieco zmodyfikowanego skryptu. Zastosowaliśmy w nim metodę CleanString programu Word, która usuwa wszystkie znaki niedrukowane. Spacje mogą być rozmieszczone nieco chaotycznie, ale odczyt pliku nie powinien być problemem.
Const ForReading = 1



Set objFSO = CreateObject("Scripting.FileSystemObject")



strComputer = "."



Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")



Set colFileList = objWMIService.ExecQuery _

    ("ASSOCIATORS OF {Win32_Directory.Name='C:\Logs'} Where " _

        & "ResultClass = CIM_DataFile")



For Each objFile In colFileList

    strFilePath = objFile.Name

    Set objTextFile = objFSO.OpenTextFile(strFilePath, ForReading)

    Do Until objTextFile.AtEndOfStream

        strLine = objTextFile.ReadLine

    Loop

    strMessage = strMessage & strLine & vbCrLf

    objTextFile.Close

Next



Set objWord = CreateObject("Word.Application")

objWord.Visible = True

Set objDoc = objWord.Documents.Add()

strMessage = objWord.CleanString(strMessage)



Set objSelection = objWord.Selection

objSelection.TypeText strMessage
 Do początku strony Do początku strony

Centrum Skryptów - Microsoft Office