Как мне создать строку Java из содержимого файла? - PullRequest
1368 голосов
/ 28 ноября 2008

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

Есть ли лучший / другой способ чтения файла в строку в 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();
    }
}

Ответы [ 33 ]

1393 голосов
/ 28 ноября 2008

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

Вот компактная и надежная идиома для 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 добавил метод 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 безопасно упрощает код, а старый ответ, в котором используется сопоставленный байтовый буфер, предотвращает удаление прочитанного файла до тех пор, пока сопоставленный буфер не будет очищен от мусора. Вы можете просмотреть старую версию по ссылке «отредактировано» в этом ответе.

318 голосов
/ 28 ноября 2008

Если вы хотите использовать внешнюю библиотеку, проверьте Apache Commons IO (200 КБ JAR). Он содержит метод 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);
}
172 голосов
/ 17 сентября 2011

Очень экономичное решение на основе 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.

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

93 голосов
/ 28 октября 2016
import java.nio.file.Files;
import java.nio.file.Paths;

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

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

75 голосов
/ 28 ноября 2008

Если вы ищете альтернативу, в которой не используется сторонняя библиотека (например, Commons I / O ), вы можете использовать класс 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();
    }
}
67 голосов
/ 08 февраля 2010

У гуавы есть метод, аналогичный методу из 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 пакет.

52 голосов
/ 16 апреля 2012
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 "";
    }
49 голосов
/ 28 ноября 2008

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

Вот альтернатива, которая этого не делает и которая (IMO) проще для понимания, чем код 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();
    }        
}
47 голосов
/ 29 октября 2014

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

Еще один пример лайнера

String out = String.join("\n", Files.readAllLines(Paths.get("file.txt")));
25 голосов
/ 29 мая 2018

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

  • Гуава: 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();
    }
    

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

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();
    }
}

@ см

...