10

Чтение текстового файла в Java

28

Существует несколько способов чтения и записи данных файлов в Java.

Я хочу прочитать данные в формате ASCII из файла. Какие существуют способы и в чем их различия?

5 ответ(ов)

1

Самый простой способ - использовать класс Scanner в Java вместе с объектом FileReader. Простой пример:

Scanner in = new Scanner(new FileReader("filename.txt"));

У класса Scanner есть несколько методов для чтения строк, чисел и т.д. Дополнительную информацию можно найти на странице документации по Java.

Например, для чтения всего содержимого файла в строку:

StringBuilder sb = new StringBuilder();
while(in.hasNext()) {
    sb.append(in.next());
}
in.close();
outString = sb.toString();

Если вам нужно использовать определенную кодировку, вы можете воспользоваться следующим вариантом вместо FileReader:

new InputStreamReader(new FileInputStream(fileUtf8), StandardCharsets.UTF_8)
1

Вот простое решение:

String content = new String(Files.readAllBytes(Paths.get("sample.txt")));

Или, если нужно считать содержимое в виде списка строк:

List<String> content = Files.readAllLines(Paths.get("sample.txt"));

Оба варианта используют класс Files и позволяют удобно работать с файлами в Java.

0

Вот еще один способ сделать это без использования внешних библиотек:

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public String readFile(String filename)
{
    String content = null;
    File file = new File(filename); // Например, foo.txt
    FileReader reader = null;
    try {
        reader = new FileReader(file);
        char[] chars = new char[(int) file.length()];
        reader.read(chars);
        content = new String(chars);
        reader.close();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if(reader != null){
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return content;
}

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

0

Я провел бенчмаркинг разных способов чтения файлов в Java и поделюсь своими находками. Вкратце, самый быстрый способ - использовать BufferedInputStream совместно с FileInputStream. Если нужно читать много файлов, то использование трех потоков позволяет уменьшить общее время выполнения примерно вдвое. Однако добавление большего количества потоков постепенно ухудшает производительность, и с двадцатью потоками время исполнения становится в три раза больше, чем с одним потоком.

Считаем, что необходимо прочитать файл и выполнить что-то осмысленное с его содержимым. В моих примерах я читаю строки из лог-файла и подсчитываю те, которые содержат значения, превышающие определенный порог. Поэтому я предполагаю, что однострочный код Java 8 вида Files.lines(Paths.get("/path/to/file.txt")).map(line -> line.split(";")) не подходит.

Я тестировал на Java 1.8, Windows 7 и как на SSD, так и на HDD.

Я написал шесть различных реализаций:

rawParse: Использует BufferedInputStream над FileInputStream и считывает строки посимвольно. Этот метод превзошел все другие однопоточные подходы, но может быть неудобным для не-ASCII файлов.

lineReaderParse: Использует BufferedReader над FileReader, читает построчно и разбивает строки, вызывая String.split(). Этот метод примерно на 20% медленнее, чем rawParse.

lineReaderParseParallel: То же самое, что и lineReaderParse, но использует несколько потоков. Это самый быстрый вариант во всех случаях.

nioFilesParse: Использует java.nio.files.Files.lines().

nioAsyncParse: Использует AsynchronousFileChannel с обработчиком завершения и пулом потоков.

nioMemoryMappedParse: Использует файловое отображение в память. Это действительно плохая идея, время выполнения оказывается как минимум в три раза длиннее, чем у любой другой реализации.

Вот средние времена чтения 204 файлов по 4 МБ каждый на четырехядерном процессоре i7 и SSD. Файлы генерировались динамически, чтобы избежать кэширования на диске.

rawParse                11.10 sec
lineReaderParse         13.86 sec
lineReaderParseParallel  6.00 sec
nioFilesParse           13.52 sec
nioAsyncParse           16.06 sec
nioMemoryMappedParse    37.68 sec

Я обнаружил, что разница между работой на SSD и HDD меньше, чем ожидал, SSD оказался примерно на 15% быстрее. Это может быть связано с тем, что файлы генерировались на неконтролируемом HDD и читались последовательно, в результате чего вращающийся диск может выполнять операции почти так же, как и SSD.

Меня удивила низкая производительность реализации nioAsyncParse. Либо я что-то реализовал неправильно, либо многопоточная реализация с использованием NIO и обработчика завершения работает так же (или даже хуже), чем однопоточная реализация с использованием java.io API. Более того, асинхронный парсер с CompletionHandler требует гораздо больше строк кода и сложнее для корректной реализации, чем простая реализация на старых потоках.

Теперь представлю шесть реализаций, за которыми следует класс, содержащий их все, плюс параметризуемый метод main(), который позволяет поиграть с количеством файлов, размером файлов и степенью параллелизма. Обратите внимание, что размер файлов варьируется плюс-минус 20%. Это сделано, чтобы избежать эффекта из-за того, что все файлы одинакового размера.

Полная исполнимая реализация всех случаев доступна по ссылке: FileReadBenchmark.java

0

Вот три проверенных метода для чтения файлов в Java:

1. Используя BufferedReader

package io;
import java.io.*;

public class ReadFromFile2 {
    public static void main(String[] args) throws Exception {
        File file = new File("C:\\Users\\pankaj\\Desktop\\test.java");
        BufferedReader br = new BufferedReader(new FileReader(file));
        String st;
        while ((st = br.readLine()) != null) {
            System.out.println(st);
        }
        br.close();
    }
}

Этот метод подходит для чтения текстовых файлов построчно. Важно закрывать BufferedReader после окончания чтения, чтобы избежать утечки ресурсов.

2. Используя Scanner

package io;

import java.io.File;
import java.util.Scanner;

public class ReadFromFileUsingScanner {
    public static void main(String[] args) throws Exception {
        File file = new File("C:\\Users\\pankaj\\Desktop\\test.java");
        Scanner sc = new Scanner(file);
        while (sc.hasNextLine()) {
            System.out.println(sc.nextLine());
        }
        sc.close();
    }
}

Scanner удобен для чтения файлов построчно и предоставляет ряд методов для работы с разными форматами данных. Не забудьте закрыть сканер после использования.

3. Используя FileReader

package io;
import java.io.*;

public class ReadingFromFile {
    public static void main(String[] args) throws Exception {
        FileReader fr = new FileReader("C:\\Users\\pankaj\\Desktop\\test.java");
        int i;
        while ((i = fr.read()) != -1) {
            System.out.print((char) i);
        }
        fr.close();
    }
}

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

Чтение всего файла без цикла с использованием Scanner

package io;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class ReadingEntireFileWithoutLoop {
    public static void main(String[] args) throws FileNotFoundException {
        File file = new File("C:\\Users\\pankaj\\Desktop\\test.java");
        Scanner sc = new Scanner(file);
        sc.useDelimiter("\\Z");
        System.out.println(sc.next());
        sc.close();
    }
}

Этот метод позволяет прочитать весь файл сразу, не используя цикл. Убедитесь, что используете правильный делимитор (в данном случае \\Z), который указывает на конец файла.

Выбирайте метод в зависимости от ваших требований к чтению файлов.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь