Saint Petersburg, 2012 Java Lecture #04 Part I - IO
IO Overview Пакет java.io Ключевое понятие – поток – линейная последовательность байт 2 Байтовые потоки InputStream OutputStream Символьные потоки Reader Writer Input Output
InputStream read() возвращает байт или -1 если конец потока skip() пропускает заданное количество байт available() возвращает доступное для чтения число байт close() закрывает поток и освобождает ресурс Некоторые классы поддерживают маркирование mark(), проверить markSupported() Пример: 1. FileInputStream fis = new FileInputStream("myfile.dat"); 2. ObjectInputStream ois = new ObjectInputStream(fis); 3. Date date = (Date) ois.readObject(); 4. ois.close(); 3
OutputStream write() записывает массив байт или единичный байт flush() принуждает записать существующий буфер close() закрывает поток и освобождает ресурс Пример: 1. FileOutputStream fos = new FileOutputStream("myfile.dat"); 2. ObjectOutputStream oos = new ObjectOutputStream(fos); 3. oos.writeObject(new Date()); 4. oos.close(); 4
Decorator pattern Динамически наделяет объекты дополнительными возможностями, является альтернативой расширению функционала с использованием наследования. 5
Streams 6 ByteArray*Stream – работа с байтовыми массивами Object*Stream – чтение/запись объектов Piped*Stream – чтение/запись на два потока File*Stream – работа с файлами Filter*Stream – реализация декоратора
Filter Streams DataInputStream, DataOutputStream Позволяет читать/писать примитивные типы readXxx(); write(xxx); BufferedInputStream, BufferedOutputStream Добавляют буферризацию ввода/вывода PushbackInputStream Позволяет возвращать байты обратно в поток unread(); PrintStream Обеспечивает возможность примитивного форматирования типов для вывода 7
Chaining Streams Example 1. public static void main(String[] args) throws IOException { 2. DataInputStream din = new DataInputStream( 3. new BufferedInputStream( 4. new FileInputStream( 5. new File("numbers.dat")))); 6. int i; 7. boolean b; 8. i = din.readInt(); 9. b = din.readBoolean(); 10. System.out.println("i = " + i + ". b = " + b); 11. din.close(); 12. } 8
What is Wrong? 1. try { 2. OutputStream file = new FileOutputStream("myfile.dat"); 3. OutputStream buffer = new BufferedOutputStream(file); 4. ObjectOutput output = new ObjectOutputStream(buffer); 5. output.writeObject(quarks); 6. } finally { 7. output.close(); 8. } 9. // program goes further 10. … 9
What is Wrong? 1. try { 2. OutputStream file = new FileOutputStream("myfile.dat"); 3. OutputStream buffer = new BufferedOutputStream(file); 4. ObjectOutput output = new ObjectOutputStream(buffer); 5. output.writeObject(quarks); 6. } finally { 7. output.close(); 8. } 9. // program goes further 10. … 10
What is Wrong? 1. ObjectOutput output = null; 2. try { 3. OutputStream file = new FileOutputStream("myfile.dat"); 4. OutputStream buffer = new BufferedOutputStream(file); 5. output = new ObjectOutputStream(buffer); 6. output.writeObject(quarks); 7. } finally { 8. output.close(); 9. } 10. // program goes further 11. … 11
Reader / Writer 12 нужны для работы с символьными потоками значительно повышают удобство использования
Reader / Writer read() возвращает символ или массив символов или -1, если достигнут конец write() записывает символ или массив символов Пример: 1. BufferedReader reader = new BufferedReader(new FileReader("myfile.dat")); 2. String s = reader.readLine(); 3. reader.close(); 13
Reader/Writer BufferedReader/BufferedWriter InputStreamReader/OutputStreamWriter FileReader/FileWriter PipedReader/PipedWriter StringReader/StringWriter PushbackReader/PushbackWriter PrintWriter 14
Converters InputStreamReader Конвертирует байтовые входные потоки в символьные. Декодирует байты в символы используя указанную кодировку. Пример: 1. FileInputStream fis = new FileInputStream("test.txt"); 2. InputStreamReader isr = new InputStreamReader(fis, "UTF8"); OutputStreamWriter Конвертирует символьные потоки в байтовые. Пример: 1. FileOutputStream fos = new FileOutputStream("test.txt"); 2. Writer out = new OutputStreamWriter(fos, "UTF8"); 15
PrintWriter Example 1. PrintWriter writer = new PrintWriter("test.txt"); 2. writer.print("abracadabra"); 3. writer.println( L); 4. writer.write('d'); 5. writer.printf("%1$(d,%2$+d", -10, 3); 6. writer.flush(); 7. writer.close(); Что произошло при создании writera: 1. public PrintWriter(String fileName) throws FileNotFoundException { 2. this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))), 3. false); 4. } 16
Pipes byte[] bb = new byte[20]; 2. PipedInputStream pis = new PipedInputStream(); 3. PipedOutputStream pos = new PipedOutputStream(pis); 4. pos.write(42); 5. pis.read(bb); 6. System.out.println(bb[0]);
Files java.io.File - файл или директория java.io.File не используется для чтения или записи данных Создание файла: 1. createNewFile() 2. С помощью Writera или Streamа Ключевые методы: mkdir() / createNewFile() delete() renameTo() exists() isDirectory() / isFile() list() 18
Sockets 19 Клиентские и серверные сокеты обеспечивают обмен данными между процессами Количество доступных сокетов ограничевается возможностями операционной системы
ServerSocket 20 Синхронный ввод-вывод Модель thread per connection 1. try { 2. ServerSocket ss = new ServerSocket(9090); 3. Socket s = ss.accept(); 4. while (s.getInputStream().read() != -1) { 5. System.out.println(s.getInputStream().read()); 6. } 7. } catch (IOException e) { 8. // do something here 9. }
ClientSocket 21 Синхронный ввод-вывод Модель thread per connection 1. try { 2. Socket s = new Socket("localhost", 9090); 3. s.getOutputStream().write(65535); 4. s.close(); 5. } catch (IOException e) { 6. // do something here 7. }
Serialization Сериализация объектов - процесс сохранения состояния этого объекта в последовательность байт Key points: Объекты сериализуются с помощью ObjectOutputStream Объекты десериализуются с помощью ObjectInputStream Объекты поддерживающие сериализацию должны реализовывать Serializable writeObject(ObjectOutputStream os) readObject(ObjectInputStream is) 22
ObjectStream FileOutputStream fos = new FileOutputStream("myfile.dat"); 2. ObjectOutputStream oos = new ObjectOutputStream(fos); 3. oos.writeInt(123456); 4. oos.writeObject("Today"); 5. oos.writeObject(new Date()); 6. oos.close(); 7. FileInputStream fis = new FileInputStream("myfile.dat"); 8. ObjectInputStream ois = new ObjectInputStream(fis); 9. int i = ois.readInt(); 10. String today = (String) ois.readObject(); 11. Date date = (Date) ois.readObject(); 12. ois.close();
What will happen? public class Main { 2. public static void main(String[] args) { 3. try { 4. FileOutputStream fos = new FileOutputStream("myfile.dat"); 5. ObjectOutputStream oos = new ObjectOutputStream(fos); 6. oos.writeObject(new Dummy()); 7. oos.close(); 8. } catch (Exception e) { 9. e.printStackTrace(); 10. } 11. } 12. } 13. class Dummy { 14. private String s = "123"; 15. public String getS() { 16. return s; 17. } 18. }
What will happen? public class Main { 2. public static void main(String[] args) { 3. try { 4. FileOutputStream fos = new FileOutputStream("myfile.dat"); 5. ObjectOutputStream oos = new ObjectOutputStream(fos); 6. oos.writeObject(new Dummy()); 7. oos.close(); 8. } catch (Exception e) { 9. e.printStackTrace(); 10. } 11. } 12. } 13. class Dummy { 14. private String s = "123"; 15. public String getS() { 16. return s; 17. } 18. } java.io.NotSerializableException: Dummy
Best Practices of java.io Потоки можно и нужно оборачивать друг в друга, например: 1. ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("myfile.dat"))); Потоки всегда надо закрывать Но не все - закрытия требует только последний созданный поток, так в примере выше, надо закрыть только oos. Закрытие должно происходить в блоке finally Лучше использовать буферизованные потоки – мгновенная обработка запросов на чтение/запись может снизить производительность 26