Вроде сначала, а потом читай, Java продвинута более чем наполовину.
Брат Нэн находится за границей stackoverflow смотретьприезжать13Такой вопрос многолетней давности:Как использовать Java построчночитать большой текстовый файл。У вас есть идеи??Давайте обсудим вместе в комментариях。
I need to read a large text file of around 5-6 GB line by line using Java.
How can I do this quickly?
Ответ, получивший больше всего голосов, дал парень по имени Питер Лоури.
Меня зовут брат Нэн, я думаю, вам будет полезно пройти собеседование и получить предложение.
Постучите по доске: в этой статье кратко описывается Java. Поток ввода-вывода, Java Общие вопросы на собеседовании NIO!=
Интервьюер: Можете ли вы рассказать мне, как вы понимаете Java IO?
Java I/O имеет два участвующих объекта,одинКонец источника ввода/вывода,одинхочуиI/O
Различные типы исходной связипринимающая сторона,Например, программа управляет выводом консоли IDEA, записывает файл А в файл Б и т.д.,Наша программа хочет гарантировать, чтоIOТечь плавночитатьи пиши спокойно。JDKПолучите это правильноJava IOВся поддержка заложенаpackage java.io
Бао Ся,Брат Нэн посчитал,Один имеет 86 классов и интерфейсов.
Давайте посмотримpackage java.io
Наиболее часто используемые пакетыReaderиWriterинтерфейс,он Все их авторыMark Reinhold。Кто этот парень??ондаOracle Главный архитектор группы платформ Java и ведущий инженер по средствам чтения и записи символьного потока. На таком фоне кажется, что Java Программирование ввода-вывода — дело непростое, и мы можем извлечь из него много полезного.
/**
* @author Mark Reinhold
* @since JDK1.1
*/
public abstract class Reader implements Readable, Closeable { }
public abstract class Writer implements Appendable, Closeable, Flushable { }
Интервьюер: Как прочитать поток байтов?
Давайте сначала поговорим о входном потоке, а затем о выходном потоке. Входной поток делится на поток байтов и поток символов. Как следует из названия, поток байтов считывается в байтах, а единица данных операции — 8-битные байты, а поток символов считывается в символах; единицей данных операции являются 16-битные символы.
читатьбайтабстрактный базовый классдаInputStream,Этот базовый класс предоставляет нам 3 метода для потоковой передачи потоков байтов.
(1) Читается следующий байт данных из входного потока.,Байт значения начинается с0приезжать255в пределах досягаемостиint
возвращаться。
public abstract int read() throws IOException
(2)из входного потокачитатьопределенная суммабайти хранить ихприезжатьбуфермножествоb
середина。
public int read(byte b[]) throws IOException
(3)из входного потокачитатьбольшинствоlen
индивидуальныйбайтданныеприезжатьбайтмножествосередина。
public int read(byte b[], int off, int len) throws IOException
Обратите внимание, что все возвращаемые параметры вышеуказанных методов имеют типы int.,Когда нормально читать,intвозвращатьсяиздачитать Количество байтов;И когдаintВозврат -1,Это указывает на то, что входной поток достиг конца.
Интервьюер: Это не примеры. Я хочу, чтобы это действительно можно было прочитать?
Вышеупомянутый абстрактный интерфейс,Сам по себе он не имеет реальной функции。действительно способныйчитатьдокументиздаInputStream
Реализация подкласса абстрактного базового класса,НапримерФайловый потокFileInputStream,С он,Читаем аудио, видео, gif и т. д. не являются проблемой.
// поток файловчитать файл
FileInputStream stream = new FileInputStream(SOURCE_PATH);
нас Достаточно хорошосуществовать Добавьте слой снаружипоток байтов кэшаулучшитьчитатьэффективность,Поместите объект BufferedInputStream во внешний слой.,О том, почему эффективность чтения можно повысить, я расскажу ниже.
BufferedInputStream stream = new BufferedInputStream(new FileInputStream(SOURCE_PATH));
В приведенном выше потоке байтов мы используем n байтов для чтения.,Если вы хотите использоватьreadLine()
читать Определенная строка неприменима в этом сценарии.。насмогу поставитьпоток байтов кэша Заменить накэшировать поток символовпредпринять,использоватьInputStreamReader
Процесс конверсииПучокбайтвходной потокизменять Заменить нахарактервходной поток。
Как показано в следующем коде.
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(SOURCE_PATH)));
Интервьюер: Почему добавление уровня потока кэша может повысить эффективность чтения?
Почему добавление уровня потока кэша может повысить эффективность чтения? Потому что он используется напрямую FileInputStream
Чтобы прочитать файл, каждый раз вызывайте read()
ВседаотДиск читает один байт,И каждый разчитать Вседасистемный вызов。Системные вызовы — это вызовы на уровне операционной системы.,Включает переключение контекста между пространством пользователя и пространством ядра.,Эти переключатели дорогие.
А если вы используете поток кэша, из файла в кэш одновременно считывается несколько байтов, что уменьшает системные вызовы и операции чтения с диска, а эффективность чтения значительно повышается.
Кроме Java Ввод-вывод использует кэшированные потоки для повышения эффективности чтения. Большинство приложений также используют кэширование для повышения производительности программы, например наше. частьсуществоватьвстреча по развитию бизнесаиспользоватьRedisКэш в будущемуменьшать Давление на базу данных。оЗачем использовать кэширование для повышения эффективности приложений
,Вы также можете посмотреть за рубежомQuoraотвечать,Очень подробное объяснение.
Интервьюер: А как насчет чтения потока символов?
характервходной потокабстрактный базовый классдаReader
,Он также предоставляет 3 метода для поддержки потока чтения.
(1) Прочитайте один символ.
public int read() throws IOException
(2) Считайте символы в массив.
public int read(char cbuf[]) throws IOException
(3) Считайте символы в часть массива.
abstract public int read(char cbuf[], int off, int len) throws IOException
характерпотокчитатьиз实例даFileReader
,То же самое можно сделатьиспользоватькэшировать поток символы повышают эффективность чтения.
BufferedReader reader = new BufferedReader(new FileReader(new File(SOURCE_PATH)));
Давайте сделаем это подробно,читатьC:\\Users\\Desktop\\JavaProGuide\\read
Все файлы под,Объедините их вместе,писатьприезжатьC:\\Users\\Desktop\\JavaProGuide\\write
внизPRODUCT.txt
документсередина。
public class Client {
private static final String PATH = "C:\\Users\\Desktop\\JavaProGuide\\read";
private static final String FILE_OUT = "C:\\Users\\Desktop\\JavaProGuide\\write\\PRODUCT.txt";
public static void main(String[] args) throws IOException {
File file = new File(PATH);
File[] files = file.listFiles();
BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_OUT));
for (File curFile : files) {
BufferedReader reader = new BufferedReader(new FileReader(curFile));
String line;
while ((line = reader.readLine()) != null) {
writer.write(line);
writer.newLine();
}
reader.close();
}
writer.close();
}
}
Интервьюер: Можете ли вы также рассказать о выходном потоке?
байтвыходной потокабстрактный базовый классдаOutputStream
,характервыходной потокабстрактный базовый классдаWriter
。он Они предоставляют следующие методы соответственно。
байтвыходной потокOutputStream
:
(1) Запишите указанные байты в этот выходной поток.
public abstract void write(int b) throws IOException
(2)уточнитбайтмножествосерединаизb.length
байтписатьэтотвыходной поток。
public void write(byte b[]) throws IOException
(3)уточнитбайтмножествосерединаот偏移量off
началосьlen
индивидуальныйбайтписатьэтотвыходной поток。
public void write(byte b[], int off, int len) throws IOException
характервыходной потокWriter
:
(1) Напишите один символ.
public void write(int c) throws IOException
(2) Записать массив символов.
public void write(char cbuf[]) throws IOException
(3) Запишите часть массива символов.
abstract public void write(char cbuf[], int off, int len) throws IOException
кроме тогохарактервыходной потокдаиспользоватьхарактерманипулировать данными,Так что его можно использоватьхарактер Вместо этого строкахарактермножество,JDKТакже поддерживает следующиеВходдахарактерстроковый метод。
(1) Напишите строку.
public void write(String str) throws IOException
(2) Запишите часть строки.
public void write(String str, int off, int len) throws IOException
Интервьюер: В чем разница между потоком байтов и потоком символов?
Разница между потоком байтов и потоком символов в основном заключается в трех аспектах.
NIOВнешний вид заключается в улучшенииIO
скорость,он сравниваеттрадиционный вход/выходной поток Быстрее。NIOчерез трубыChannel
ибуферBuffer
обрабатывать данные,Думайте о трубопроводе как о шахте,Буфер — это грузовик в шахте.
Программа обменивается данными через буфер в конвейере.,иНе обрабатывает данные напрямую。Программа либо получает данные из буфера,Либо вводите данные в буфер.
NIO предоставляет два основных объекта: каналы и буферы.
(1)трубопроводChannel
:
с традиционнымIO
поток只能只读或只写изОдносторонний потокдругой,NIOряддадвусторонний,Другими словами, операции чтения и записи могут выполняться одновременно.,Это делает обработку данных более эффективной.
(2)буферBuffer
:
Традиционные потоки ввода-вывода обрабатывают только один байт за раз, и каждый прочитанный байт представляет собой системный вызов, включающий переключение контекста между пространством пользователя и пространством ядра, что, как правило, неэффективно.
иNIO
Используйте файлы, отображаемые в памяти, для обработки ввода/выход,Channelпроходитьmap()
методфрагмент данныхкартографированиеприезжать Памятьсередина。программапроходитьBuffer
Выполнение взаимодействия с данными,уменьшать Прямой доступ к исходным источникам данных。NIOблочно-ориентированныйиз处理方式使得эффективностьвыше。
традиционный вход/выходной потокдасинхронная блокировкаIO
Модель,Если в источнике данных нет данных,На этом этапе программа заблокируется.
иNIO
даI/OМультиплексирование Модель,Потоки могутпроситьЕсть ли на канале доступные данные?,Нет необходимости блокировать поток, когда нет данных.
Все данные Включает текстовые данные最终ВседакБайтовая формахранится,Потому что нижний уровень компьютера может понимать только двоичные данные.
Символы в конечном итоге должны быть преобразованы в байтовую форму. Причина, по которой вы можете видеть символы в текстовых файлах, заключается в том, что система преобразует базовую двоичную последовательность в символы.
BufferЕсть3индивидуальныйключевые переменные。
Buffer
Максимальная емкость данных。Buffer
индексная позиция,Это роль указателя записи.Buffer
Первый в миреиндивидуальныйневозможно прочитать/писатьиндексная позиция。кроме тогоBuffer
Также предоставленоget
、put
метод предоставлениянас Данные операции,ииспользоватьget/put
назад,Положение указателя положения также изменится соответствующим образом.
public abstract byte get();
public abstract ByteBuffer put(byte b);
Канал имеет три общих метода: map(), read() и write().
// Сопоставьте область файла канала непосредственно с байтовым буфером.
public abstract MappedByteBuffer map(MapMode mode, long position, long size)
// Последовательность байтов из этого канала в данный буфер dst
public abstract int read(ByteBuffer dst)
// Записывает последовательность байтов из src в данном буфере в этот канал.
public abstract int write(ByteBuffer src)
к下даChannel
из简单использоватькод。
public class TestFileChannel {
public static void main(String[] args) {
File f = new File("D:\\JavaGetOffer\\TestFileChannel.java");
try {
FileChannel inChannel = new FileInputStream(f).getChannel();
FileChannel outChannel = new FileOutputStream("a.txt").getChannel();
MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, f.length());
outChannel.write(buffer);
buffer.clear();
CharBuffer charBuffer = StandardCharsets.UTF_8.newDecoder().decode(buffer);
System.out.println(charBuffer);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
существоватьNIO
До нулевой копии,одининдивидуальныйI/OОперация будет выполнена с теми же данныминесколько копий。Вы можете увидеть картинку ниже,Операция ввода-вывода выполняет четыре операции над данными.,Поставляется с двумя переключателями контекста: Режим ядра и Пользовательский режим одновременно.,Хорошо известно, что переключение контекста — очень ресурсозатратная операция.
Технология нулевого копирования решает вышеупомянутые проблемы. Вы можете сравнить картинку ниже,Технология нулевого копированияуменьшатьКоличество копий фрагмента данных,Больше не нужно передавать данныесуществоватьРежим ядра и пользовательский режимкопировать между,Это также означает отсутствие переключения контекста.,Сделайте передачу данных более эффективной.
Я Брат Нэн, Нэн - это Нэн. Мне нравятся ваши лайки, лайки и лайки на Get.
Творить непросто, поэтому вы можете ставить лайки, собирать и подписываться, чтобы поддержать его. Ваша поддержка — самая большая мотивация для моего творчества.❤️