Лекция 05. Ввод/вывод
#######################################################################################



Введение
===========================================================


Классификация ВВ
``````````````````````````````````````````````````````````

Под вводом/выводом понимают часть стандартной библиотеки пакетов, предоставляющей средства для обмена информацией между устройствами ввода/вывода, а также файлами.


Основной абстракцией в этом процессе является **поток**. Потоки могут быть **буферизированные** и **небуферизированные**. Первые используют промежуточные хранилища (буферы), а вторые - нет.


Также потоки могут быть **байтовые** и **символьные**. Первые рассматривают данные как наборы байт, вторые умеют работать с данными, как с символами. Это важно при использование многобайтных кодировок.
Рассмотрим потоки применительно к трем областям:


* Низкоуровневый ввод/вывод.
* Консольный ввод/вывод.
* Файловый ввод/вывод.

Stream
``````````````````````````````````````````````````````````

Во главе иерархии **байтовых** потоков ввода/вывода лежат


#. **InputStream** - абстрактный поток ввода.
#. **OutputStream** - абстрактный поток вывода.

Во главе иерархии **символьных** потоков ввода/вывода лежат


#. **Reader** - абстрактный поток ввода.
#. **Writer** - абстрактный поток вывода.


Байтовые потоки
``````````````````````````````````````````````````````````

Абстрактный класс **InputStream**



.. code-block:: java

 //Читает 1 байт из вх. потока. Результат в младшем байте. 
 public abstract int read() throws IOException 
 
 //Читает послед-ть байт в массив b[ ]. 
 // Возвращает кол-во прочитанных байт или -1.  
 public int read (byte[ ] b) throws IOException 
 
 //Заполняет массив с указанного байта, 
 //читает не более len символов  
 public int read (byte[ ] b, int off, int len) throws IOException
 
 // пропускает n байтов в потоке
 public long skip (long n) throws IOException 
 
 // количество доступных байтов
 int available () 
 
 void close ()



OutputStream
``````````````````````````````````````````````````````````



.. code-block:: java

 
 // Записывает 1 байт в выходной поток.  
 public abstract void write (int b) throws IOException
 
 // Записывает в поток массив байт
 public void write (byte[ ] b) throws IOException
 
 // Записывает часть массива в поток 
 // (len элементов начиная с элемента off)
 public void write (byte[ ] b, int off, int len)  throws IOException
 
 //Немедленно выталкивает из буфера в поток 
 //все что накоплено в буфере. 
 public void flush() throws IOException
 
 //Закрывает поток. 
 public void close() throws IOException



Низкоуровневый ввод/вывод
===========================================================


ByteArrayInputStream
``````````````````````````````````````````````````````````

**ByteArrayInputStream** – это реализация входного потока, в

котором в качестве источника используется массив типа 

**byte**. У этого класса два конструктора, каждый из которых 

в качестве первого параметра требует байтовый массив. 




.. code-block:: java

 ByteArrayInputStream(byte array[ ])
 ByteArrayInputStream(byte array[ ], 
                      int start, int numBytes)




.. code-block:: java

 import java.io.*;
 public class Program {
   public static void main(String[] arg) {
     byte [] arr={1,2,3,14,14,16,17,81,82,83};
       ByteArrayInputStream in=new ByteArrayInputStream(arr);
       ByteArrayOutputStream out=new ByteArrayOutputStream();
       System.out.println(in.available());
       int b; 
       while((b=in.read())!=-1)
         out.write(b);
       out.write(10);
       byte [] c=out.toByteArray();
       for(byte i:c)
         System.out.println((char)i);
    }
 }



ByteArrayOutputStream
``````````````````````````````````````````````````````````

Выходной поток имеет два конструктора:



.. code-block:: java

 ByteArrayOutputStream() 
 ByteArrayOutputStream(int size)




.. code-block:: java

 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 String text = "Hello Wolrd!";
 byte[] buffer = text.getBytes();
 try{
     baos.write(buffer);
 }
 catch(Exception ex){      
     System.out.println(ex.getMessage());
 }
 // превращаем массив байтов в строку
 System.out.println(baos.toString());
          
 // получаем массив байтов и выводим по символьно
 byte[] array = baos.toByteArray();


Метод, записывающий содержимое одного потока в другой:



.. code-block:: java

 public void writeTo(OutputStream out) throws IOException




.. code-block:: java

 byte buf [ ] = {'a','b','c','d'};
 ByteArrayOutputStream b = new ByteArrayOutputStream();
 b.write(buf);
 FileOutputStream f = new FileOutputStream("result.txt");
 b.writeTo(f);  



Консольный ввод/вывод
===========================================================


Р’РІРѕРґ
-----------------------------------------------------------


Консольный ВВ
``````````````````````````````````````````````````````````

Два примера консольного ввода:


#. **Классический**
#. **Современный**



.. code-block:: java

 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
 
 public class Main {
    public static void main(String[] args) throws IOException
    {
       System.out.println("Hello, enter your name:");
       String buf;
       BufferedReader in=new BufferedReader(
          new InputStreamReader(System.in));
       buf=in.readLine();
       System.out.println("Hello, "+buf);
    }


Еще один вариант:



.. code-block:: java

 import java.io.*;
 
 public class ReadConsole {
    public static void main(String args[]) throws IOException
    {
       InputStreamReader cin = null;  char c;
       try {
          cin = new InputStreamReader(System.in);
          System.out.println("Enter characters, 'q' to quit.");
          do {
             c = (char) cin.read();
             System.out.print(c);
          } while(c != 'q');
       }finally {
          if (cin != null) {
             cin.close();
          }
       }
    }
 }


Более современный вариант:



.. code-block:: java

 import java.util.Scanner;
 
 public class Main {
     public static void main(String[] args) {
       System.out.println("Enter a line:");
       String buf;
       Scanner in = new Scanner(System.in);
       buf=in.nextLine();
       System.out.println("Hello, "+buf);
     }
 }




.. code-block:: java

    System.out.println("How old are you?");
    int age=0;
    try {
        age=Integer.parseInt(in.readLine());
    }
    catch(NumberFormatException ex) {
        System.out.println("Wrong age!");
        System.exit(1);
    }
    System.out.printf("Good age %d",age);
   }
 }



Вывод
-----------------------------------------------------------


Консольный ВВ
``````````````````````````````````````````````````````````

Рассмотрим методы, используемые с **System.out**:


#. **print()** - печать строки без перевода курсора
#. **println()** - печать строки с переводом курсора
#. **printf()** - печать строки с форматированием



.. code-block:: java

 int value=5;
 System.out.println("Отлично - это "+value);
 System.out.printf("%d - отличная оценка\n",value);




.. code-block:: java

 import java.util.Date;
 
 public class PrintfDemo
 {
    public static void main(String[] args)
    {
       System.out.println(new Date());
    }
 }


Результат: **Thu Mar 23 18:11:50 MSK 2017**
Печать текущего года:



.. code-block:: java

 import java.util.Date;
 
 public class PrintfDemo
 {
    public static void main(String[] args)
    {
       System.out.printf("%tY\n",new Date());
    }
 }



Файловый ввод/вывод
===========================================================


Работа с файлами
``````````````````````````````````````````````````````````

Для работы с файлами применяются различные потоки


* **FileInputStream,FileOutputStream** - байтовые потоки
* **FileReader,FileWriter** - символьные потоки
Создание файлового объекта:




.. code-block:: java

 File f = new File("1.txt");


Файловый объект может использоваться как параметр при создании потоков.

Байтовые потоки
-----------------------------------------------------------


FileInputStream
``````````````````````````````````````````````````````````

Рассмотрим работу с файлами с помощью **FileInputStream**



.. code-block:: java

 FileInputStream(String name) throws FileNotFoundException
 FileInputStream (File file) throws FileNotFoundException 



В классе **FileInputStream** переопределяется большая часть методов класса **InputStream** (в т.ч. абстрактный метод

**read()** ). Когда создается объект класса **FileInputStream**, он одновременно с этим открывается для чтения. 



.. code-block:: java

 import java.io.*;
  
 public class FilesApp {
    public static void main(String[] args) {
       try
       {
          FileInputStream fin=new FileInputStream("note.txt")
          System.out.println("Размер файла: " + 
                           fin.available() + " байт(а)");    
          int i=-1;
          while((i=fin.read())!=-1){    
             System.out.print((char)i);
          }   
       }
       catch(IOException ex){       
          System.out.println(ex.getMessage());
       } 
    } 
 }




.. code-block:: java

 byte[] buffer = new byte[fin.available()];
 
 // считываем файл в буфер
 fin.read(buffer, 0, fin.available());
  
 System.out.println("Содержимое файла:");
 for(int i=0; i<buffer.length;i++){
    System.out.print((char)buffer[i]);
 }



FileOutputStream
``````````````````````````````````````````````````````````

Класс **FileOutputStream** можно применять для записи  байтов в файл. У класса **FileOutputStream** есть 3 конструктора:



.. code-block:: java

 FileOutputStream (String filePath) throws FileNotFoundException
 FileOutputStream (File fileObj) throws FileNotFoundException
 FileOutputStream (String filePath, boolean append) 
                  throws FileNotFoundException




.. code-block:: java

 try
 {
    FileInputStream source = new FileInputStream("infile.dat");
    FileOutputStream dest = new  FileOutputStream("outfile.dat");
    int c;
    while ((c = source.read()) != -1)
    {
       dest.write(c); 
    }
    source.close(); dest.close();
 } 
 catch (FileNotFoundException ex) 
 {...}


Пример работы с двумя файлами



.. code-block:: java

 import java.io.*;
  
 public class FilesApp {
    public static void main(String[] args) {      
       try       
       {
          FileOutputStream fos=new FileOutputStream("new.txt");
          FileInputStream fin=new FileInputStream("notes.txt");
          byte[] buffer = new byte[fin.available()];
          // считываем буфер
          fin.read(buffer, 0, buffer.length);
          // записываем из буфера в файл
          fos.write(buffer, 0, buffer.length);
       }
       catch(IOException ex){       
          System.out.println(ex.getMessage());
       } 
    } 
 }



Символьные потоки
-----------------------------------------------------------


FileReader
``````````````````````````````````````````````````````````

Для работы с символами и строками используют **символьные потоки**.


Основные методы **FileReader**:


* **int read() throws IOException** - чтение одиночного символа.
* **int read(char [] c, int offset, int len)** - чтение символов в массив.


.. code-block:: java

 ...
 try {
    FileReader reader=new FileReader("1.txt");
    int c;
    while((c=reader.read())!=-1) {
       System.out.print((char)c);
    }
    catch(IOException ex) {
       System.out.println(ex.getMessage());
    }
 }
 ...


Для чтения строк удобно использовать буферизированный поток **BufferedReader**:



.. code-block:: java

 File file = new File("...");
 FileReader reader = new FileReader(file);
 BufferedReader breader = new BufferedReader(reader);
 String line;
 
 while ((line=breader.readLine()) != null) {
    ...
 }
 reader.close();



FileWriter
``````````````````````````````````````````````````````````



.. code-block:: java

 import java.io.*;
 
 class Random2FileWriter
 {
    public static void main(String[] args) 
       throws Exception {
       Writer file = new FileWriter("random.txt");
       int n=(int)(Math.random()*10);
       String outstr="Number:"+n;
       file.write(outstr);
       file.close();
    }
 }


Копирование строк:



.. code-block:: java

 BufferedReader in = null;
 PrintWriter out = null;
 String line;
 try {
   in = new BufferedReader(new FileReader(args[0]));
   out = new PrintWriter(new FileWriter(args[1]));
   while ((line = in.readLine()) != null) {
       out.println(l);
   }} finally {
    if (in!= null) { in.close(); }
    if (out!= null) { out.close(); }
 }




.. code-block:: java

 Reader reader;
 Writer writer;
 try {
   reader = new FileReader(args[0]);
   writer = new FileWriter(args[1]);
   int c = 0;
   while ((c = reader.read()) >= 0) {
     writer.write(Character.toUpperCase((char) c));
   }
   reader.close();
   writer.close();
  }
  catch(FileNotFoundException ex) {}
  catch(IOException ex) { }



Специальные типы файлов
===========================================================


Файлы свойств
-----------------------------------------------------------


Properties
``````````````````````````````````````````````````````````

Можно использовать файлы для хранения наборов свойств:



.. code-block:: java

 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.Enumeration;
 import java.util.Properties;
 
 public class ReadPropertiesFile {
    public static void main(String[] args) {
    try {
       File file = new File("test.properties");
       FileInputStream fileInput = new FileInputStream(file);
       Properties properties = new Properties();
       properties.load(fileInput);
       fileInput.close();




.. code-block:: java

    Enumeration enuKeys = properties.keys();
    while (enuKeys.hasMoreElements()) {
       String key = (String) enuKeys.nextElement();
       String value = properties.getProperty(key);
       System.out.println(key + ": " + value);
    }
   } catch (FileNotFoundException e) {
     e.printStackTrace();
   } catch (IOException e) {
     e.printStackTrace();
   }
  }
 }


Запись файла со свойствами:



.. code-block:: java

 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.Properties;
 
 public class WritePropertiesFile {
    public static void main(String[] args) {
       try {
          Properties properties = new Properties();
          properties.setProperty("favoriteAnimal", "marmot");
          properties.setProperty("favoriteContinent", "Antarctica");
          properties.setProperty("favoritePerson", "Nicole");




.. code-block:: java

    File file = new File("test.properties");
    FileOutputStream fileOut = new FileOutputStream(file);
    properties.store(fileOut, "Favorite Things");
    fileOut.close();
   } catch (FileNotFoundException e) {
     e.printStackTrace();
   } catch (IOException e) {
     e.printStackTrace();
   }
  }
 }



XML-файлы
-----------------------------------------------------------


XML
``````````````````````````````````````````````````````````

В более сложных случаях предпочтительно использовать **XML**-файлы.



.. code-block:: java

 import java.io.*;
 import java.util.Enumeration;
 import java.util.Properties;
 
 public class ReadPropertiesXmlFile {
  public static void main(String[] args) {
   try {
    File file = new File("test.xml");
    FileInputStream fileInput = new FileInputStream(file);
    Properties properties = new Properties();
    properties.loadFromXML(fileInput);
    fileInput.close();
    ...




.. code-block:: java

 ...
   Enumeration enuKeys = properties.keys();
   while (enuKeys.hasMoreElements()) {
     String key = (String) enuKeys.nextElement();
     String value = properties.getProperty(key);
     System.out.println(key + ": " + value);
   }
   } catch (FileNotFoundException e) {
       e.printStackTrace();
   } catch (IOException e) {
       e.printStackTrace();
   }}}


Запись XML- файла:



.. code-block:: java

 import java.io.*
 import java.util.Properties;
 
 public class WritePropertiesXmlFile {
  public static void main(String[] args) {
   try {
    Properties properties = new Properties();
    properties.setProperty("favoriteAnimal", "marmot");
    properties.setProperty("favoriteContinent", "Antarctica");
    properties.setProperty("favoritePerson", "Nicole");
 ...




.. code-block:: java

 ...
   File file = new File("test.xml");
   FileOutputStream fileOut = new FileOutputStream(file);
   properties.storeToXML(fileOut, "Favorite Things");
   fileOut.close();
   } catch (FileNotFoundException e) {
     e.printStackTrace();
   } catch (IOException e) {
     e.printStackTrace();
   }
 }}



JSON
-----------------------------------------------------------

**JSON (JavaScript Object Notation)** - специальный текстовый формат для обмена данными (чаще всего между клиентом и сервером).

Рассмотрим пример:



.. code-block:: none

     "students": [
         {
             "id": 100,
             "fio": "Иванов А.А."
         },
         {
             "id": 101,
             "fio": "Петров В.В."
         }
     ]
 }

Для работы с форматом **JSON** существует несколько библиотек. Одна из наиболее распространенных: **json-simple**.




.. code-block:: java

 import java.io.*;
 import org.json.simple.*;
 import org.json.simple.parser.JSONParser;
 import org.json.simple.parser.ParseException;
 
 public class JSONRead {
    public static void main(String[] args) {
      try {
        File f=new File("students.json");
        JSONParser parser=new JSONParser();
        FileReader fr = new FileReader(f);




.. code-block:: java

    Object obj=parser.parse(fr);
    JSONObject js=(JSONObject)obj;
    JSONArray items=(JSONArray)js.get("students");
    for(Object i : items) {
       System.out.println(((JSONObject)i).get("id"));
    }
   } catch (FileNotFoundException ex) {
     System.out.println(ex.getMessage());
   } catch (ParseException ex) {
     System.out.println(ex.getMessage());
   } catch(IOException ex) {
     System.out.println(ex.getMessage());
   }
  }
 }



Вопросы для самоконтроля
=============================================