«1. Обзор

В этом руководстве мы обсудим различные способы чтения файла в ArrayList.

Есть много способов прочитать файл в Java. Когда мы читаем файл, мы можем выполнять множество операций над содержимым этого файла.

Некоторые из этих операций, например сортировка, могут потребовать обработки всего содержимого файла в памяти. Для выполнения таких операций нам может потребоваться прочитать файл как массив или список строк или слов.

2. Использование FileReader

Наиболее простым способом чтения файла в Java является использование FileReader. По определению FileReader — это удобный класс для чтения потока символов из файла.

Для инициализации FileReader доступно несколько конструкторов:

FileReader f = new FileReader(String filepath);
FileReader f = new FileReader(File f);
FileReader f = new FileReader(FileDescriptor fd);

Все эти конструкторы предполагают, что кодировка символов по умолчанию и размер байтового буфера по умолчанию являются подходящими.

Однако, если мы хотим предоставить пользовательскую кодировку символов и размер байтового буфера, мы можем использовать InputStreamReader или FileInputStream.

В следующем коде мы покажем, как читать строки из файла в ArrayList, используя FileReader:

ArrayList<String> result = new ArrayList<>();

try (FileReader f = new FileReader(filename)) {
    StringBuffer sb = new StringBuffer();
    while (f.ready()) {
        char c = (char) f.read();
        if (c == '\n') {
            result.add(sb.toString());
            sb = new StringBuffer();
        } else {
            sb.append(c);
        }
    }
    if (sb.length() > 0) {
        result.add(sb.toString());
    }
}       
return result;

3. Использование BufferedReader

Хотя FileReader довольно прост в использовании, рекомендуется всегда оборачивайте его с помощью BuffereReader при чтении файла.

Это связано с тем, что BufferedReader использует буфер символов для одновременного чтения нескольких значений из потока ввода символов и, следовательно, уменьшает количество вызовов read(), выполняемых базовым FileStream.

Конструкторы для BufferedReader принимают Reader в качестве входных данных. Кроме того, мы также можем указать размер буфера в конструкторах, но для большинства случаев использования размер по умолчанию достаточно велик:

BufferedReader br = new BufferedReader(new FileReader(filename));
BufferedReader br = new BufferedReader(new FileReader(filename), size);

В дополнение к унаследованным методам от класса Reader, BufferedReader также предоставляет метод readLine() , чтобы прочитать всю строку как строку:

ArrayList<String> result = new ArrayList<>();

try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
    while (br.ready()) {
        result.add(br.readLine());
    }
}

4. Использование сканера

Еще один распространенный способ чтения файлов — через сканер.

Scanner — это простой текстовый сканер, используемый для разбора примитивных типов и строк с использованием регулярных выражений.

При чтении файлов Scanner инициализируется с использованием объектов File или FileReader:

Scanner s = new Scanner(new File(filename));
Scanner s = new Scanner(new FileReader(filename));

Подобно BufferedReader, Scanner предоставляет метод readLine() для чтения всей строки. Кроме того, он также предоставляет метод hasNext(), чтобы указать, доступны ли дополнительные значения для чтения или нет:

ArrayList<String> result = new ArrayList<>();

try (Scanner s = new Scanner(new FileReader(filename))) {
    while (s.hasNext()) {
        result.add(s.nextLine());
    }
    return result;
}

Сканер разбивает ввод на токены, используя разделитель, разделителем по умолчанию является пробел. Эти токены могут быть преобразованы в значения разных типов с использованием различных доступных методов next (nextInt, nextLong и т. д.):

ArrayList<Integer> result = new ArrayList<>();

try (Scanner s = new Scanner(new FileReader(filename))) {
    while (s.hasNext()) {
        result.add(s.nextInt());
    }
    return result;
}

5. Использование Files.readAllLines

Вероятно, самый простой способ прочитать файл разобрать все его строки в ArrayList, заключается в использовании метода readAllLines(), доступного в классе Files:

List<String> result = Files.readAllLines(Paths.get(filename));

Этот метод также может принимать параметр charset для чтения в соответствии с определенной кодировкой символов:

Charset charset = Charset.forName("ISO-8859-1");
List<String> result = Files.readAllLines(Paths.get(filename), charset);

~~ ~ 6. Заключение

Подводя итог, мы обсудили некоторые распространенные способы чтения содержимого файла в ArrayList. Кроме того, мы рассмотрели некоторые преимущества и недостатки различных методов.

Например, мы можем использовать BufferedReader для буферизации символов для повышения эффективности. В качестве альтернативы мы могли бы использовать Scanner для чтения примитива с использованием разделителей. Или, возможно, мы могли бы просто использовать Files.readAllLines(), не беспокоясь о базовой реализации.

Как обычно, код доступен в нашем репозитории GitHub.