В Java потоки I/O представлены классами InputStream и OutputStream. InputStream используется для чтения данных, а OutputStream - для записи данных.
Java предоставляет различные реализации потоков I/O, такие как классы FileInputStream и FileOutputStream для работы с файлами, классы ByteArrayInputStream и ByteArrayOutputStream для работы с данными в памяти, классы PipedInputStream и PipedOutputStream для обмена данными между потоками и другие.
В Java также доступны декораторы потоков, которые позволяют добавлять дополнительную функциональность к основным потокам I/O. Например, классы BufferedInputStream и BufferedOutputStream предоставляют буферизацию данных для повышения производительности.
Пример использования потоков I/O в Java:
Чтение данных из файла:
InputStream inputStream = new FileInputStream("file.txt");
int data = inputStream.read();
while(data != -1) {
System.out.print((char) data);
data = inputStream.read();
}
inputStream.close();
Запись данных в файл:
OutputStream outputStream = new FileOutputStream("file.txt");
String text = "Hello, World!";
byte[] data = text.getBytes();
outputStream.write(data);
outputStream.close();
По завершению операций чтения и записи данных, потоки I/O должны быть закрыты с помощью метода close() для освобождения ресурсов и предотвращения утечек памяти.
Разновидности потоков
Потоки байтов предназначены для работы с байтами данных и представлены классами InputStream и OutputStream. Эти потоки читают и записывают данные в виде последовательности байтов.
Потоки символов предназначены для работы с символами и представлены классами Reader и Writer. Они позволяют читать и записывать данные в виде последовательности символов.
Потоки буферизованные обеспечивают более эффективное чтение и запись данных, так как используют внутренний буфер. Они представлены классами BufferedInputStream и BufferedOutputStream для потоков байтов и классами BufferedReader и BufferedWriter для потоков символов.
Потоки данных предназначены для работы с различными типами данных и представлены классами DataInputStream и DataOutputStream. Они позволяют читать и записывать примитивные типы данных, такие как числа, строки и т.д.
Потоки объектов предназначены для сериализации объектов и представлены классами ObjectInputStream и ObjectOutputStream. Они позволяют сохранять объекты в файлы или передавать их по сети.
Блокирующие и неблокирующие потоки
Блокирующие потоки, как следует из их названия, блокируют исполнение программы до тех пор, пока операция чтения или записи не будет завершена. Если в потоке данных нет, то программа остановится и будет ждать, пока не появятся новые данные. Это значит, что блокирующие потоки могут занимать больше системных ресурсов, так как они активно ждут появления данных.
Неблокирующие потоки, напротив, позволяют программе продолжать свою работу независимо от наличия данных в потоке. Если в потоке нет данных, то программа просто будет продолжать выполняться, без блокировки. При наличии данных, программа будет обрабатывать их немедленно.
Выбор между блокирующими и неблокирующими потоками зависит от требований к производительности и от потребности программы в мгновенной реакции на изменения данных. Если важна скорость обработки данных и программа должна немедленно реагировать на изменения, то лучше использовать неблокирующие потоки. Если же потоки не часто содержат данные и скорость обработки не является критичной, то блокирующие потоки могут быть предпочтительнее.
Чтение из потока ввода: для этого используется метод read() объекта класса InputStream. Этот метод возвращает очередной байт из потока в виде целого числа. Если на данный момент нет доступных данных, метод вернет значение -1.
Закрытие потока: для этого используется метод close() объекта класса InputStream или OutputStream. Закрытие потока освобождает ресурсы, которые он занимает, и делает его недоступным для дальнейшего использования.
Перемещение указателя в потоке: для этого используются методы mark(), reset() и skip() объекта класса InputStream. Метод mark() устанавливает метку в текущей позиции указателя, метод reset() перемещает указатель в позицию метки, а метод skip() перемещает указатель на заданное количество байтов вперед.
Буферизация данных: для обеспечения более эффективной работы с потоками данных, в Java предусмотрена возможность использования буферов. Буферизация позволяет считывать или записывать данные блоками, что существенно ускоряет процесс работы.
Чтение текстового файла
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.out.println("Ошибка чтения файла: " + e.getMessage());
}
Запись в текстовый файл
String text = "Пример текста для записи в файл.";
try (BufferedWriter writer = new BufferedWriter(new FileWriter("file.txt"))) {
writer.write(text);
} catch (IOException e) {
System.out.println("Ошибка записи файла: " + e.getMessage());
}
Чтение данных из сетевого соединения
try (Socket socket = new Socket("example.com", 80);
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.out.println("Ошибка чтения данных из сети: " + e.getMessage());
}
Запись данных в сетевое соединение
try (Socket socket = new Socket("example.com", 80);
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream()))) {
writer.write("GET / HTTP/1.1
");
writer.write("Host: example.com
");
writer.write("
");
writer.flush();
} catch (IOException e) {
System.out.println("Ошибка записи данных в сеть: " + e.getMessage());
}
Обработка ошибок и исключений
Для обработки исключений в Java используется конструкция try-catch. Внутри блока try выполняется код, который потенциально может порождать исключение. Если исключение происходит внутри блока try, управление передается в соответствующий блок catch, который обрабатывает исключение.
Код | Описание |
---|---|
|
В блоке catch можно выполнить определенные действия при возникновении исключения, например, записать сообщение об ошибке в лог-файл, повторить операцию или вывести сообщение об ошибке пользователю.
Обработка ошибок и исключений в Java позволяет создавать более надежные и стабильные программы, которые могут адекватно реагировать на возникающие проблемы.