Потоки Java, файлы и ввод-вывод
Потоки, файлы и ввод-вывод (ввод/вывод) в Java — это инфраструктура для обработки чтения и записи данных. Они позволяют программам взаимодействовать с внешними данными (такими как файлы, сети, системный ввод и т. д.).
Пакет java.io — это основной пакет в стандартной библиотеке Java, предоставляющий классы для системного ввода и вывода. Он содержит инструменты для работы с потоками данных (байтовыми и символьными потоками), чтения и записи файлов, сериализации и форматирования данных.
java.io — это основополагающий пакет для работы с файловыми операциями, операциями с потоками и низкоуровневыми операциями ввода-вывода.
Потоки в пакете java.io поддерживают множество форматов, таких как примитивные типы, объекты, локализованные наборы символов и т. д.
Поток можно понимать как последовательность данных. Входной поток представляет чтение данных из источника, а выходной поток — запись данных в место назначения.
Чтение консольного ввода
Ввод с консоли в Java обрабатывается с помощью System.in.
Чтобы получить символьный поток, связанный с консолью, можно обернуть System.in в объект BufferedReader, чтобы создать символьный поток.
Ниже приведён базовый синтаксис для создания BufferedReader:
После создания объекта BufferedReader мы можем использовать метод read() для чтения символа с консоли или метод readLine() для чтения строки.
Чтение нескольких символов из консольного ввода
Чтобы прочитать символ из объекта BufferedReader, используйте метод read(). Его синтаксис выглядит следующим образом:
Каждый раз, когда вызывается метод read(), он читает символ из входного потока и возвращает символ в виде целочисленного значения. Он возвращает -1, когда поток заканчивается. Этот метод выбрасывает IOException.
Следующая программа демонстрирует использование метода read() для непрерывного чтения символов с консоли, пока пользователь не введётq。
Код файла BRRead.java:
Результат компиляции и выполнения приведенного выше примера выглядит следующим образом:
输入字符, 按下 'q' 键退出。 example r u n o o b q q
Чтение строк из консольного ввода
Чтобы прочитать строку из стандартного ввода, нужно использовать метод readLine() класса BufferedReader.
Его общий формат:
Следующая программа читает и отображает строки символов, пока вы не введёте слово "end".
Код файла BRReadLines.java:
Результат компиляции и выполнения приведенного выше примера выглядит следующим образом:
Enter lines of text. Enter 'end' to quit. This is line one This is line one This is line two This is line two end end
В версиях после JDK 5 мы также можем использовать классJava Scannerдля получения ввода с консоли.
Вывод на консоль
Как было сказано ранее, вывод на консоль осуществляется с помощью print() и println(). Все эти методы определены в классе PrintStream, а System.out — это ссылка на объект этого класса.
PrintStream наследует класс OutputStream и реализует метод write(). Таким образом, write() также можно использовать для записи в консоль.
Простейшая форма write(), определённая в PrintStream, выглядит так:
Этот метод записывает младшие восемь битов byteval в поток.
Пример
В следующем примере используется write() для вывода на экран символа "A", за которым следует символ новой строки:
Код файла WriteDemo.java:
Запуск приведённого выше примера выводит символ "A" в окне вывода.
A
Примечание:Метод write() используется нечасто, поскольку методы print() и println() удобнее в использовании.
Чтение и запись файлов
Как упоминалось ранее, поток определяется как последовательность данных. Входные потоки используются для чтения данных из источника, а выходные потоки — для записи данных в место назначения.
Следующая диаграмма — это диаграмма иерархии классов, описывающая входные и выходные потоки.
Байтовые потоки (обработка двоичных данных)
Байтовые потоки используются для обработки двоичных данных, таких как файлы, изображения, видео и т. д.
| Имя класса | Type | Описание |
|---|---|---|
InputStream | Абстрактный класс (входной поток) | Суперкласс всех байтовых входных потоков, обрабатывающий операции байтового ввода. |
OutputStream | Абстрактный класс (выходной поток) | Суперкласс всех байтовых выходных потоков, обрабатывающий операции байтового вывода. |
FileInputStream | Входной поток | Читает байтовые данные из файла. |
FileOutputStream | Выходной поток | Записывает байтовые данные в файл. |
BufferedInputStream | Входной поток | Обеспечивает буферизацию для байтовых входных потоков для повышения эффективности чтения. |
BufferedOutputStream | Выходной поток | Обеспечивает буферизацию для байтовых выходных потоков для повышения эффективности записи. |
ByteArrayInputStream | Входной поток | Использует массив байтов в памяти в качестве источника ввода. |
ByteArrayOutputStream | Выходной поток | Записывает данные в массив байтов в памяти. |
DataInputStream | Входной поток | Позволяет читать примитивные типы данных Java из входного потока (например,int、float、boolean)。 |
DataOutputStream | Выходной поток | Позволяет записывать примитивные типы данных Java в выходной поток. |
ObjectInputStream | Входной поток | Читает сериализованные объекты из входного потока. |
ObjectOutputStream | Выходной поток | Сериализует объекты и записывает их в выходной поток. |
PipedInputStream | Входной поток | Используется для чтения байтовых данных в канале, обычно сPipedOutputStreamИспользуются вместе. |
PipedOutputStream | Выходной поток | Используется для записи байтовых данных в канале, обычно сPipedInputStreamИспользуются вместе. |
FilterInputStream | Входной поток | Класс-обёртка для входных потоков байтов, используемый для фильтрации других входных потоков. |
FilterOutputStream | Выходной поток | Класс-обёртка для выходных потоков байтов, используемый для фильтрации других выходных потоков. |
SequenceInputStream | Входной поток | Объединяет несколько входных потоков в один входной поток для обработки. |
Символьные потоки (обработка текстовых данных)
Символьные потоки используются для обработки текстовых данных, например для чтения и записи строк или файлов.
| Имя класса | Type | Описание |
|---|---|---|
Reader | Абстрактный класс (входной поток) | Суперкласс всех входных символьных потоков, обрабатывающий операции ввода символов. |
Writer | Абстрактный класс (выходной поток) | Суперкласс всех символьных потоков вывода, обрабатывающий операции вывода символов. |
FileReader | Входной поток | Читает символьные данные из файла. |
FileWriter | Выходной поток | Записывает символьные данные в файл. |
BufferedReader | Входной поток | Обеспечивает буферизацию для символьных потоков ввода, поддерживает построчное чтение и повышает эффективность чтения. |
BufferedWriter | Выходной поток | Обеспечивает буферизацию для символьных потоков вывода, поддерживает построчную запись и повышает эффективность записи. |
CharArrayReader | Входной поток | Использует массив символов в качестве источника ввода. |
CharArrayWriter | Выходной поток | Записывает данные в массив символов. |
StringReader | Входной поток | Использует строку в качестве источника ввода. |
StringWriter | Выходной поток | Записывает данные в строковый буфер. |
PrintWriter | Выходной поток | Удобный символьный поток вывода, поддерживает автосброс и форматированный вывод. |
PipedReader | Входной поток | Используется для чтения символьных данных в канале, обычно сPipedWriterиспользуется вместе. |
PipedWriter | Выходной поток | Используется для записи символьных данных в канал, обычно сPipedReaderиспользуется вместе. |
LineNumberReader | Входной поток | Буферизованный входной поток символов с номерами строк, позволяющий отслеживать номер считываемой строки. |
PushbackReader | Входной поток | Позволяет возвращать символы обратно в поток после чтения, чтобы их можно было прочитать снова. |
Вспомогательные классы (другие важные классы)
Вспомогательные классы обеспечивают поддержку файлов, каталогов и произвольного доступа к файлам.
| Имя класса | Type | Описание |
|---|---|---|
File | Операции с файлами и каталогами | Используется для представления файла или каталога и предоставляет файловые операции, такие как создание, удаление, переименование и т. д. |
RandomAccessFile | Файл произвольного доступа | Поддерживает произвольный доступ к файлам, позволяя читать данные из любой позиции файла и записывать их в любую позицию файла. |
Console | Консольный ввод/вывод | Обеспечивает поддержку ввода и вывода для системной консоли. |
Два важных потока, которые будут рассмотрены далее, — этоFileInputStreamиFileOutputStream。
FileInputStream
Этот поток используется для чтения данных из файла. Его объект можно создать с помощью ключевого слова new.
Существует несколько конструкторов, которые можно использовать для создания объектов.
Вы можете использовать имя файла строкового типа для создания объекта входного потока для чтения файла:
Вы также можете использовать файловый объект для создания объекта входного потока для чтения файла. Сначала нам нужно использовать метод File() для создания файлового объекта:
После создания объекта InputStream вы можете использовать следующие методы для чтения потока или выполнения других операций с потоком.
| Метод | Описание | Пример кода |
|---|---|---|
int read() | Читает один байт данных, возвращаемое значение — целое число от 0 до 255. Возвращает -1, если достигнут конец потока. | int data = inputStream.read(); |
int read(byte[] b) | Читает байты из входного потока и сохраняет их в байтовом массивеbи возвращает фактическое количество прочитанных байтов. Возвращает -1, если достигнут конец потока. | byte[] buffer = new byte[1024]; int bytesRead = inputStream.read(buffer); |
int read(byte[] b, int off, int len) | Читает доlenбайтов из входного потока и сохраняет их в массиве байтовbизoffначиная с позиции offset, возвращая фактическое количество прочитанных байтов. Возвращает -1, если достигнут конец потока. | byte[] buffer = new byte[1024]; int bytesRead = inputStream.read(buffer, 0, buffer.length); |
long skip(long n) | Пропускает и отбрасываетnбайтов во входном потоке, возвращая фактическое количество пропущенных байтов. | long skippedBytes = inputStream.skip(100); |
int available() | Возвращает количество байтов, которые можно прочитать (без блокировки). | int availableBytes = inputStream.available(); |
void close() | Закрывает входной поток и освобождает все ресурсы, связанные с этим потоком. | inputStream.close(); |
void mark(int readlimit) | Устанавливает метку в текущей позиции потока,readlimitявляется верхним пределом количества байтов, которые можно прочитать. | inputStream.mark(1024); |
void reset() | Перемещает поток в позицию последней метки. Если метки нет или метка недействительна, выбрасываетIOException。 | inputStream.reset(); |
boolean markSupported() | Проверяет, поддерживает ли текущий входной потокmark()иreset()операцию. | boolean isMarkSupported = inputStream.markSupported(); |
Помимо InputStream, существуют и другие входные потоки. Для получения дополнительной информации перейдите по ссылке ниже:
FileOutputStream
Этот класс используется для создания файла и записи данных в файл.
Если целевой файл не существует до того, как поток откроет файл для вывода, поток создаст файл.
Существуют два конструктора, которые можно использовать для создания объекта FileOutputStream.
Используйте имя файла строкового типа для создания объекта выходного потока:
Вы также можете использовать объект файла для создания выходного потока для записи в файл. Сначала нам нужно использовать метод File() для создания объекта файла:
После создания объекта OutputStream вы можете использовать следующие методы для записи в поток или выполнения других операций с потоком.
| Метод | Описание | Пример кода |
|---|---|---|
void write(int b) | Записывает указанный байт в выходной поток; младшие 8 бит отbбудут записаны в поток. | outputStream.write(255); |
void write(byte[] b) | Записывает все байты в массиве байтовbв выходной поток. | byte[] data = "Hello".getBytes(); outputStream.write(data); |
void write(byte[] b, int off, int len) | Записывает байты из массива байтовbначиная со смещенияoffначиная сlenбайты в выходной поток. | byte[] data = "Hello".getBytes(); outputStream.write(data, 0, data.length); |
void flush() | Сбрасывает выходной поток и принудительно записывает все буферизованные данные, гарантируя, что данные немедленно записываются в целевой выходной поток. | outputStream.flush(); |
void close() | Закрывает выходной поток и освобождает все ресурсы, связанные с этим потоком. После закрытия больше нельзя выполнять запись. | outputStream.close(); |
Помимо OutputStream, существуют и другие выходные потоки. Для получения дополнительных сведений перейдите по ссылке ниже:
Пример
Ниже приведён пример, демонстрирующий использование InputStream и OutputStream:
код файла fileStreamTest.java:
Вышеприведённая программа сначала создаёт файл test.txt, записывает заданные числа в файл в бинарной форме и одновременно выводит их в консоль.
Поскольку приведённый выше код использует бинарную запись, могут появляться искажённые символы. Вы можете использовать следующий пример кода, чтобы решить проблему с искажёнными символами:
Код файла fileStreamTest2.java:
Файлы и ввод-вывод
Также есть несколько классов, связанных с файлами и вводом-выводом, которые нам нужно знать:
Каталоги в Java
Создание каталогов:
В классе File есть два метода, которые можно использовать для создания папок:
- mkdir( )Метод создаёт папку. Он возвращает true при успехе и false при неудаче. Неудача означает, что путь, указанный объектом File, уже существует, или что папку нельзя создать, потому что полный путь ещё не существует.
- mkdirs()Метод создаёт папку и все её родительские папки.
Следующий пример создает папку "/tmp/user/java/bin":
Код файла CreateDir.java:
Скомпилируйте и выполните приведенный выше код, чтобы создать каталог "/tmp/user/java/bin".
Примечание:Java автоматически различает разделители пути к файлам в зависимости от соглашений в UNIX и Windows. Если вы используете разделитель (/) в версии Java для Windows, путь все равно может быть разрешен правильно.
Чтение каталогов
Каталог на самом деле является объектом File, который содержит другие файлы и папки.
Если вы создаете объект File и он является каталогом, то вызов метода isDirectory() вернет true.
Вы можете извлечь список файлов и папок, которые он содержит, вызвав метод list() для этого объекта.
В приведенном ниже примере показано, как использовать метод list() для проверки содержимого папки:
Код файла DirList.java:
Результат компиляции и запуска приведенного выше примера выглядит следующим образом:
目录 /tmp bin 是一个目录 lib 是一个目录 demo 是一个目录 test.txt 是一个文件 README 是一个文件 index.html 是一个文件 include 是一个目录
Удаление каталогов или файлов
Чтобы удалить файл, можно использовать методjava.io.File.delete().
Следующий код удалит каталог/tmp/java/. Обратите внимание, что при удалении каталога необходимо убедиться, что в этом каталоге нет других файлов, чтобы удалить его корректно; в противном случае удаление не удастся.
Структура тестового каталога:
/tmp/java/ |-- 1.log |-- test
