Вопрос: Как создать строку Java из содержимого файла?


Я уже некоторое время использую идиому ниже. И это, по-видимому, самый распространенный, по крайней мере, на сайтах, которые я посетил.

Есть ли лучший / отличный способ прочитать файл в строке на Java?

private String readFile(String file) throws IOException {
    BufferedReader reader = new BufferedReader(new FileReader (file));
    String         line = null;
    StringBuilder  stringBuilder = new StringBuilder();
    String         ls = System.getProperty("line.separator");

    try {
        while((line = reader.readLine()) != null) {
            stringBuilder.append(line);
            stringBuilder.append(ls);
        }

        return stringBuilder.toString();
    } finally {
        reader.close();
    }
}

1194


источник


Ответы:


Читать весь текст из файла

Вот компактный, надежный идиом для Java 7, завершенный в утилите:

static String readFile(String path, Charset encoding) 
  throws IOException 
{
  byte[] encoded = Files.readAllBytes(Paths.get(path));
  return new String(encoded, encoding);
}

Чтение строк текста из файла

Java 7 добавила удобный метод для чтения файла в виде строк текста, представленный как List<String>, Этот подход является «потерянным», поскольку разделители строк удаляются с конца каждой строки.

List<String> lines = Files.readAllLines(Paths.get(path), encoding);

В Java 8, BufferedReaderдобавлен новый метод, lines()для производства Stream<String>, Если IOExceptionвстречается при чтении файла, он завернут в UncheckedIOException, поскольку Streamне принимает лямбда, которые бросают проверенные исключения.

try (BufferedReader r = Files.newBufferedReader(path, encoding)) {
  r.lines().forEach(System.out::println);
}

Существует также Files.lines()метод, который делает что-то очень похожее, возвращая Stream<String>непосредственно. Но мне это не нравится. Streamнуждается в close()вызов; это плохо документировано по API, и я подозреваю, что многие люди даже не замечают Streamимеет close()метод. Таким образом, ваш код будет выглядеть очень похоже, например:

try (Stream<String> lines = Files.lines(path, encoding)) {
  lines.forEach(System.out::println);
}

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

Использование памяти

Первый метод, который сохраняет разрывы строк, может временно потребовать памяти в несколько раз больше размера файла, потому что на короткое время содержимое необработанного файла (байтовый массив) и декодированные символы (каждый из которых составляет 16 бит, даже если кодируется как 8 бит в файле) одновременно находятся в памяти. Безопаснее всего применять к файлам, которые, как известно, малы относительно доступной памяти.

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

Для чтения больших файлов вам нужен другой дизайн для вашей программы, который читает фрагмент текста из потока, обрабатывает его и затем переходит к следующему, повторно используя один и тот же блок памяти фиксированного размера. Здесь «большой» зависит от характеристик компьютера. В настоящее время этот порог может быть много гигабайт оперативной памяти. Третий метод, используя Stream<String>это один из способов сделать это, если ваши «записи» ввода - это отдельные строки. (Используя readLine()метод BufferedReaderявляется процедурным эквивалентом этого подхода.)

Кодировка символов

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

StandardCharsetsclass определяют некоторые константы для кодировок, требуемых для всех Java-процессов:

String content = readFile("test.txt", StandardCharsets.UTF_8);

По умолчанию платформа доступна из Charsetкласс сам:

String content = readFile("test.txt", Charset.defaultCharset());

Примечание. Этот ответ в значительной степени заменяет мою версию Java 6. Утилита Java 7 безопасно упрощает код, а старый ответ, который использовал отображенный байт-буфер, предотвратил удаление файла, который был прочитан, до тех пор, пока отображаемый буфер не будет собран мусором. Вы можете просмотреть старую версию с помощью «отредактированной» ссылки на этот ответ.


1238



Commons FileUtils.readFileToString:

public static String readFileToString(File file)
                       throws IOException

Читает содержимое файла в String, используя кодировку по умолчанию   для ВМ. Файл всегда закрыт.

Параметры:

  • file- файл для чтения, не должен быть нулевым

Возвращает:   содержимое файла, никогда не имеет значения

Броски:    - IOException- в случае ошибки ввода-вывода

Поскольку:   Commons IO 1.3.1

Код, используемый (косвенно) этим классом:

IOUtils.java под Лицензия Apache 2.0 ,

public static long copyLarge(InputStream input, OutputStream output)
       throws IOException {
   byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
   long count = 0;
   int n = 0;
   while (-1 != (n = input.read(buffer))) {
       output.write(buffer, 0, n);
       count += n;
   }
   return count;
}

Он очень похож на тот, который используется Ritche_W.


292



Из эта страница очень сухое решение:

Scanner scanner = new Scanner( new File("poem.txt") );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Put this call in a finally block

или

Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Put this call in a finally block

Если вы хотите установить кодировку


157



Если вы ищете альтернативу, которая не включает стороннюю библиотеку (например, Commons I / O ), вы можете использовать сканер класс:

private String readFile(String pathname) throws IOException {

    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int)file.length());
    Scanner scanner = new Scanner(file);
    String lineSeparator = System.getProperty("line.separator");

    try {
        while(scanner.hasNextLine()) {
            fileContents.append(scanner.nextLine() + lineSeparator);
        }
        return fileContents.toString();
    } finally {
        scanner.close();
    }
}

68



гуайява имеет метод, аналогичный методу из Commons IOUtils, о котором говорил Вилли Аус Рор:

import com.google.common.base.Charsets;
import com.google.common.io.Files;

// ...

String text = Files.toString(new File(path), Charsets.UTF_8);

РЕДАКТИРОВАТЬ Оскар Рейес

Это (упрощенный) базовый код в цитируемой библиотеке:

InputStream in = new FileInputStream(file);
byte[] b  = new byte[file.length()];
int len = b.length;
int total = 0;

while (total < len) {
  int result = in.read(b, total, len - total);
  if (result == -1) {
    break;
  }
  total += result;
}

return new String( b , Charsets.UTF_8 );

редактировать (Jonik): Вышеупомянутое не соответствует исходному коду последних версий Guava. Для текущего источника см. Классы файлы , CharStreams , ByteSource а также CharSource в com.google.common.io пакет.


63



import java.nio.file.Files;

.......

 String readFile(String filename) {
            File f = new File(filename);
            try {
                byte[] bytes = Files.readAllBytes(f.toPath());
                return new String(bytes,"UTF-8");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "";
    }

50



If you need a string processing (parallel processing) Java 8 has the great Stream API.

String result = Files.lines(Paths.get("file.txt"))
                    .parallel() // for parallel processing 
                    .map(String::trim) // to change line   
                    .filter(line -> line.length() > 2) // to filter some lines by a predicate                        
                    .collect(Collectors.joining()); // to join lines

More examples are available in JDK samples sample/lambda/BulkDataOperations that can be downloaded from Oracle Java SE 8 download page

Another one liner example

String out = String.join("\n", Files.readAllLines(Paths.get("file.txt")));

44



That code will normalize line breaks, which may or may not be what you really want to do.

Here's an alternative which doesn't do that, and which is (IMO) simpler to understand than the NIO code (although it still uses java.nio.charset.Charset):

public static String readFile(String file, String csName)
            throws IOException {
    Charset cs = Charset.forName(csName);
    return readFile(file, cs);
}

public static String readFile(String file, Charset cs)
            throws IOException {
    // No real need to close the BufferedReader/InputStreamReader
    // as they're only wrapping the stream
    FileInputStream stream = new FileInputStream(file);
    try {
        Reader reader = new BufferedReader(new InputStreamReader(stream, cs));
        StringBuilder builder = new StringBuilder();
        char[] buffer = new char[8192];
        int read;
        while ((read = reader.read(buffer, 0, buffer.length)) > 0) {
            builder.append(buffer, 0, read);
        }
        return builder.toString();
    } finally {
        // Potential issue here: if this throws an IOException,
        // it will mask any others. Normally I'd use a utility
        // method which would log exceptions and swallow them
        stream.close();
    }        
}

44