Як створити рядок Java із вмісту файлу?


1513

Я вже деякий час використовую ідіому нижче. І це, здається, є найбільш розповсюдженим, принаймні на сайтах, які я відвідував.

Чи є кращий / інший спосіб зчитувати файл у рядку на 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();
    }
}

7
Хтось може мені дуже просто пояснити, що з NIO? Кожного разу, коли я читаю про це, я гублюся в n-й згадці про канал :(
OscarRyz

7
пам'ятайте, що не гарантується, що роздільник рядків у файлі не є таким самим, як роздільник рядків системи.
Генрік Пол

138
Чи можете ви, будь ласка, вставити належну спробу, нарешті, що закриває читача? Хтось може насправді використовувати цей приклад і ввести помилку в свій код.
Ганс-Пітер Штерр

6
У наведеному вище коді є помилка додавання додаткових символів нового рядка в останньому рядку. Це має бути щось на зразок наступного, якщо (line = reader.readLine ())! = Null) {stringBuilder.append (line); } while (line = reader.readLine ())! = null) {stringBuilder.append (ls); stringBuilder.append (рядок); }
Глибокий

27
Java 7 знайомить byte[] Files.readAllBytes(file);тих, хто пропонує однолінійне рішення сканера: Вам не потрібно закривати його?
Val

Відповіді:


1533

Прочитайте весь текст із файлу

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()метод отримання a Stream<String>. Знову ж таки, цей метод є втратним, оскільки роздільники ліній позбавлені. Якщо IOExceptionпід час читання файлу виникає "an" 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 біт у файлі) постійно перебувають у пам'яті. Це найбезпечніше застосувати до файлів, які, як ви знаєте, малі відносно наявної пам’яті.

Другий метод, читаючи рядки, як правило, більш ефективний у пам'яті, оскільки вхідний байтовий буфер для декодування не повинен містити весь файл. Однак це все ще не підходить для файлів, які є дуже великими щодо наявної пам'яті.

Для читання великих файлів вам потрібен інший дизайн для вашої програми, який читає шматок тексту з потоку, обробляє його, а потім переходить до наступного, використовуючи той же блок пам'яті фіксованого розміру. Тут "великий" залежить від специфікацій комп'ютера. В даний час цей поріг може становити багато гігабайт оперативної пам’яті. Третій метод, використовуючи a, 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 безпечно спрощує код, і стара відповідь, яка використовувала відображений байтовий буфер, не дозволила видалити прочитаний файл, поки зібраний буфер не зібрав сміття. Ви можете переглянути стару версію через посилання "відредагований" на цю відповідь.


3
Технічно кажучи, це O (n) у часі та просторі. Якісно, ​​завдяки вимозі незмінності Strings, це досить важко в пам'яті; тимчасово є дві копії даних char в пам’яті, плюс приміщення для закодованих байтів. Якщо припустити деяке однобайтове кодування, йому (тимчасово) потрібно 5 байт пам'яті для кожного символу у файлі. Оскільки запитання задається спеціально для String, це те, що я показую, але якщо ви можете працювати з CharBuffer, повернутим «декодуванням», потреба в пам'яті значно менша. По мірі часу, я не думаю, що ви знайдете щось швидше в основних язиках Java.
erickson

5
Можливий друкарський помилок? NIO має клас Charset (не CharSet), який називається java.nio.charset.Charset. Це те, яким повинен був бути CharSet?
Джонатан Райт

31
Примітка. Після використання цього коду я виявив, що ви не можете надійно видалити файл, прочитавши його цим методом, що може бути проблемою, але не моєю. Можливо, це стосується цього питання: bugs.sun.com/bugdatabase/view_bug.do?bug_id=4715154 ? Нарешті я пішов із пропозицією Джона Скіта, який не страждає від цієї помилки. У будь-якому випадку, я просто хотів дати інформацію для інших людей, про всяк випадок ...
Sébastien Nussbaumer

5
@ Sébastien Nussbaumer: Я також наткнувся на цю проблему. Дивно, що помилка була позначена "Не виправиться". Це по суті означає, що FileChannel#mapвзагалі є непридатним.
Joonas Pulakaka

4
@ Sébastien Nussbaumer: Помилка видалена з бази даних Oracle / Sun Bug: "Ця помилка недоступна." Google кешував
bobndrew

350

Якщо ви бажаєте використовувати зовнішню бібліотеку, перегляньте IO 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);
}

Я не знаходжу цього методу в наданій вами URL.
OscarRyz

2
Це в класі org.apache.commons.io.FileUtils
Cyrille Ka

2
Я також використовую FileUtils, але мені цікаво, що краще betwwen за допомогою FileUtils або прийнятої відповіді nio?
Гійом

4
@Guillaume: Найголовніше питання - чи вам комфортно мати залежність від сторонньої бібліотеки. Якщо у вашому проекті є Commons IO або Guava , тоді використовуйте це (лише для простоти коду; інакше, ймовірно, не буде помітної різниці).
Jonik

183

Дуже пісне рішення, засноване на 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

Або за допомогою блоку спробу використання ресурсів , який вимагатиме 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
\\ Працює тому, що немає "іншого початку файлу", тому ви насправді читаєте останній маркер ... який також є першим. Ніколи не пробував із \\ Z. Також зауважте, що ви можете прочитати все, що можна прочитати, як-от Файли, InputStreams, канали ... Я інколи використовую цей код для читання з вікна відображення затемнення, коли я не впевнений, чи читаю я один чи інший файл .. ., так, однокласник мене бентежить.
Пабло Грисафі

1
Як плакат, я можу сказати, що я дійсно не знаю, чи і коли файл належним чином закритий ... Я ніколи не записую цей у виробничому коді, я використовую його лише для тестів або налагодження.
Пабло Грісафі

2
У нього ліміт 1024 символів, я думаю
примхливий

20
Сканер реалізує Closeable (він викликає закриття на джерелі) - тому, хоча він елегантний, він насправді не повинен бути одноколірним. Типовий розмір буфера - 1024, але Scanner збільшить розмір у міру необхідності (див. Scanner # makeSpace ())
earcam

8
Цей не вдається для порожніх файлів з a java.util.NoSuchElementException.
SpaceTrucker

116
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

String content = new String(Files.readAllBytes(Paths.get("readMe.txt")), StandardCharsets.UTF_8);

оскільки java 7 ви можете це зробити так.


Це слід сприймати як відповідь - однорядний, без зовнішніх ліб.
Вишня

Це додало символу нового рядка наприкінці, навіть якщо його не було у файлі
Стефан Хаберль,

79

Якщо ви шукаєте альтернативу, яка не передбачає сторонніх бібліотек (наприклад, 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();
    }
}

2
Я думаю, що це найкращий спосіб. Перевірте java.sun.com/docs/books/tutorial/essential/io/scanning.html
Тарського

3
Конструктор сканера, який приймає рядок, не розглядає рядок як ім'я файлу для читання, а як текст, який потрібно сканувати. Я постійно робив цю помилку. : - /
Алан Мур

@Alan, хороший улов. Я трохи відредагував відповідь Дона, щоб виправити це (сподіваюся).
Джонік

3
fileContents.append (scanner.nextLine ()). додати (lineSeparator);
заборона-геоінженерія

1
Змініть оператор ініціалізації на Scanner scanner = new Scanner((Readable) new BufferedReader(new FileReader(file)));. В іншому випадку ви можете захопити лише частину файлу.
Вей Ян

71

Гуава має метод, аналогічний тому, який виклав Віллі аур Рор:

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

// ...

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

EDIT від PiggyPiglet
Files#toString є застарілим і належить до вилучення Octobor 2019. Замість цього використовувати Files.asCharSource(new File(path), StandardCharsets.UTF_8).read();

EDIT Оскара Рейєса

Це (спрощений) базовий код цитованої бібліотеки:

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

Редагувати (за Джоніком): Наведене вище не відповідає вихідному коду останніх версій Guava. Для поточного джерела див. Класи " Файли" , " CharStreams" , " ByteSource" та " CharSource" в пакеті com.google.common.io .


Цей код має трансляцію від long до int, що може спливати шалену поведінку з великими файлами. Є додаткові пробіли і де ви закриваєте вхідний потік?
Mohamed Taher Alrefaie

@MTA: потік буде закритий, зверніть увагу на використання Closerв CharSource . Код у відповіді не є фактичним, поточним джерелом Guava.
Джонік

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

6
Або ще простіше:new String(Files.readAllBytes(FileSystems.getDefault().getPath( filename)));

12
або new String(Files.readAllBytes(Paths.get(filename)));:-)
assafmo

1
Добре зіграний, і щоб врятувати наступного хлопця Googling, Pathsмабуть, 1.7+ як є FileSystems. (Dang it!)
ruffin

4
Прикро, ця відповідь не має більше голосів. Я шукав найшвидший і найпростіший спосіб отримати текстовий файл у String. Це все, і якби я не прокручував вниз і вниз і вниз, я б пропустив це. ОП має розглянути можливість прийняття цієї відповіді, щоб перемістити її до початку.
Торн

@Thorn Ця відповідь має жахливу обробку помилок. Не використовуйте цей метод у виробничому коді, а ще краще: ніколи.
xehpuk

51

Якщо вам потрібна обробка рядків (паралельна обробка), у Java 8 є чудовий API Stream.

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

Чи відбувається .parallel () після того, як ви прочитали рядки або до цього?
Іштван

Справжня робота починається з того часу, коли викликається робота терміналу збирання (...). Потік ліниво населений рядом. Перед обробкою не потрібно читати весь файл у пам'яті (наприклад, фільтрування та відображення).
Андрій N

обрізати перед вибором не порожніх ліній?
Thorbjørn Ravn Andersen

50

Цей код нормалізує розриви рядків, що може бути або не бути тим, що ви дійсно хочете робити.

Ось альтернатива, яка цього не робить, і яку (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();
    }        
}

1
Пробачте, що я відновив цей старий коментар, але ви мали на увазі передати об'єкт String під назвою "файл", чи це повинен бути об'єкт File?
Брайан Ларсон

28

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

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

@подивитися


26

Якщо це текстовий файл, чому б не використовувати apache commons-io ?

Він має такий спосіб

public static String readFileToString(File file) throws IOException

Якщо ви хочете, щоб рядки використовувались у списку

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

25

З 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

Чому, о, чому, впроваджувати нові методи, які покладаються на схему за замовчуванням у 2018 році?
mryan

2
@mryan цей метод не покладається на системну схему за замовчуванням. Він за замовчуванням UTF-8, це нормально.
leventov

@leventov ви праві! так це і Files.readAllLines! це робить API файлів не дуже відповідним старішим методам, але це на краще :)
mryan

17

Щоб прочитати файл як двійковий та перетворити його наприкінці

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

16

У Java 7 це найкращий варіант для читання файлу UTF-8:

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

Оскільки Java 7, JDK має новий java.nio.fileAPI, який надає багато ярликів, тому сторонні бібліотеки не завжди потрібні для простих операцій з файлами.


15

Java намагається бути надзвичайно загальним та гнучким у всьому, що робить. Як результат, щось, що є відносно простим мовою сценаріїв (ваш код буде замінено на " open(file).read()" в python), набагато складніше. Здається, не існує жодного коротшого способу зробити це, окрім використання зовнішньої бібліотеки (наприклад, Віллі аур Рор ). Ваші варіанти:

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

Ваша найкраща ставка, ймовірно, друга, оскільки вона має найменші залежності.


4
Дріжджі. Це змушує мову "високого" рівня приймати інше значення. Java є високим рівнем порівняно з C, але низьким порівняно з Python або Ruby
OscarRyz

3
Погодьтеся, що Java триває на абстракціях високого рівня, але коротких на зручні методи
Dónal

3
Правда, у Java існує шалена кількість способів поводження з Файлами, і багато з них здаються складними. Але це досить близько до того, що є у мовах вищого рівня:byte[] bytes = Files.readAllBytes(someFile.toPath());
Торн

11

Використання JDK 8 або вище:

не використовуються зовнішні бібліотеки

Ви можете створити новий об’єкт String із вмісту файлу (Використання класів з java.nio.fileпакету):

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

Дублікат відповіді Моріца Петерсена, який написав: String content = new String (Files.readAllBytes (Paths.get (назва файлу)), "UTF-8");
Жан-Крістоф Бланшард

8

Існує варіант цієї ж теми, який використовує цикл, а не цикл час, щоб обмежити область змінної рядка. Чи це "краще" - це питання особистого смаку.

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

3
Це змінить рядки для вибору нового рядка за замовчуванням. Це може бути бажано або ненавмисно.
Пітер Лорі

Відкотив редагування цієї відповіді, оскільки суть полягала в тому, щоб звузити область lineзмінної. Редагування заявило про це двічі, що було б помилкою компіляції.
Dan Dyer

7

Якщо у вас немає доступу до 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);
}

приклад діаграми для виклику?
Туфір

4

Гнучке рішення з використанням 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-адреси.


3

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

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.


1
Цей код може дати непередбачувані результати. Згідно документації по available()методу, немає ніякої гарантії , що кінець файлу досягається в тому випадку, якщо метод повертає 0. В цьому випадку ви могли б у кінцевому підсумку з неповним файлом. Що ще гірше, кількість дійсно прочитаних байтів може бути меншою, ніж значення, повернене available(), і в цьому випадку ви отримаєте пошкоджений вихід.
wa

3

У цьому використовується метод 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
        }
    }
}

3

Ви можете спробувати сканер і клас файлів, рішення декількох рядків

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

3

Користувач 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);
}

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

Я думаю, що це спричинило незручності при використанні кодування платформи за замовчуванням. +1 у будь-якому випадку :)
OscarRyz

7
Мені здається, що нарешті блок не знає змінних, визначених у блоці спробу. javac 1.6.0_21 кидає помилку cannot find symbol.
припинення

Ви навіть спробували власний код? Ви визначили читач у блоці спробу / лову, тому він не буде доступний в остаточному блоці.
mauron85

2

Я ще не можу коментувати інші записи, тому просто залишу її тут.

Один з найкращих відповідей тут ( https://stackoverflow.com/a/326448/1521167 ):

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

все ще є один недолік. Він завжди ставить новий рядок char в кінці рядка, що може спричинити деякі дивні помилки. Моя пропозиція - змінити його на:

    private String readFile(String pathname) throws IOException {
    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int) file.length());
    Scanner scanner = new Scanner(new BufferedReader(new FileReader(file)));
    String lineSeparator = System.getProperty("line.separator");

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

У першому випадку ви можете додати додатковий новий рядок наприкінці. у другому випадку ви можете його опустити. Тож обидва однаково неправильно. Дивіться цю статтю
Патрік Паркер

2

Після Ctrl + F'ing після сканера, я вважаю, що також слід вказати рішення Scanner. У найпростішій для читання моді це виглядає так:

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 або новішу версію (і вам справді слід), подумайте про те, щоб скористатися пробними ресурсами, щоб полегшити читання коду. Більше не все, що закриває точки, засмічує все. Але це переважно стилістичний вибір.

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

Моя пропозиція полягала б у використанні файлів # readAllBytes (Шлях), щоб схопити всі байти та подати їх у новий String (байт [] Charset) щоб отримати з нього рядок, якому ви можете довіряти. Шарсети будуть для вас значущими, тому остерігайтесь цього матеріалу зараз.

Інші дали код і речі, і я не хочу красти їхню славу. ;)



2

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

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


2

На основі відповіді @ 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()]));
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.