Я уже некоторое время использую идиому ниже. И он кажется самым распространенным, по крайней мере, на тех сайтах, которые я посещал.
Есть ли лучший / другой способ прочитать файл в строке в 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();
}
}
помните, что не гарантируется, что разделитель строк в файле не является таким же, как системный разделитель строк.
В приведенном выше коде есть ошибка добавления дополнительного символа новой строки в последнюю строку. Это должно быть что-то вроде следующего if (line = reader.readLine ())! = Null) {stringBuilder.append (line); } пока (строка = reader.readLine ())! = ноль) {stringBuilder.append (ls); stringBuilder.append (строка); }
Java 7 представляет byte[] Files.readAllBytes(file); Тем, кто предлагает решение «однострочного» сканера: не нужно ли его закрывать?
@OscarRyz Самым большим изменением для меня является то, что NIO позволяет вам прослушивать множество портов, не выделяя для каждого по потоку. Не проблема, если вы не хотите отправить пакет на каждую машину в сетевом адресном пространстве класса B (65 тыс. Адресов), чтобы увидеть, что существует, в Windows заканчиваются потоки примерно на 20 тыс. сеть класса A / B, до NIO было тяжело).
Если вы видите реализацию Files.readAllBytes (), вы заметите, что она использует закрываемый канал. Так что не нужно закрывать его явно.
С появлением Groovy вы можете читать файл таким образом: return new File (file) .text ()
Связывание еще одной ссылки на StackOverflow, поиск которой хорошо объяснен: stackoverflow.com/questions/14169661/…
@Deep Последняя строка в текстовом файле обычно заканчивается строкой, поэтому то, что вы описываете как ошибка, не является ошибкой, и в вашем коде есть ошибка удаления все ограничителей строки.




Если вы хотите использовать внешнюю библиотеку, попробуйте 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.
Это в классе org.apache.commons.io.FileUtils
Я тоже использую FileUtils, но мне интересно, что лучше между использованием FileUtils или принятым ответом nio?
@Guillaume: Самый большой вопрос заключается в том, комфортно ли вам иметь зависимость от сторонней библиотеки. Если в вашем проекте есть Commons IO или Гуава, используйте их (просто для простоты кода; иначе, скорее всего, не будет заметной разницы).
Java пытается быть чрезвычайно универсальной и гибкой во всем, что она делает. В результате что-то, что относительно просто на языке сценариев (ваш код был бы заменен на «open(file).read()» в python), намного сложнее. Кажется, нет более короткого способа сделать это, кроме использования внешней библиотеки (например, упомянутой Вилли аус Рор). Ваши варианты:
Лучше всего, вероятно, будет второй вариант, так как у него меньше всего зависимостей.
Ага. Это заставляет язык «высокого» уровня принимать другое значение. Java имеет высокий уровень по сравнению с C, но низкий по сравнению с Python или Ruby.
Согласитесь, что в Java много абстракций высокого уровня, но мало удобных методов.
Действительно, в Java есть безумное количество способов работы с файлами, и многие из них кажутся сложными. Но это довольно близко к тому, что мы имеем в языках более высокого уровня: byte[] bytes = Files.readAllBytes(someFile.toPath());
В 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 безопасно упрощает код, а старый ответ, в котором использовался сопоставленный байтовый буфер, предотвращал удаление файла, который был прочитан, до тех пор, пока сопоставленный буфер не будет собран сборщиком мусора. Вы можете просмотреть старую версию, перейдя по ссылке «отредактировано» в этом ответе.
Довольно интересно. Что означает канал. Я знаю, что это во избежание блокировки «нити»? Они могут быть двунаправленными (или я так понял) Но, проще говоря, что это такое? Не могли бы вы подробнее рассказать?
Во многих отношениях ReadableByteChannel похож на InputStream, а WritableByteChannel похож на OutputStream. Многие конкретные каналы реализуют оба этих интерфейса, поэтому один объект является двунаправленным. Некоторые каналы (SocketChannel) поддерживают неблокирующий ввод-вывод, но это верно не для всех каналов.
Знаете ли вы, насколько эффективна эта идиома с точки зрения времени и памяти, или можете хотя бы оценить? Это красивая идиома!
Технически говоря, это O (n) во времени и пространстве. Качественно, из-за требования неизменяемости строк, это довольно сложно для памяти; временно есть две копии данных char в памяти плюс место для закодированных байтов. Предполагая некоторую однобайтовую кодировку, потребуется (временно) 5 байтов памяти для каждого символа в файле. Поскольку вопрос конкретно касается String, это то, что я показываю, но если вы можете работать с CharBuffer, возвращаемым методом «decode», требования к памяти намного меньше. С точки зрения времени, я не думаю, что вы найдете что-то более быстрое в основных библиотеках Java.
Возможная опечатка? У NIO есть класс Charset (не CharSet), называемый java.nio.charset.Charset. Это то, чем должен был быть CharSet?
Примечание: немного поработав этот код, я обнаружил, что вы не можете надежно удалить файл сразу после его прочтения с помощью этого метода, что в некоторых случаях может быть не проблемой, но не для меня. Может быть в связи с этим вопросом: bugs.sun.com/bugdatabase/view_bug.do?bug_id=4715154? В конце концов я согласился с предложением Джона Скита, который не страдает этой ошибкой. В любом случае, я просто хотел дать информацию другим людям, на всякий случай ...
@ Себастьен Нуссбаумер: Я тоже столкнулся с этой проблемой. Удивительно, что ошибка помечена как «Не исправить». По сути, это означает, что FileChannel#map вообще непригоден для использования.
@ Себастьен Нуссбаумер: Ошибка была удалена из базы данных ошибок Oracle / Sun: «Эта ошибка недоступна». Google кэшировал сайт по адресу webcache.googleusercontent.com/search?q=cache:bugs.sun.com/…
Я попытался прочитать exe-файл с помощью этого метода с кодировкой по умолчанию, добавить в него некоторые данные и снова сделать его exe, но он испортил exe, есть мысли?
@smilepleeeaz То, что вы описываете, не имеет смысла. EXE-файлы не являются текстовыми. И у них есть четко определенная структура. Сначала вы уничтожаете содержимое файла, декодируя его как текст, затем вы разрушаете структуру, добавляя к ней текст. Как это могло не повредить EXE?
Меня действительно не волнует кодировка, могу ли я просто использовать Charset.defaultCharset() вместо того, чтобы принимать аргумент?
@yannbane Если вы уверены, что файл всегда будет кодироваться с использованием набора символов платформы по умолчанию, да, вы можете это сделать. Если есть несоответствие, вы позаботитесь о кодировке.
Начиная с Java 8, кодировку можно не указывать по умолчанию для использования UTF-8. Таким образом, чтение всех строк становится Files.readAllLines(Paths.get("/your/path/to/file"));
В чем преимущество этого: encoding.decode (ByteBuffer.wrap (закодировано)). ToString (); по сравнению с этим: новая строка (закодированная, кодировка);
@Trejkaz Нет ни одного! Я думаю, что это было просто перенесено из исходного кода, в котором использовался сопоставленный буфер. Спасибо, что указали на это.
magnifico, решение java 8, а также
В моем случае я делал это статическим методом, поэтому это выглядело так: URL url = NarrationDataProvider.class.getResource(filePath); byte[] encoded = Files.readAllBytes(Paths.get(url.toURI())); return new String(encoded, StandardCharsets.US_ASCII);
Применимо ли что-нибудь из этого к компиляторам?
Я попытался использовать метод readFile этого ответа, но не могу найти, где находится класс Files. Я использую JDK 1.7.0_79
К сожалению, этот фрагмент кода не работает в Android.
@MiralSarwar "не работает" - не совсем точное описание проблемы. Что случается? О каком из четырех фрагментов кода вы говорите?
java.nio.file.Files или java.nio.file.Paths не поддерживаются в Android.
@MiralSarwar Ну, этот вопрос касается Java, а не Android, но версия Java 6 (которую можно просмотреть в истории редактирования) будет работать на Android.
Раздел «Кодировка символов» должен быть закрыт теперь, когда вы удалили все другие ссылки на Apache Commons IO.
@Powerlord Этот раздел не имеет ничего общего с Apache Commons IO. Это полностью относится к ядру Java NIO.
Если вы ищете альтернативу, не использующую стороннюю библиотеку (например, Ввод / вывод общего пользования), вы можете использовать класс Сканер:
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();
}
}
Думаю, это лучший способ. Проверить java.sun.com/docs/books/tutorial/essential/io/scanning.html
Конструктор Scanner, который принимает String, обрабатывает строку не как имя файла для чтения, а как текст для сканирования. Я все время делаю эту ошибку. : - /
@ Алан, хороший улов. Я немного отредактировал ответ Дона, чтобы исправить это (надеюсь).
fileContents.append (scanner.nextLine ()). append (lineSeparator);
Измените оператор инициализации на Scanner scanner = new Scanner((Readable) new BufferedReader(new FileReader(file)));. В противном случае вы можете захватить только часть файла.
Этот метод добавит дополнительный разделитель в конец файла, когда его нет в фактическом файле (для файла, который заканчивается без новой строки).
@WeiYang Почему?
Этот код нормализует разрывы строк, что может быть, а может и не быть тем, что вы действительно хотите делать.
Вот альтернатива, которая этого не делает и которая (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();
}
}
Простите меня за то, что возродил такой старый комментарий, но вы хотели передать объект String с именем "file" или это должен быть объект File?
Отличный ответ. +1. Но этому ответу 12 лет. В Java теперь есть возможность попробовать ресурсы.
Существует вариант той же темы, в которой вместо цикла while используется цикл for, чтобы ограничить область действия строковой переменной. «Лучше» ли это - дело личного вкуса.
for(String line = reader.readLine(); line != null; line = reader.readLine()) {
stringBuilder.append(line);
stringBuilder.append(ls);
}
Это изменит символы новой строки на выбор по умолчанию. Это может быть желательно или непреднамеренно.
Откатил редактирование этого ответа, потому что цель заключалась в том, чтобы сузить область действия переменной line. Редакция объявила это дважды, что было бы ошибкой компиляции.
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 все равно :)
Мне кажется, что блок finally не знает переменных, определенных в блоке try. javac 1.6.0_21 выдает ошибку cannot find symbol.
Вы хоть раз пробовали свой собственный код? Вы определили читателя в блоке try / catch, поэтому он не будет доступен в блоке finally.
Гуава имеет метод, аналогичный методу из Commons IOUtils, который упомянул Вилли аус Рор:
import com.google.common.base.Charsets;
import com.google.common.io.Files;
// ...
String text = Files.toString(new File(path), Charsets.UTF_8);
ИЗМЕНИТЬ PiggyPigletFiles#toString устарел и подлежит удалению в октябре 2019 года. Вместо этого используйте
Files.asCharSource(new File(path), StandardCharsets.UTF_8).read();
РЕДАКТИРОВАТЬ Оскар Рейес
Это (упрощенный) базовый код указанной библиотеки:
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.
Этот код имеет преобразование от long к int, что может вызвать сумасшедшее поведение с большими файлами. Есть лишние пробелы и где вы закрываете поток ввода?
@ M-T-A: поток является закрыт, обратите внимание на использование Closer в CharSource. Код в ответе не является фактическим текущим исходным кодом Guava.
Чтобы прочитать файл как двоичный и преобразовать в конце
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();
}
}
Очень простое решение, основанное на 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.
Источник: Блог Пэта Нимейера
\\ A работает, потому что нет "другого начала файла", поэтому вы фактически читаете последний токен ... который также является первым. Никогда не пробовал с \\ Z. Также обратите внимание, что вы можете читать все, что доступно для чтения, например, Files, InputStreams, каналы ... Иногда я использую этот код для чтения из окна отображения eclipse, когда я не уверен, читаю ли я тот или иной файл .. .да, путь к классам меня смущает.
Как плакат, я могу сказать, что действительно не знаю, правильно ли закрыт файл и когда ... Я никогда не пишу его в производственном коде, я использую его только для тестов или отладки.
Я думаю, он имеет ограничение в 1024 символа
Сканер реализует Closeable (он вызывает close для источника), поэтому, хотя он элегантен, он не должен быть однострочным. Размер буфера по умолчанию - 1024, но Scanner при необходимости увеличит его размер (см. Scanner # makeSpace ())
Этот не подходит для пустых файлов с java.util.NoSuchElementException.
Это решение позволяет читать файлы из потоков, поэтому вы можете читать, например, ресурсы пути к классам. Широко предлагаемое решение Files.readAllBytes(Paths.get(path)) не работает, например, в среде JEE.
Кроме того, не забудьте вызвать trim() в результирующей строке, если вы не хотите, чтобы \r\n был добавлен в конец.
@SpaceTrucker это можно исправить, используя sc.findWithinHorizon("(?s).*", 0) вместо .useDelimiter("\\A").next(). Затем он будет соответствовать всему (возможно, пустому) файлу вместо поиска разделителя.
@VladimirSosnin зависит от типа ресурса classpath и доступных реализаций файловой системы. Для хранения файлов и модулей Files.readAllBytes(Paths.get(url.toURI())) работает "из коробки", тогда как для записей jar вам нужно будет создать ZipFileSystem один раз вручную в начале вашего приложения. Для других, специальных конструкций ваш контейнер должен предоставлять необходимую файловую систему, что действительно не гарантируется. Но начиная с Java 9, вы можете вызывать readAllBytes() прямо на InputStream.
Если это текстовый файл, почему бы не использовать Apache Commons-io?
Он имеет следующий метод
public static String readFileToString(File file) throws IOException
Если вы хотите, чтобы строки в виде списка использовали
public static List<String> readLines(File file) throws IOException
Здесь используется метод 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
}
}
}
Гибкое решение с использованием 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-адреса.
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 "";
}
Или еще проще: new String(Files.readAllBytes(FileSystems.getDefault().getPath( filename)));
или new String(Files.readAllBytes(Paths.get(filename))); :-)
Хорошо сыграно, и, чтобы спасти следующего парня из Google, Paths, по-видимому, 1.7+, как FileSystems. (Черт возьми!)
Жаль, что за этот ответ не набралось больше голосов. Я искал самый быстрый и простой способ превратить текстовый файл в строку. Вот и все, и если бы я не прокручивал вниз и вниз и вниз, я бы это пропустил. OP должен рассмотреть возможность принятия этого ответа, чтобы переместить его наверх.
@Thorn В этом ответе ужасная обработка ошибок. Не используйте этот метод в производственном коде, или лучше: никогда.
Имейте в виду, что при использовании 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.
Этот код может дать непредсказуемые результаты. Согласно документация метода available(), нет гарантии, что конец файла будет достигнут в случае, если метод вернет 0. В этом случае вы можете получить неполный файл. Что еще хуже, количество фактически прочитанных байтов может быть меньше, чем значение, возвращаемое available(), и в этом случае вы получите искаженный вывод.
Я пока не могу комментировать другие записи, поэтому оставлю это здесь.
Один из лучших ответов здесь (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();
}
}
еще есть один недостаток. Он всегда помещает символ новой строки в конец строки, что может вызвать некоторые странные ошибки. Я предлагаю изменить его на:
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();
}
}
В первом случае вы могли бы добавить в конец дополнительный перевод строки. во втором случае вы можете пропустить один. Так что оба одинаково неправы. См. эта статья
Если вам нужна обработка строк (параллельная обработка), в 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, которые можно загрузить с Страница загрузки Oracle Java SE 8.
Еще один пример лайнера
String out = String.join("\n", Files.readAllLines(Paths.get("file.txt")));
Выполняется ли .parallel () после того, как вы прочитаете строки или до этого?
Настоящая работа начинается с вызова терминальной операции collect (...). Поток лениво заполняется построчно. Нет необходимости читать весь файл в памяти перед обработкой (например, фильтрацией и отображением).
обрезать перед выбором непустых строк?
Если у вас нет доступа к классу 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);
}
пример кодировки для вызова?
После нажатия Ctrl + F после Scanner, я думаю, что решение 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 или новее (а вам действительно стоит), подумайте об использовании try-with-resources, чтобы упростить чтение кода. Больше никаких беспорядков, засоряющих все вокруг. Но я думаю, это в основном стилистический выбор.
Я публикую это в основном для завершения, поскольку, если вам нужно делать это много, в java.nio.file.Files должны быть вещи, которые должны выполнять эту работу лучше.
Я предлагаю использовать Файлы # readAllBytes (Путь), чтобы захватить все байты и передать их новому Строка (byte [] Charset), чтобы получить из него строку, которой вы можете доверять. Кодировки будут иметь значение для вас в течение всей вашей жизни, так что остерегайтесь этого сейчас.
Другие дали код и прочее, и я не хочу украсть их славу. ;)
В Java 7 я предпочитаю читать файл UTF-8:
String content = new String(Files.readAllBytes(Paths.get(filename)), "UTF-8");
Начиная с Java 7, JDK имеет новый API java.nio.file, который предоставляет множество ярлыков, поэтому сторонние библиотеки не всегда требуются для простых операций с файлами.
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 вы можете сделать это таким образом.
Это следует принять как ответ - одна строка, никаких внешних библиотек.
Это добавило символ новой строки в конце, даже если его не было в файле
в java 8 есть новый класс
java.util.stream.Stream
Поток представляет собой последовательность элементов и поддерживает различные типы операций для выполнения вычислений над этими элементами.
Подробнее об этом:
Вот пример:
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;
public Class ReadFile{
public static String readFile(String filePath) {
StringBuilder stringBuilder = new StringBuilder();
String ls = System.getProperty("line.separator");
try {
try (Stream<String> lines = Files.lines(Paths.get(filePath), StandardCharsets.UTF_8)) {
for (String line : (Iterable<String>) lines::iterator) {
stringBuilder.append(line);
stringBuilder.append(ls);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return stringBuilder.toString();
}
}
Используя эта библиотека, это одна строка:
String data = IO.from(new File("data.txt")).toString();
если не учитываются строки внутри библиотеки.
Используйте код:
File file = new File("input.txt");
BufferedInputStream bin = new BufferedInputStream(new FileInputStream(
file));
byte[] buffer = new byte[(int) file.length()];
bin.read(buffer);
String fileStr = new String(buffer);
fileStr содержит вывод в виде строки.
Вы можете попробовать класс Scanner и File, решение из нескольких строк
try
{
String content = new Scanner(new File("file.txt")).useDelimiter("\\Z").next();
System.out.println(content);
}
catch(FileNotFoundException e)
{
System.out.println("not found!");
}
Также, если ваш файл находится внутри банки, вы также можете использовать это:
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");
В одной строке (Java 8), если у вас есть Reader:
String sMessage = String.join("\n", reader.lines().collect(Collectors.toList()));
Основываясь на ответе @ 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()]));
}
Собрал все возможные способы чтения файла в виде строки с диска или сети.
Гуава: 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();
}
}
@видеть
внешние библиотеки не используются
Вы можете создать новый объект 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 (filename)), «UTF-8»);
Начиная с 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 этот метод не полагается на системную кодировку по умолчанию. По умолчанию используется UTF-8, это нормально.
@leventov ты прав! как и Files.readAllLines! что делает API файлов не очень совместимым со старыми методами, но это к лучшему :)
Пользователь 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);
}
Может ли кто-нибудь очень просто объяснить мне, что с NIO? Каждый раз, когда читаю об этом, я теряюсь в n-м упоминании канала :(