Как создать строку 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();
    }
}

Ответы

Ответ 1

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

Java 11 добавила метод readString() для чтения небольших файлов в виде String, сохраняя разделители строк:

String content = Files.readString(path, StandardCharsets.US_ASCII);

Для версий между Java 7 и 11, здесь компактная и надежная идиома, заключенная в служебный метод:

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 добавила метод Files.lines() для создания Stream<String>. Опять же, этот метод с потерями, потому что разделители строк удалены. Если при чтении файла возникает исключение IOException, оно помещается в исключение UncheckedIOException, поскольку Stream не принимает лямбда-выражения, которые выдают проверенные исключения.

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

Этот Stream нуждается в вызове close(); это плохо документировано в API, и я подозреваю, что многие люди даже не замечают, что Stream имеет метод close(). Обязательно используйте ARM-блок, как показано на рисунке.

Если вы работаете с источником, отличным от файла, вы можете использовать метод lines() в BufferedReader.

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

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

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

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

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

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

Класс StandardCharsets определяет некоторые константы для кодировок, требуемых для всех сред выполнения Java:

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

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

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

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

Ответ 2

Если вы хотите использовать внешнюю библиотеку, обратитесь к Apache Commons IO (JAR на 200 КБ). Он содержит метод org.apache.commons.io.FileUtils.readFileToString() который позволяет читать весь File в String с одной строкой кода.

Пример:

import java.io.*;
import java.nio.charset.*;
import org.apache.commons.io.*;

public String readFile() throws IOException {
    File file = new File("data.txt");
    return FileUtils.readFileToString(file, StandardCharsets.UTF_8);
}

Ответ 3

Очень простое решение на основе Scanner:

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

Или с помощью блока try-with-resources, который вызовет scanner.close() для вас:

try (Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" )) {
    String text = scanner.useDelimiter("\\A").next();
}

Помните, что конструктор Scanner может генерировать IOException. И не забудьте импортировать java.io и java.util.

Источник: блог Пэт Нимейер

Ответ 4

import java.nio.file.Files;
import java.nio.file.Paths;

String content = new String(Files.readAllBytes(Paths.get("readMe.txt")), "UTF-8");

начиная с Java 7 вы можете сделать это таким образом.

Ответ 5

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

private String readFile(String pathname) throws IOException {

    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int)file.length());        

    try (Scanner scanner = new Scanner(file)) {
        while(scanner.hasNextLine()) {
            fileContents.append(scanner.nextLine() + System.lineSeparator());
        }
        return fileContents.toString();
    }
}

Ответ 6

Guava имеет метод, аналогичный методу из 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. Для текущего источника см. Классы Files, CharStreams, ByteSource и CharSource в com.google.common.io.

Ответ 7

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 "";
    }

Ответ 8

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

Здесь альтернатива, которая этого не делает, и которая (ИМО) проще понять, чем код NIO (хотя она все еще использует 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();
    }        
}

Ответ 9

Если вам нужна обработка строк (параллельная обработка), у Java 8 есть отличный 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

В примерах JDK sample/lambda/BulkDataOperations, которые можно загрузить с страницы загрузки Java Java SE 8,

Еще один пример liner

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

Ответ 10

Собраны все возможные способы чтения файла как строки с диска или сети.

  • Гуава: Google использует классы Resources, Files

    static Charset charset = com.google.common.base.Charsets.UTF_8;
    public static String guava_ServerFile( URL url ) throws IOException {
        return Resources.toString( url, charset );
    }
    public static String guava_DiskFile( File file ) throws IOException {
        return Files.toString( file, charset );
    }
    

  • APACHE - ОБЩИЙ IO с использованием классов IOUtils, FileUtils

    static Charset encoding = org.apache.commons.io.Charsets.UTF_8;
    public static String commons_IOUtils( URL url ) throws IOException {
        java.io.InputStream in = url.openStream();
        try {
            return IOUtils.toString( in, encoding );
        } finally {
            IOUtils.closeQuietly(in);
        }
    }
    public static String commons_FileUtils( File file ) throws IOException {
        return FileUtils.readFileToString( file, encoding );
        /*List<String> lines = FileUtils.readLines( fileName, encoding );
        return lines.stream().collect( Collectors.joining("\n") );*/
    }
    

  • Java 8 BufferReader с использованием Stream API

    public static String streamURL_Buffer( URL url ) throws IOException {
        java.io.InputStream source = url.openStream();
        BufferedReader reader = new BufferedReader( new InputStreamReader( source ) );
        //List<String> lines = reader.lines().collect( Collectors.toList() );
        return reader.lines().collect( Collectors.joining( System.lineSeparator() ) );
    }
    public static String streamFile_Buffer( File file ) throws IOException {
        BufferedReader reader = new BufferedReader( new FileReader( file ) );
        return reader.lines().collect(Collectors.joining(System.lineSeparator()));
    }
    

  • Класс сканера с регулярным выражением \A который соответствует началу ввода.

    static String charsetName = java.nio.charset.StandardCharsets.UTF_8.toString();
    public static String streamURL_Scanner( URL url ) throws IOException {
        java.io.InputStream source = url.openStream();
        Scanner scanner = new Scanner(source, charsetName).useDelimiter("\\A");
        return scanner.hasNext() ? scanner.next() : "";
    }
    public static String streamFile_Scanner( File file ) throws IOException {
        Scanner scanner = new Scanner(file, charsetName).useDelimiter("\\A");
        return scanner.hasNext() ? scanner.next() : "";
    }
    

  • Java 7 (java.nio.file.Files.readAllBytes)

    public static String getDiskFile_Java7( File file ) throws IOException {
        byte[] readAllBytes = java.nio.file.Files.readAllBytes(Paths.get( file.getAbsolutePath() ));
        return new String( readAllBytes );
    }
    

  • BufferedReader с использованием InputStreamReader.

    public static String getDiskFile_Lines( File file ) throws IOException {
        StringBuffer text = new StringBuffer();
        FileInputStream fileStream = new FileInputStream( file );
        BufferedReader br = new BufferedReader( new InputStreamReader( fileStream ) );
        for ( String line; (line = br.readLine()) != null; )
            text.append( line + System.lineSeparator() );
        return text.toString();
    }
    

Пример с основным методом для доступа к вышеуказанным методам.

public static void main(String[] args) throws IOException {
    String fileName = "E:/parametarisation.csv";
    File file = new File( fileName );

    String fileStream = commons_FileUtils( file );
            // guava_DiskFile( file );
            // streamFile_Buffer( file );
            // getDiskFile_Java7( file );
            // getDiskFile_Lines( file );
    System.out.println( " File Over Disk : \n"+ fileStream );


    try {
        String src = "https://code.jquery.com/jquery-3.2.1.js";
        URL url = new URL( src );

        String urlStream = commons_IOUtils( url );
                // guava_ServerFile( url );
                // streamURL_Scanner( url );
                // streamURL_Buffer( url );
        System.out.println( " File Over Network : \n"+ urlStream );
    } catch (MalformedURLException e) {
        e.printStackTrace();
    }
}

@увидеть

Ответ 11

Если это текстовый файл, почему бы не использовать apache commons-io?

Он имеет следующий метод

public static String readFileToString(File file) throws IOException

Если вы хотите, чтобы строки в виде списка использовали

public static List<String> readLines(File file) throws IOException

Ответ 12

Поскольку JDK 11:

String file = ...
Path path = Paths.get(file);
String content = Files.readString(path);
// Or readString(path, someCharset), if you need a Charset different from UTF-8

Ответ 13

Чтобы прочитать файл как двоичный и преобразовать в конец

public static String readFileAsString(String filePath) throws IOException {
    DataInputStream dis = new DataInputStream(new FileInputStream(filePath));
    try {
        long len = new File(filePath).length();
        if (len > Integer.MAX_VALUE) throw new IOException("File "+filePath+" too large, was "+len+" bytes.");
        byte[] bytes = new byte[(int) len];
        dis.readFully(bytes);
        return new String(bytes, "UTF-8");
    } finally {
        dis.close();
    }
}

Ответ 14

В Java 7 это мой предпочтительный вариант для чтения файла UTF-8:

String content = new String(Files.readAllBytes(Paths.get(filename)), "UTF-8");

Начиная с Java 7, JDK имеет новый API java.nio.file, который предоставляет множество ярлыков, поэтому сторонние библиотеки не всегда необходимы для простых операций с файлами.

Ответ 15

Java пытается быть чрезвычайно общим и гибким во всем, что он делает. В результате что-то, что относительно просто на языке сценариев (ваш код будет заменен на "open(file).read()" в python) намного сложнее. Кажется, что нет более короткого способа сделать это, за исключением использования внешней библиотеки (например, Willi aus Rohr). Ваши варианты:

  • Используйте внешнюю библиотеку.
  • Скопируйте этот код во все ваши проекты.
  • Создайте собственную мини-библиотеку, которая часто использует функции, которые вы используете.

Ваш лучший выбор, вероятно, второй, так как он имеет наименьшие зависимости.

Ответ 16

Использование JDK 8 или выше:

не использовались внешние библиотеки

Вы можете создать новый объект String из содержимого файла (используя классы из пакета java.nio.file):

public String readStringFromFile(String filePath) throws IOException {
    String fileContent = new String(Files.readAllBytes(Paths.get(filePath)));
    return fileContent;
}

Ответ 17

Существует вариация по той же теме, которая использует цикл for, а не цикл while, чтобы ограничить область строки. Является ли это "лучше" вопросом личного вкуса.

for(String line = reader.readLine(); line != null; line = reader.readLine()) {
    stringBuilder.append(line);
    stringBuilder.append(ls);
}

Ответ 18

Если у вас нет доступа к классу Files, вы можете использовать собственное решение.

static String readFile(File file, String charset)
        throws IOException
{
    FileInputStream fileInputStream = new FileInputStream(file);
    byte[] buffer = new byte[fileInputStream.available()];
    int length = fileInputStream.read(buffer);
    fileInputStream.close();
    return new String(buffer, 0, length, charset);
}

Ответ 19

Однострочное решение

String content = new String(Files.readAllBytes(Paths.get("d://test.txt")));

Ответ 20

Гибкое решение с использованием IOUtils от Apache commons- io в сочетании с StringWriter:

Reader input = new FileReader();
StringWriter output = new StringWriter();
try {
  IOUtils.copy(input, output);
} finally {
  input.close();
}
String fileContents = output.toString();

Он работает с любым считывателем или потоком ввода (не только с файлами), например, при чтении с URL-адреса.

Ответ 21

public static String slurp (final File file)
throws IOException {
    StringBuilder result = new StringBuilder();

    BufferedReader reader = new BufferedReader(new FileReader(file));

    try {
        char[] buf = new char[1024];

        int r = 0;

        while ((r = reader.read(buf)) != -1) {
            result.append(buf, 0, r);
        }
    }
    finally {
        reader.close();
    }

    return result.toString();
}

Ответ 22

Этот метод использует метод RandomAccessFile.readFully, он, как представляется, доступен из JDK 1.0!

public static String readFileContent(String filename, Charset charset) throws IOException {
    RandomAccessFile raf = null;
    try {
        raf = new RandomAccessFile(filename, "r");
        byte[] buffer = new byte[(int)raf.length()];
        raf.readFully(buffer);
        return new String(buffer, charset);
    } finally {
        closeStream(raf);
    }
} 


private static void closeStream(Closeable c) {
    if (c != null) {
        try {
            c.close();
        } catch (IOException ex) {
            // do nothing
        }
    }
}

Ответ 23

Помните, что при использовании fileInputStream.available() возвращаемое целое число не должно представлять фактический размер файла, а скорее угаданную сумму байтов, которую система должна иметь возможность читать из потока без блокировки ввода-вывода. Безопасный и простой способ может выглядеть так:

public String readStringFromInputStream(FileInputStream fileInputStream) {
    StringBuffer stringBuffer = new StringBuffer();
    try {
        byte[] buffer;
        while (fileInputStream.available() > 0) {
            buffer = new byte[fileInputStream.available()];
            fileInputStream.read(buffer);
            stringBuffer.append(new String(buffer, "ISO-8859-1"));
        }
    } catch (FileNotFoundException e) {
    } catch (IOException e) { }
    return stringBuffer.toString();
}

Следует учитывать, что этот подход не подходит для многобайтовых кодировок символов, таких как UTF-8.

Ответ 24

Вы можете попробовать Scanner и File class, несколько решений линии

 try
{
  String content = new Scanner(new File("file.txt")).useDelimiter("\\Z").next();
  System.out.println(content);
}
catch(FileNotFoundException e)
{
  System.out.println("not found!");
}

Ответ 25

Пользователь java.nio.Files для чтения всех строк файла.

public String readFile() throws IOException {
        File fileToRead = new File("file path");
        List<String> fileLines = Files.readAllLines(fileToRead.toPath());
        return StringUtils.join(fileLines, StringUtils.EMPTY);
}

Ответ 26

После Ctrl + F'ing после сканера, я думаю, что также нужно указать решение для сканера. В самой легкой для чтения моде это выглядит следующим образом:

public String fileToString(File file, Charset charset) {
  Scanner fileReader = new Scanner(file, charset);
  fileReader.useDelimiter("\\Z"); // \Z means EOF.
  String out = fileReader.next();
  fileReader.close();
  return out;
}

Если вы используете Java 7 или новее (и вам действительно нужно), подумайте о том, как использовать try-with-resources для упрощения чтения кода. Больше ничего не забивает все. Но в основном стилистический выбор звучит.

Я отправляю это в основном для завершения, так как если вам нужно сделать это много, должны быть вещи в java.nio.file.Files, которые должны лучше выполнять работу.

Мое предложение было бы использовать Files # readAllBytes (Path), чтобы захватить все байты и передать его новому String (byte [] Charset), чтобы получить строку, из которой вы можете доверять. Коды будут иметь для вас значение в течение вашей жизни, поэтому остерегайтесь этого материала сейчас.

Другие дали код и прочее, и я не хочу красть их славу.;)

Ответ 27

Используя эту библиотеку, это одна строка:

String data = IO.from(new File("data.txt")).toString();

Ответ 28

Также, если ваш файл находится внутри банки, вы также можете использовать это:

public String fromFileInJar(String path) {
    try ( Scanner scanner 
            = new Scanner(getClass().getResourceAsStream(path))) {
        return scanner.useDelimiter("\\A").next();
    }
}

Путь должен начинаться с /, например, если ваша банка

my.jar/com/some/thing/a.txt

Затем вы хотите вызвать его следующим образом:

String myTxt = fromFileInJar("/com/com/thing/a.txt");

Ответ 29

В одной строке (Java 8), если у вас есть Reader:

String sMessage = String.join("\n", reader.lines().collect(Collectors.toList()));

Ответ 30

Основываясь на ответе @erickson, вы можете использовать:

public String readAll(String fileName) throws IOException {
    List<String> lines = Files.readAllLines(new File(fileName).toPath());
    return String.join("\n", lines.toArray(new String[lines.size()]));
}