Centrum skryptów - Systemy operacyjne

Jak uczynić nazwę pliku pierwszym wierszem każdego pliku tekstowego znajdującego się w folderze? Udostępnij na: Facebook

Skrypciarze odpowiadają na Wasze pytania

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 uczynić nazwę pliku pierwszym wierszem każdego pliku tekstowego znajdującego się w folderze?

Cześć, Skrypciarze! Jak uczynić nazwę pliku pierwszym wierszem każdego pliku tekstowego znajdującego się w folderze?

-- DJ

Cześć, DJ. Tak w ogóle to mam nadzieję, że Wy macie lepszy dzień niż ja. A czy ja mam zły dzień? Można tak powiedzieć. Na przykład, dziś rano przeszedłem obok sklepu spożywczego, w którym codziennie kupuję pączki, nawet na niego nie spojrzawszy. Skrypciarz zapominający o kupieniu pączków?!? Jeżeli to nie jest zły omen, to ja nie wiem, co to oznacza.

Uwaga. Nie martwcie się: po jakimś czasie zawróciłem i w końcu kupiłem te pączki. Spóźniłem się przez to do pracy. Ale przecież w życiu trzeba mieć jakieś priorytety, nieprawdaż?

Możecie wierzyć lub nie, ale w miarę upływu czasu sprawy się pokomplikowały trochę bardziej. Postanowiłem więc posiedzieć w spokoju z moimi pączkami i poużalać się nad sobą. Jak się przekonałem, użalanie się nad sobą wcale nie jest takie fajne, jak myślałem. (Robi to tak wiele osób w tej firmie, że myślałem, że to naprawdę coś super.) Postanowiłem więc znaleźć sobie jakieś zajęcie dla zabicia czasu, żeby ten dzień się szybciej skończył. Wpadłem na to, że przecież mogę od razu odpowiedzieć na zadane pytanie, a nie czekać z tym do ostatniej chwili.

Zanim jednak zacznę, chciałbym wyjaśnić dzisiejsze założenia dotyczące naszej rubryki. Według wiadomości DJ, mamy serię plików tekstowych zawierających dane dotyczące temperatury. Te pliki wyglądają tak:

45.544 34.544 65.433 56.783

32.451 65.432 22.435. 44.564

DJ chce otrzymać skrypt, który sprawi, że dla wszystkich plików w tym folderze nazwa pliku stanie się pierwszym wierszem danego pliku tekstowego; w ten sposób te pliki będą mogły zostać zaimportowane do innego programu. Innymi słowy, DJ chce otrzymać serię plików tekstowych wyglądających mniej-więcej tak:

apr_avg_temp

45.544 34.544 65.433 56.783

32.451 65.432 22.435. 44.564

Pamiętacie, o czym śpiewali Rolling Stones, prawda? Nie można zawsze mieć tego, co się chce.

Na szczęście jednak, w tym przypadku, można. Oto skrypt, dzięki któremu nazwa pliku staje się pierwszym wierszem pliku tekstowego, i to w przypadku każdego pliku tekstowego znajdującego się w folderze:

Const ForReading = 1

Const ForWriting = 2



Set objFSO = CreateObject("Scripting.FileSystemObject")



strComputer = "."



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



Set colFiles = objWMIService.ExecQuery _

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

        & "ResultClass = CIM_DataFile")



For Each objFile in colFiles

    strFileName = objFile.FileName

    strFilePath = objFile.Name



    Set objFile = objFSo.OpenTextFile(strFilePath, ForReading)

    strContents = objFile.ReadAll

    objFile.Close

    

    Set objFile = objFSo.OpenTextFile(strFilePath, ForWriting)

    strContents = strFileName & vbCrLf & strContents

    objFile.Write strContents

    objFile.Close

Next
Uwaga. Czy to Was chociaż trochę rozweseliło? Na pewno. Ale w końcu kogo nie rozwesela, przynajmniej odrobinę, widok skryptu wykorzystującego zarówno usługę WMI, jak również obiekt FileSystemObject?

Jak działa ten skrypt? Zaraz o tym opowiem. Ten skrypt rozpoczyna się od zdefiniowania pary stałych, ForReading oraz ForWriting; wykorzystamy je podczas odczytu z pliku i zapisu do każdego pliku tekstowego. Po zdefiniowaniu pary stałych tworzymy wystąpienie obiektu Scripting.FileSystemObject, który umożliwi nam odczyt i zapis do plików tekstowych.

Naszym następnym zadaniem jest połączenie się z usługą WMI na lokalnym komputerze. Zazwyczaj, kiedy piszę o usłudze WMI, następne zdanie to coś w tym stylu:

„Oczywiście, ten skrypt zadziała także na zdalnym komputerze.”

Tym razem niestety nie będzie to nasze następne zdanie. Zamiast tego, następne zdanie brzmi tak:

„Zanim zapytacie: nie, ten skrypt nie zadziała na zdalnym komputerze, przynajmniej nie bez wprowadzenia większych zmian w kodzie.”

Zatem dlaczego nie można uruchomić tego skryptu na zdalnym komputerze? Czy usługa WMI nie może pobrać kolekcji plików ze zdalnego komputera?

No cóż, usługa WMI może pobrać kolekcję plików ze zdalnego komputera. Jednak w tym przypadku to nie usługa WMI jest tutaj winna, problem jest z obiektem FileSystemObject, który może pracować tylko z lokalnymi plikami na lokalnym komputerze. Nie oznacza to, że wykonanie tego zadania jest niemożliwe na zdalnym komputerze; jak już mówiłem, można to zrobić, ale to wymagałoby wprowadzenia sporych zmian w kodzie. Jeżeli będzie wystarczające zainteresowanie uruchomieniem tego skryptu na zdalnych komputerach, zobaczę, co da się z tym zrobić. Tymczasem zajrzyjcie do tego artykułu rubryki Cześć Skrypciarze!, w którym jest mowa o pracy z plikami tekstowymi na zdalnych komputerach.

Po połączeniu się z usługą WMI stosujemy poniższy wiersz kodu (oraz jedną z dziwnie wyglądających kwerend Associators Of) w celu pobrania kolekcji wszystkich plików znajdujących się w folderze C:\TemperatureData:

Set colFiles = objWMIService.ExecQuery _

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

        & "ResultClass = CIM_DataFile")

Teraz w końcu możemy się zabrać za poważną robotę.

Teraz musimy uruchomić pętlę For Each, która przejdzie przez kolekcję plików znajdujących się w folderze C:\TemperatureData. A co robimy wewnątrz tej pętli? Na początek to:

strFileName = objFile.FileName

strFilePath = objFile.Name

W pierwszym wierszu przypisujemy wartość właściwości FileName do zmiennej o nazwie strFileName. W usłudze WMI, właściwość FileName to po prostu nazwa pliku niezawierająca rozszerzenia. Przykładowo, załóżmy, ze mamy plik C:\TemperatureData\Apr_avg_temp.txt. Jaka jest wartość właściwości FileName dla tego pliku? Apr_avg_temp.

W drugim wierszu, przypisujemy wartość właściwości Name do zmiennej o nazwie strFilePath. Nazwa tej właściwości (Name) jest tak naprawdę trochę myląca. W usłudze WMI nazwa Name pliku jest taka sama, jak ścieżka pliku. Oznacza to, że plik C:\TemperatureData\Apr_avg_temp.txt posiada nazwę, no cóż C:\TemperatureData\Apr_avg_temp.txt.

Od razu po przypisaniu wartości do tych dwóch zmiennych, wywołujemy metodę OpenTextFile w celu otwarcia pierwszego pliku z kolekcji; do tego służy nam poniższy wiersz kodu:

Set objFile = objFSo.OpenTextFile(strFilePath, ForReading)

Po otwarciu pliku stosujemy metodę ReadAll w celu dokonania odczytu całej zawartości pliku i zachowujemy tę zawartość z zmiennej o sprytnej nazwie strContents. (Dlaczego wczytujemy całą zawartość pliku do zmiennej? O tym za moment.) Teraz wywołujemy metodę Close w celu zamknięcia pliku.

Jeszcze jedno pytanie: dlaczego zamykamy plik? Przecież ciągle nazwa pliku nie jest pierwszym wierszem pliku tekstowego.

No tak, zostało nam jeszcze to. Jednakże na początku otworzyliśmy ten plik do odczytu, żeby można było odczytać jego zawartość. Za pomocą obiektu FileSystemObject można otworzyć plik do odczytu lub do zapisu, ale nie można otworzyć pliku do odczytu oraz do zapisu. Konieczne jest otwarcie pliku do odczytu, odczytanie jego zawartości, a następnie zamknięcie pliku. Następnie możemy ponownie otworzyć plik, tym razem do zapisu.

Tak się składa, że robimy to za pomocą poniższego wiersza kodu:

Set objFile = objFSo.OpenTextFile(strFilePath, ForWriting)

Teraz z kolei możemy przejść do tego wiersza kodu:

strContents = strFileName & vbCrLf & strContents

Jak zaobserwowaliśmy, obiekt FileSystemObject jest trochę kapryśny. Z jednej strony nie pozwala otworzyć pliku do odczytu oraz do zapisu; a do tego jeszcze nie pozwala na selektywną modyfikację pliku. Jedynym sposobem na dokonanie zmian w pliku jest wczytanie jego zawartości do pamięci, wprowadzenie zmian, a następnie ponowne wpisanie całego pliku. To wyjaśnia, dlaczego wczytaliśmy całą zawartość pliku do pamięci: wszystkie zmiany musimy wprowadzić w pamięci.

O wyjaśnia także kod, który właśnie Wam pokazałem: w tym wierszu rekonstruujemy zawartość naszego nowego pliku poprzez połączenie:

  • Nazwy pliku (zachowanej w zmiennej strFileName).
  • Znaku powrotu karetki (reprezentowanego przez stałą skryptu VBScript – vbCrLf).
  • Istniejącej zawartości pliku (zachowanej w zmiennej strContents).

Poskładane do kupy daje nam zmienną strContents wyglądającą tak:

apr_avg_temp

45.544 34.544 65.433 56.783

32.451 65.432 22.435. 44.564

Owszem, skoro już o tym mowa, jest to dokładnie to, co chcieliśmy osiągnąć, nieprawdaż? To dobrze, ponieważ oznacza to, że teraz wystarczy tylko wywołać metodę Write w celu zastąpienia istniejącej zawartości pierwszego pliku nowo-zmodyfikowaną zawartością znajdującą się w pamięci:

objFile.Write strContents

Teraz po prostu zamykamy plik, wracamy na początek pętli i powtarzamy proces dla następnego pliku znajdującego się kolekcji.

I to powinno wystarczyć. DJ. Jeżeli o mnie chodzi, to naprawdę nie ma się czym martwić, prędzej czy później wszystko znowu będzie dobrze, w najgorszym wypadku w czwartek rano, kiedy to wsiądę do samolotu lecącego do Barcelony na forum informatyczne TechEd (j.ang.). Zobaczmy, co mnie czeka: odprawa na lotnisku, posiłek linii lotniczych, 4½ godziny lotu do Atlanty, 3 godziny czekania na lotnisku w Atlancie, 9 godzin lotu przez Atlantyk – wszystko będzie lepsze niż dzisiejszy dzień. Do zobaczenia jutro.

 Do początku strony Do początku strony

Centrum skryptów - Systemy operacyjne