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

Введение

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

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

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

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

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

Stream

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

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

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

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

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

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

//Читает 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

// Записывает 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. У этого класса два конструктора, каждый из которых

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

ByteArrayInputStream(byte array[ ])
ByteArrayInputStream(byte array[ ],
                     int start, int numBytes)
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

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

ByteArrayOutputStream()
ByteArrayOutputStream(int size)
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();

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

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

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

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

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

  1. Классический
  2. Современный
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);
   }

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

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();
         }
      }
   }
}

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

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);
    }
}
   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:

  1. print() - печать строки без перевода курсора
  2. println() - печать строки с переводом курсора
  3. printf() - печать строки с форматированием
int value=5;
System.out.println("Отлично - это "+value);
System.out.printf("%d - отличная оценка\n",value);
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 Печать текущего года:

import java.util.Date;

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

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

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

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

  • FileInputStream,FileOutputStream - байтовые потоки
  • FileReader,FileWriter - символьные потоки

Создание файлового объекта:

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

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

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

FileInputStream

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

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

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

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

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());
      }
   }
}
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 конструктора:

FileOutputStream (String filePath) throws FileNotFoundException
FileOutputStream (File fileObj) throws FileNotFoundException
FileOutputStream (String filePath, boolean append)
                 throws FileNotFoundException
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)
{...}

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

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) - чтение символов в массив.
...
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:

File file = new File("...");
FileReader reader = new FileReader(file);
BufferedReader breader = new BufferedReader(reader);
String line;

while ((line=breader.readLine()) != null) {
   ...
}
reader.close();

FileWriter

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();
   }
}

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

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(); }
}
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

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

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();
   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();
  }
 }
}

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

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");
   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-файлы.

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();
   ...
...
  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- файла:

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");
...
...
  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) - специальный текстовый формат для обмена данными (чаще всего между клиентом и сервером).

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

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

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

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);
   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());
  }
 }
}

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