1 1 Pliki i katalogi K. Barteczko 2009 -2010
2 2 Pojęcie pliku Plik - to ciąg bajtów zapisanych na dysku lub w innej fizycznie trwałej formie. po co są pliki separacja danych od kodu, utrwalanie i przenoszenie danych znaczenie bajtów pliki binarne pliki tekstowe strony kodowe Unicode a inne systemy kodowania domyślna strona kodowa kodowanie i dekodowanie
3 3 Obiekty typu File Pliki i katalogi są reprezentowane przez obiekty typu File. f1 = new File('text.txt') def f1 = new File('text.txt') File f1 = new File('text.txt') f2 = new File('c:\\src\\Prog.groovy') f2 = new File('c:/src/Prog.groovy') f3 = new File('sub/Some.txt') f4 = new File('../Some.txt') cdir = new File('.') someDir = new File('c:/temp') Obiekty typu File mogą oznaczać istniejące lub nie istniejące pliki (wtedy plik jest tworzony dopiero w momencie zapisywania do niego) albo istniejące lub nieistniejące katalogi. Z bieżącego katalogu Z podanego katalogu Z podkatalogu sub bieżącego katalogu Z nadkatalogu bieżącego katalogu Nazwa pliku Katalogi
4 4 Czytanie plików tekstowych def file = new File(...) def cont = file.getText() def cont = file.text // skrót def lineList = file.readLines() file.eachLine { line -> // process line } file.splitEachLine(sep) { tokenListInLine -> // process token list } Wczytanie całego pliku naraz Uzyskanie listy wierszy Przetwarzanie wiersz po wierszu w domknięciu Przetwarzanie z rozbiorem wierszy
5 5 Przykład 1 def file = new File('test1.txt') def cont = file.getText() if (cont.indexOf('23-10-15')) println 'Number found' def lines = file.readLines() println 'There are ' + lines.size() + ' lines.' lines.eachWithIndex { line, i -> println "${i+1} $line" } println 'List of lines starting with "J"' jlist = [] file.eachLine { if (it.startsWith('J')) jlist
6 6 Przykład 2 import static javax.swing.JOptionPane.*; def file = new File('test1.txt') def map = [:] file.splitEachLine('\t') { tokens -> name = tokens[0].tokenize() map[name[1]+' '+name[0]] = tokens[1] } while ((inp = showInputDialog('Enter name')) != null) { name = inp.tokenize().join(' ') num = map[name] ?: 'Not found' showMessageDialog(null, "$name\n$num") }
7 7 Zapisywanie plików tekstowych def file = new File(...) // Metody nadpisujące (lub tworzące nowy plik) file.setText(txt) file.text = txt // skrót file.write(txt) // Metoda dopisujące file.append(txt) // Operator
8 8 Przykład zapisywania plików def file = new File('test2.txt') def lines = ['aaa', 'bbb'] def cont = lines.join('\n') file.text = cont // creating and writineg showFile file file.append('\nccc') // appending file.append(111) // can append any Object showFile file file
9 9 Problem końca wiersza Normalnie LF (\n). Różne platformy różnie (LF, CRLF, CR). Niezależnie od platformy: 1) używać System.getProperty('line.separator') 2) normalizować i denormalizować napisy wielowierszowe def f1 = new File('normalized.txt') def f2 = new File('platform.txt') def txt = 'a\nb\nc' f1.text = txt f2.text = txt.denormalize() println 'Normal separator is: ' + '\n'.bytes println 'Platform line separator is ' + System.getProperty('line.separator').bytes println 'f1 byte cont is: ' + f1.text.bytes println 'f2 byte cont is: ' + f2.text.bytes def norm = f2.text.normalize() println 'Normalized f2 byte cont: ' + norm.bytes Output: Normal separator is: [10] Platform line separator is [13, 10] f1 byte cont is: [97, 10, 98, 10, 99] f2 byte cont is: [97, 13, 10, 98, 13, 10, 99] Normalized f2 byte cont: [97, 10, 98, 10, 99] Pobór wartości bajtów. Widać je tu - to są kody znaków (CR = 10, LF =13 Bajty z pliku można też pobierać metodą eachByte.
10 10 Dekodowanie - kodowanie Normalnie czytanie, pisanie plików używa domyślnej strony kodowej. Czasem to nie wystarcza Kodowanie: Unicode -> wybrana strona kodowa Dekodowanie: wybrana strona kodowa -> Unicode def file = new File(...) def cont = file.getText(charset) // dekodowanie file.write(txt, charset) // kodowanie file.append(txt, charset) // kodowanie Przykładowe charsety: 'ISO-8859-1', 'cp1250', 'UTF-8' Zobaczyć wszystkie: import java.nio.charset.*; def chs = Charset.availableCharsets() chs.each { println it.key + ' ' + it.value.aliases() }
11 11 Przykład: użyteczne narzędzie Uniwersalny kawałek kodu do zmiany kodowania plików: def changeEncoding(inFile, cpin, outFile, cpout) { def cont = inFile.getText(cpin) outFile.write(cont, cpout) } Przykładowe wywołanie: changeEncoding(new File('windows-1250.html'), 'cp1250', new File('iso-8859-2.html'), 'ISO-8859-2')
12 12 Pojęcie o strumieniach Strumień - ogólniejsza abstrakcja odczytu-zapisu danych. Źródła bądź odbiorniki danych mogą być różnorodne: plik, pamięć operacyjna, potoki, URL, gniazdo sieciowie. Przy odczycie - zapisie - można dokonywać transformacji danych. Strumienie są reprezentowane przez klasy strumieniowe, które tworzą hierarchie. Początkowe klasy tych hierarchii:
13 13 Rodzaje strumieni
14 14 Użycie strumieni w operacjach na plikach 1) file dos.writeInt(ints.size()) ints.each { dos.writeInt(it) } } def bytes = [] file.eachByte { bytes n = dis.readInt() n.times { sum += dis.readInt() } println sum Result: [0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3] 6 [0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3] 6 3) serializacja (utrwalenie) obiektów def f = new File('o.ser') def d = new Date() def list = [1,2,3] f.withObjectOutputStream { it.writeObject(d) it.writeObject(list) } olist = [] f.eachObject { olist
15 15 Pliki - zarządzanie zasobami 1) otwarcie pliku 2) operacje 3) zamknięcie pliku (i np. wymiatanie buforów) Omówione metody (setText(), getText(), each.., with...) biorą to na siebie. Ponadto nie wymuszają obsługi błędów (wyjątków).
16 16 Inne metody klasy File Najważniejsze: exists() // czy istnieje? getName() // nazwa getCanonicalPath() // pełna ścieżka isDirectory() // czy to katalog lastModified() // data ostatniej modyfikacji length() lub size() // rozmiar w bajtach mkdir(...) // utwórz katalog mkdirs(...) // utwórz katalog z wszystkimi nadkatalogami delete() // usuń plik deleteDir() // usun katalog z całą zawartością renameTo(...) // zmień nazwę Uwaga: do metod getProp() bez argumentów można odwoływac się f.prop
17 17 Przykład def fnames = ['c:/ppp/ppp', '.', 'test1.txt', 'src'] fnames.each { showProps(it) } def showProps(fname) { println "Passed filename is: $fname" def f = new File(fname) println f.name println f.path println f.absolutePath println f.canonicalPath if (f.exists()) { println f.isDirectory() println f.size() println f.lastModified() } else println "File doesn't exists" } Passed filename is: c:/ppp/ppp ppp c:\ppp\ppp C:\ppp\ppp File doesn't exists Passed filename is:.. E:\cdir true 0 1250325759531 Passed filename is: test1.txt test1.txt E:\cdir\test1.txt false 76 1250134599468 Passed filename is: src src E:\cdir\src true 0 1250328771000
18 18 Przeglądanie katalogów def dir = new File(dir) Metody: def list = list(...) // lista plików w katalogu (Java) dir.eachFile { closure } // dla każdego pliku wykonaj dir.eachDir { closure } // dla każdego katalogu wykonaj dir.eachFileRecurse { closure } // j.w. wchodząc w podkatalogi dir.eachDirRecurse { closure } dir.eachFileMatch(filter) { closure } // o nazwach wg filtra dir.eachDirMatch(filter) { closure }
19 19 Przykład 1 def dir = new File('../TestDir') print '\n--- eachFile --- ' dir.eachFile { show(it) } print '\n--- eachDir --- ' dir.eachDir { show(it) } print '\n--- eachFileRec --- ' dir.eachFileRecurse { show(it) } print '\n--- eachDirRec --- ' dir.eachDirRecurse { show(it) } def show(f) { print '\n' + f.name if (f.isDirectory()) print ' - dir' } --- eachFile --- Calc1.groovy Join.groovy LineSplit.groovy normalized.txt platform.txt subDir1 - dir subDir2 - dir --- eachDir --- subDir1 - dir subDir2 - dir --- eachFileRec --- Calc1.groovy Join.groovy LineSplit.groovy normalized.txt platform.txt subDir1 - dir ClipTest.class LitZn.class subDir2 - dir ClipTest.java LitZn.java subDir21 - dir p.txt --- eachDirRec --- subDir1 - dir subDir2 - dir subDir21 - dir
20 20 each...Match eachFileMatch(filter) { closure} filter - jak klasyfikator w switch (testowana jest nazwa pliku) def dir = new File('../TestDir') def list = [] dir.eachFileMatch( ~/\w+\.groovy/) { if (it.text.contains('[')) list