3.1. Ievade/izvade

Ievads

Mērķi

  • Uzrakstīt programmu, kura lasa no standartievades (standard input)
  • Uzrakstīt programmu, kura var izveidot, lasīt un rakstīt failus
  • Aprakstīt galvenās iezīmes pakotnei java.io
  • Izveidot ieteku (source) un izteku (sink) un apstrādes plūsmas, atbilstoši tās lietot
  • Atšķirt lasītājus un rakstītājus no plūsmām un tos atbilstoši izvēlēties

Ievadjautājumi

  • Uzrakstīt programmu, kura lasa no standartievades
  • Uzrakstīt programmu, kura var veidot, lasīt un rakstīt failus
  • Kādi mehānismi ir pieejami Javā, lai lasītu un rakstītu ar ietekām (un iztekām), kuras nav faili?
  • Kā ievades/izvades darbības atbalsta dažādas kodu tablulas?
  • Kāda ir simbolu un baitu plūsmu iespējamās ietekas un iztekas.

Konsoles ievade/izvade

  • System.out ļauj rakstīt uz standartizvadi (standard output). System.out ir PrintStream objekts.
  • System.in ļauj lasīt no standartievades (standard input). Tas ir InputStream objekts.
  • System.err ļauj rakstīt uz "kļūdu izvadi". Tas ir PrintStream objekts.

Teksta apstrādes programmās standartizvadi (STDOUT) parasti lieto, lai izvadītu derīgo galarezultātu, ko var redirektēt ierakstīšanai failā. Savukārt kļūdu izvadi (STDERR) lieto kļūdu un citu paziņojumu izvadei, kas nepieder pie programmas derīgā galarezultāta. Piemērs komandrindai (gan UNIX, gan DOS), kas redirektē programmas "mypackage.SomeClass" izvadi failā out.txt:

java mypackage.SomeClass arg1 arg2 > out.txt

Ja izvade (piemēram, System.out) nav redirektēta failā (t.i. komandrindas beigās nav rakstīts "> ..."), tad STDOUT un STDERR paziņojumi var parādīties uz konsoles kaut kādā secībā (plūsma STDOUT turklāt var nebūt hronologjiski saskaņota ar STDOUT, ja izvade tiek buferizēta).

Eclipse konsole STDOUT izvadi drukā melnā krāsā, bet STDERR izvadi - sarkanā.

Rakstīšana uz standartizvadi

  • println metodes drukā argumentu un rindas pārnesumu (\n vai \r\n).
  • print metodes drukā argumentu bez rindas pārnesuma
  • print un println metodes ir pārslogotas vairumam primitīvo tipu: boolean, char, int, long, float un double, kā arī char[], Object un String.
  • print(Object) un println(Object) metodes izsauc toString metodi uz sava argumenta

Lasīšana no standartievades

1  import java.io.*;
2  
3  public class KeyboardInput {
4      public static void main (String args[]) {
5          String s;
6          // Izveidot "BufferedReader" instanci, kura 
7          // lasa katru rindu no klaviatūras
8          InputStreamReader ir = new InputStreamReader(System.in);
9          BufferedReader in = new BufferedReader(ir);
10  
11         System.out.println("Unix: Ievades beigas: ctrl-d vai ctrl-c.");
12         System.out.println("Windows: Ievades beigas: ctrl-z.");
13         try {
14             // Nolasām rindiņu un atbalsojam to uz konsoles
15             s = in.readLine();
16             while ( s != null ) {
17                 System.out.println("Read: " + s);
18                 s = in.readLine();
19             }
20  
21             // Aizver "BufferedReader"
22             in.close();
23         } catch (IOException e) { // Noķeram I/O izņēmumus
24             e.printStackTrace();
25         }
26     }
27 }

Faili un failu ievade/izvade

  • java.io pakotne
  • File objektu radīšana
  • File objektu manipulācijas
  • Rakstīšana un lasīšana failu plūsmās

Jauna File objekta veidošana

  • File myFile;
  • myFile = new File("myfile.txt");
  • myFile = new File("MyDocs", "myfile.txt");
  • Direktorijas Javā uztver tāpat kā failus; File klase atbalsta metodes, kuras atgriež direktorijas saturu kā masīvu
File myDir = new File("MyDocs");
myFile = new File(myDir, "myfile.txt");

File objekti ir piemēroti augsta līmeņa manipulācijām ar failiem un direktorijām (direktoriju satura uzskaitīšanai, faila parametru noskaidrošanai, utml.). Lai lasītu vai rakstītu faila saturu, ir jāizmanto ievades/izvades plūsmas (InputStream/OutputStream apakšklases) vai arī simbolisko datu ievade/izvade (Reader/Writer apakšklases) - par tām stāstīts tālāk šajā materiālā.

Pārbaudes un utilītmetodes klasē File

File vārdu noskaidrošana:

String getName()
String getPath()
String getAbsolutePath()
String getParent()
boolean renameTo(File newName)

File pārbaudes:

boolean exists()
boolean canWrite()
boolean canRead()
boolean isFile()
boolean isDirectory()
boolean isAbsolute();

Citas metodes:

long lastModified()
long length()
boolean delete()

Direktoriju utilītmetodes:

boolean mkdir()
String[] list()

Failu plūsmu ievade/izvade

Failu ievade:

  • Lietot FileReader klasi, lai lasītu simbolus
  • Izmantot BufferedReader klasi, lai lietotu readLine metodi

Failu izvade:

  • Lietot FileWriter klasi, lai rakstītu simbolus
  • Izmantot PrintWriter klasi, lai lietotu print un println metodes

Faila ievades piemērs

1  import java.io.*;
2  public class ReadFile {
3      public static void main (String[] args) {
4          // Izveido "File" objektu
5          File file = new File(args[0]);
6  
7          try {
8              // Izveido buferizētu lasītāju, lai lasītu pa rindiņām
9              BufferedReader in = new BufferedReader(new FileReader(file));
10             String s;
11  
12             // Nolasa rindiņu un atbalso to uz ekrāna
13             s = in.readLine();
14             while ( s != null ) {
15                 System.out.println("Read: " + s);
16                 s = in.readLine();
17             }
18             // Aizver buferizētu lasītāju, kurš aizver arī faila lasītāju
19             in.close();
20  
21         } catch (FileNotFoundException e1) {
22             // Ja fails neeksistē
23             System.err.println("File not found: " + file);
24  
25         } catch (IOException e2) {
26             // Apstrādā citus I/O izņēmumus
27             e2.printStackTrace();
28         }
29     }
30 }

Faila izvades piemērs

1  import java.io.*;
2  
3  public class WriteFile {
4      public static void main (String[] args) {
5          // Izveido "File" instanci
6          File file = new File(args[0]);
7  
8          try {
9              // Izveido buferizētu lasītāju lasīšanai no standartievades
10             BufferedReader in
11                 = new BufferedReader(new InputStreamReader(System.in));
12             // Izveido 'PrintWriter' instanci šim failam
13             PrintWriter out
14                 = new PrintWriter(new FileWriter(file));
15             String s;
16  
17             System.out.print("Ievadiet tekstu  ");
18             System.out.println("[Ievades beigas: Ctrl-z]");
19  
20             // Lasīt pa rindiņām un izvadīt tās failā 
21             while ((s = in.readLine()) != null) {
22                 out.println(s);
23             }
24  
25             // Aizvērt konsoles lasītāju un faila rakstītāju
26             in.close();
27             out.close();
28  
29         } catch (IOException e) {
30             // Apstrādā I/O izņēmumus
31             e.printStackTrace();
32         }
33     }
34 }

Ievades/izvades pamati

  • Plūsmu (stream) var iztēloties kā datu plūsmu no ietekas (source) uz izteku (sink).
  • Ietekas plūsma (source stream) uzsāk datu plūsmu, to sauc arī par ievades plūsmu.
  • Iztekas plūsma (sink stream) beidz datu plūsmu, to sauc arī par izvades plūsmu.
  • Ietekas un iztekas sauc par virsotnes plūsmām (node stream)
  • Virsotnes plūsmu piemēri ir faili, atmiņas masīvi, kā arī trubas (pipe) starp pavedieniem vai procesiem.

Plūsmu pamatklases

Byte StreamsCharacter Streams
Source StreamsInputStreamReader
Sink StreamsOutputStreamWriter

Dati plūsmās

  • Javas tehnoloģija atbalsta divu tipu plūsmas: simbolu un baitu plūsmas.
  • Simbolu datu ievadi un izvadi nodrošina lasītāji (reader) un rakstītāji (writer)
  • Baitu datu ievadi un izvadi apstrādā ievades plūsmas (input stream) un izvades plūsmas (output stream)
  • Parasti jēdzienu plūsma (stream) attiecina uz baitu plūsmu
  • Jēdzienus lasītājs (reader) un rakstītājs (writer) attiecina uz simbolu plūsmām.

InputStream metodes

Trīs galvenās read metodes:

int read()
int read(byte[] buffer)
int read(byte[] buffer, int offset, int length)

Citas metodes:

void close()
int available()
skip(long n)
boolean markSupported()
void mark(int readlimit)
void reset()

Izmantojot mark/reset metodes, no plūsmas zināmu gabalu var nolasīt atkārtoti.

OutputStream metodes

Trīs galvenās write metodes:

void write(int c)
void write(byte[] buffer)
void write(byte[] buffer, int offset, int length)

Citas metodes:

void close()
void flush()

Reader metodes

Trīs galvenās read metodes:

int read()
int read(char[] cbuf)
int read(char[] cbuf, int offset, int length)

citas metodes:

void close()
boolean ready()
skip(long n)
boolean markSupported()
void mark(int readAheadLimit)
void reset()

Writer metodes

Galvenās write metodes:

void write(int c)
void write(char[] cbuf)
void write(char[] cbuf, int offset, int length)
void write(String string)
void write(String string, int offset, int length)

Citas metodes:

void close()
void flush()

Citas plūsmas

TipsSimbolu plūsmasBaitu plūsmas
FailsFileReader
FileWriter
FileInputStream
FileOutputStream
Atmiņa: MasīvsCharArrayReader
CharArrayWriter
ByteArrayInputStream
ByteArrayOutputStream
Atmiņa: StringsStringReader
StringWriter
TrubaPipedReader
PipedWriter
PipedInputStream
PipedOutputStream

Vienkāršs piemērs

Šī programma veic vienkāršu failu kopēšanu:

java TestNodeStreams file1 file2
1  import java.io.*;
2
3  public class TestNodeStreams {
4      public static void main(String[] args) {
5          try {
6              FileReader input = new FileReader(args[0]);
7              FileWriter output = new FileWriter(args[1]);
8              char[] buffer = new char[128];
9              int charsRead;
10
11             // nolasa pirmo buferi
12             charsRead = input.read(buffer);
13
14             while ( charsRead != -1 ) {
15                 // raksta buferi izejas failā
16                 output.write(buffer, 0, charsRead);
17
18                 // nolasa nākošo buferi
19                 charsRead = input.read(buffer);
20             }
21
22             input.close();
23             output.close();
24         } catch (IOException e) {
25             e.printStackTrace();
26         }
27     }
28 }

Simbolu lasīšana no failiem ar FileReader notiek platformas "noklusētajā kodējumā". Ja gribam konkrētu kodējumu, Reader instance jākonstruē no FileInputStream.

Buferizētas plūsmas

java TestBufferedStreams file1 file2
1   import java.io.*;
2
3   public class TestBufferedStreams {
4       public static void main(String[] args) {
5           try {
6               FileReader     input     = new FileReader(args[0]);
7               BufferedReader bufInput  = new BufferedReader(input);
8               FileWriter     output    = new FileWriter(args[1]);
9               BufferedWriter bufOutput = new BufferedWriter(output);
10              String line;
11
12              // nolasa pirmo rindiņu
13              line = bufInput.readLine();
14
15              while ( line != null ) {
16                  // write the line out to the output file
17                  bufOutput.write(line, 0, line.length());
18                  bufOutput.newLine();
19
20                  // nolasa nākamo rindiņu
21                  line = bufInput.readLine();
22              }
23
24              bufInput.close();
25              bufOutput.close();
26          } catch (IOException e) {
27              e.printStackTrace();
28          }
29      }
30  }

Ievades/izvades plūsmu sakabināšana

Plūsmu sakabināšana

Apstrādes plūsmas

TipsSimbolu plūsmasBaitu plūsmas
BuferizācijaBufferedReader
BufferedWriter
BufferedOutputStream
BufferedInputStream
FiltrēšanaFilterReader
FilterWriter
FilterOutputStream
FilterInputStream
Pārveidošana starp
baitiem un simboliem
InputStreamReader
OuptutStreamWriter
Objektu serializācijaObjectInputStream
ObjectOutputStream
Datu pārveidošanaDataInputStream
DataOutputStream
SkaitīšanaLineNumberReaderLineNumberInputStream
Iepriekšēja SkatīšanāsPushbackReaderPushbackInputStream
Drukāšana teksta failāPrintWriterPrintStream

InputStream klašu hierarhija

'InputStream' klašu hierarhija

OutputStream klašu hierarhija

'OutputStream' klašu hierarhija

Reader klašu hierarhija

'Reader' klašu hierarhija

Writer klašu hierarhija

'Writer' klašu hierarhija

Jautājumi paškontrolei

  • Raksturot pakotnes java.io galvenās iezīmes
  • Izveidot virsotnes plūsmas un apstrādes plūsmas, un tās atbilstoši lietot
  • Atšķirt lasītājus un rakstītājus no plūsmām un izvēlēties atbilstošāko ievades/izvades veidu.

Diskusiju tēmas:

  • Daudzas aplikācijas balstās uz teksta apstrādi. Kādi ir citi programmu veidi?
  • Kā šajā nodaļā tika lietoti interfesi? Vai tos var aizstāt ar citu mehānismu, piemēram, ar abstraktām klasēm?
  • Vai jūsu aplikācijās var lietot specializētus plūsmu vai simbolu filtrus?