Linux - Friheden til at programmere i Java: Version 0.7.20040516 - 2020-12-31 | ||
---|---|---|
forrige | Kapitel 15. Datastrømme og filhåndtering | næste |
I pakken java.io findes omkring 40 klasser, der kan læse eller skrive binære eller tegnbaserede data fra et væld af datakilder eller -mål og på et væld af forskellige måder. Der henvises til javadokumentationen for en nærmere beskrivelse af de enkelte klasser.
Næsten alle metoderne i klasserne kan kaste en IOException-undtagelse, som skal fanges i en try-catch-blok (eller kastes videre som beskrevet i kapitlet om undtagelser).
Datastrømmene kan ordnes i fire grupper, og den konsistente navngivning gør dem lettere at overskue:
InputStream-objekter læser binære data. OutputStream-objekter skriver binære data.
Reader-objekter læser tekstdata. Writer-objekter skriver tekstdata.
Byte-baserede data som f.eks. billeder, lyde eller andre binære programdata håndteres af klasser, der arver fra InputStream eller OutputStream.
Af klassediagrammet ses, at metoderne i InputStream og OutputStream læser og skriver byte-data: write(byte[]) på OutputStream skriver et array (en række) af byte. Arvingerne har lignende metoder (disse er ikke vist).
InputStream og OutputStream er tegnet i kursiv. Det er fordi de er abstrakte klasser, og det betyder, at man ikke kan oprette InputStream og OutputStream-objekter direkte med f.eks. new InputStream(). I stedet skal man bruge en af nedarvingerne. Abstrakte klasser og metoder bliver behandlet i Kapitel 21, Avancerede klasser.
Tegn-baserede data bruges til tekstfiler, til at læse brugerinput og til meget netværkskommunikation. Dette håndteres af klasserne, der nedarver fra Reader og Writer.
Af klassediagrammet ses, at alle metoderne i Reader og Writer læser og skriver tegndata (datatype char). Tegn repræsenteres i Java som 16-bit unicode-værdier, og man kan derfor arbejde med ikke blot det vesteuropæiske tegnsæt, men også det østeuropæiske, kinesiske, russiske, ...
Klasserne til filhåndtering er FileInputStream, FileReader, FileOutputStream og FileWriter.
Med StringReader kan man læse data fra en streng, som om det kom fra en datastrøm. Det kan være praktisk til f.eks. at simulere indtastninger fra tastaturet under test (sml. Afsnit 15.3, Indlæsning fra tastatur).
StringReader tegnlæser = new StringReader("Jacob\n4\n5.14\n"); BufferedReader ind = new BufferedReader( tegnlæser );
StringWriter er en datastrøm, der gemmer uddata i et StringBuffer-objekt, der kan konverteres til en streng.
Et array er en liste eller række af noget (se Kapitel 9 om arrays). Ligesom man kan behandle en streng som en datastrøm, kan man også arbejde med et array som datakilde eller -mål. Klasserne CharArrayReader og CharArrayWriter hhv. læser og skriver fra et array af tegn, mens ByteArrayInputStream og ByteArrayOutputStream læser og skriver binært fra et array af byte.
Det er muligt at skrive hele objekter ned i en datastrøm. Objektet bliver da "serialiseret", dvs. dets data gemmes i datastrømmen. Refererer objektet til andre objekter, bliver disse også serialiseret og så fremdeles. Dette er nyttigt til at gemme en hel graf af objekter på disken for senere at hente den frem igen. Emnet vil blive behandlet mere i Kapitel 18Serialisering.
Klasserne BufferedInputStream, BufferedReader, BufferedOutputStream og BufferedWriter sørger for en buffer (et opsamlingsområde) til datastrømmen. Det sikrer mere effektiv indlæsning, fordi der bliver læst/skrevet større blokke data ad gangen.
BufferedReader sørger også for, at man kan læse en hel linje af datastrømmen ad gangen.
Nogen gange står man med en binær datastrøm og ønsker at arbejde med den, som om den var tekstbaseret. Der er to klasser, der konverterer til tegnbaseret indlæsning og -udlæsning:
InputStreamReader er et Reader-objekt, der læser fra en InputStream (byte til tegn).
OutputStreamWriter er et Writer-objekt, der skriver til en InputStream (tegn til byte).
Klasserne, der arver fra FilterOutputStream og FilterInputStream, sørger alle for en eller anden form for behandling og præsentation, der letter programmørens arbejde:
LineNumber-klasser tæller antallet af linjeskift i datastrømmen, men lader den ellers være uændret.
Pushback-klasser giver mulighed for at skubbe data tilbage i datastrømmen (nyttigt hvis man af en eller anden grund kan "komme til" at læse for langt).
SequenceInputStream tager to eller flere datakilder og læser dem i forlængelse af hinanden.
Piped-klasserne letter datakommunikationen mellem to tråde (samtidige programudførelsespunkter i et program) ved at sætte data "i kø" sådan, at en tråd kan læse fra datastrømmen og en anden skrive.
Checked-klasserne (i pakken java.util.zip) udregner en tjeksum på data. Det kan være nyttigt til at undersøge, om nogen eller noget har ændret data (f.eks. en cracker eller en dårlig diskette). Man skal angive et tjeksum-objekt, f.eks. Adler32 eller CRC32.
Zip-klasserne (i java.util.zip) læser og skriver ZIP-filer (lavet af f.eks. WinZip). De er lidt indviklede at bruge, da de er indrettet til at håndtere pakning af flere filer.
GZIP-klasserne (i java.util.zip) komprimerer og dekomprimerer data med Lempel-Ziv-kompression, kendt fra filer, der ender på .gz på UNIX-systemer (især Linux). Er nemmere at bruge end Zip-klasserne, hvis man kun ønsker at pakke én fil.
Filtreringsklasser skydes ind som ekstra "indpakning" mellem de andre datastrømme. F.eks. kan
PrintWriter ud= new PrintWriter(new FileOutputStream("fil"));
ændres til også at komprimere uddata, simpelthen ved at skyde et GZIPOutputStream-objekt ind:
PrintWriter ud=new PrintWriter(GZIPOutputStream(new(FileOutputStream("fil.gz"));