- •Краткая историческая справка.
- •Преимущества языка Java.
- •Недостатки java:
- •Лекция 2. Этапы разработки java-приложений. Этапы разработки java-приложений.
- •Установка jdk.
- •Инсталляция исходных кодов библиотек
- •Инсталляция пакета документации.
- •Тестирование правильности установки и создание простейшей программы
- •Визуальные среды программирования.
- •Лекция 3. Переменные и типы данных. Переменные и типы данных.
- •Подробности о примитивных типах.
- •Лекция 4. Операторы и функции. Операторы и функции.
- •Операторы ветвлений и циклов.
- •Оператор цикла while.
- •Оператор цикла for.
- •Лекция 5. Объектно ориентированное программирование Объектно ориентированное программирование.
- •Определение объекта.
- •Инкапсуляция.
- •Наследование.
- •Полиморфизм (перегрузка).
- •Пример ооп – программы.
- •Отличие перегрузки функций от переопределения.
- •Отличие классов от интерфейсов.
- •Лекция 6. Массивы и строки. Массивы и строки.
- •Многомерные массивы.
- •Приведение типов и динамические массивы.
- •Строки в java.
- •Лекция 7. Организация ввода-вывода данных Организация ввода-вывода данных.
- •Функции стандартной библиотеки ввода/вывода.
- •Новая библиотека ввода/вывода.
- •Классы потокового ввода/вывода из пакета java.Io.
- •Лекция 8. Обработка исключений. Обработка исключений.
- •Классификация исключений.
- •Перехват исключений блоками try/catch.
- •Самостоятельное выбрасывание исключений.
- •Разработка собственных классов исключений.
- •Лекция 9. Потоки. Потоки.
- •1. Cпециальный класс Thread.
- •2. Реализация интерфейса Runnable.
- •Выбор между использованием класса Thread и интерфейса Runnable.
- •Синхронизация потоков с помощью оператора synchronized.
- •Синхронизация потоков с помощью семафоров.
- •Лекция 10. Подключаемые библиотеки java. Подключаемые библиотеки java.
- •Библиотека awt
- •Внутреннее устройство системы обработки событий awt.
- •Библиотека Swing.
Классы потокового ввода/вывода из пакета java.Io.
import java.io.InputStream;
import java.io.OutputStream;
Представляют потоки байт для чтения или записи. Оба класса абстрактные, то есть, создать их экземпляры нельзя. Более того, на уровне этих классов не определены также и источники данных. Источник или пункт назначения потока будет зависеть от того, с чем мы работаем в данный момент – файл, архив, файловая система удаленного компьютера и т.д. и располагаться в соответствующем подклассе.
Подключаются они следующим образом. Допустим, у нас есть какие-то файлы источника и назначения "input.txt" и "output.txt". Откуда мы забираем и куда сливаем поток байт.
InputStream inputStream = new FileInputStream(new File("input.txt"));
OutputStream outputStream(new File("output.txt"));
Далее можно заниматься пересылкой байт по созданному потоку. Например, так:
int totalBytesWritten = 0; // общее количество переданных байт
byte [] buf = new byte [1024]; // объявление временного буфера для записи
int blockSize; // размер пересылаемого/читаемого блока байт
while (( blockSize = inputStream.read(buf)) > 0) { // читаем файл в буфер
outputStream.write(buf, 0, blockSize); // записываем байты из буфера
totalBytesWritten += blockSize; // считаем, сколько записали
}
Для пересылки данных нам необходим временный накопитель, то есть буфер. В него считывается информация из файла и из него она уходит к цели назначения.
Информация считывается поблочно с размером блоков меньше, но очевидно кратным размеру буфера. Ну и всегда желательно знать, сколько байт ушло в поток, чтобы сравнить потом, насколько полно и безошибочно передан файл.
Теперь заглянем "под капот" этих потоковых классов и посмотрим в исходниках, как они устроены внутри. Для справки приведу сокращенный листинг. Полный листинг можно посмотреть в документации java по этим классам. Класс InputStream:
package java.io
public abstract class InputStream implements Closeable {
public abstract int read() trows IOExeption;
public int read(byte b []) trows IOExeption {
return read(b, 0, b.length);
}
public int read (byte b [], int off, int len)
throws IOExeption { // …
}
public long skip (long n) trows IOExeption {
// …
}
public void close() throws IOException {}
// …
}
Первый метод read() возвращает следующий байт из входного потока и переходит к следующему байту. То есть, трижды вызвав метод read() мы получим три байта, идущих один за другим в потоке. Возвращаемое значение имеет тип int, а не байт для того, чтобы была возможность обозначить конец потока. Когда байтов больше не остается в виде маркера конца потока возвращается "-1". Для того, чтобы из типа int получить фактически считанный байт, можно сделать приведение типов. Ну или просто указать перед переменной модификатор типа (byte).
При возникновении каких либо ошибок выбрасываются исключения IOExeption.
Читать поток побайтово не всегда эффективно, поэтому есть еще пара методов, которые используют для чтения потока буфер b [] – это read (byte b []) и read (byte b [], int off, int len). Разница между ними только в том, что первый считывает количество байт, заполняя буфер за один раз целиком, а второй считывает байты в буфер, заполняя его начиная с байта int off и до заполнения количеством int len. Обе функции возвращают количество реально считанных байт, которых может быть мало или нет совсем, если поток закончился. В этом случае функции вернут "-1".
Кроме этих функций есть еще функция skip(long n), которая просто пропускает количество байт n, никуда их не сохраняя (возвращает количество реально пропущеных байт) и функция close(), которая закрывает поток и освобождает все дескрипторы файлов.
Листинг второго класса OutputStream:
package java.io
public abstract class OutputStream implements Closeable, Flushable {
public abstract void write (int b) throws IOExeption;
public void write (byte b [] ) throws IOException {
write(b, 0, b.length);
}
public void write(byte b [], int off, int len) throws IOException {
// …
}
public void flush () throws IOException {
// … }
public void close () throws IOException {
// …
}
}
Назначение отдельных методов у этого класса и тип возвращаемого значения совершенно аналогичны, с той лишь разницей, что идет не чтение, а запись в файл.
Отдельно пару слов стоит сказать про метод flush(). Дело в том, что кроме нашего программного буфера чтения – записи файлов, есть еще низкоуровневый системный буфер. Вызов команды flush() вызывает сброс системного буфера и если в нем к моменту вызова этой команды еще оставались какие – то данные, они также сбрасываются в файл.
При закрытии потока путем вызова функции close(), вызов функции flush() происходит автоматически и специально беспокоиться о нем в этом случае не нужно.
Классы потокового ввода/вывода очень хорошо подходят для побайтовой или построчной обработки огромных текстовых файлов в несколько гигабайт, когда считывать их в память целиком за один раз не представляется возможным.
Приведем еще один пример использования классов потокового ввода/вывода для получения Internet – страниц через сокетное соединение.
try (Socket socket = new Socket("ya.ru", 80)) { // открываем сокет
OutputStream outputStream = socket.getOutputStream(); // получаем поток
outputStream.write("GET / HTTP /1/0\r\n\r\n".getBytes()); //запрашиваем страницу
outputStream.flush(); // сброс буферов
InputStream inputStream = socket.getInputStream(); // ждем ответа сервера
int read = inputStream.read(); // читаем html – код из буфера
while (read >= 0) {
System.out.print((char) read); // выводим страницу в консоль
read = inputStream.read();
}
}
И в заключение, еще маленький пример использования этих классов для случая, когда у нас есть в памяти произвольный массив данных и мы его просто хотим выгрузить в какое-либо приложение или файл:
byte [] data = {"1","2","3"};
InputStream inputStream = new ByteArrayInputStream(data);
Потом эти данные можно использовать в качестве входных для какого-нибудь приложения, читающего потоки.
Или наоборот, загрузить данные на вход нашего кода, которому требуется потоковый ввод:
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// ..
byte [] result = outputStream.toByteArray();
Эти способы упрощенной работы с потоками удобно использовать для отладки собственного кода. Например, отлаживаем программу с соединением к интернету через сокет. Кода, отвечающего за подключение к интернету еще нет. Создали массив байт, закинули на вход нашей функции, обработали, отправили ответ, получили в виде массива, распечатали, посмотрели где ошибка
