Если у вас есть java.io.InputStream
объект, как вы должны обработать этот объект и создать String
?
Предположим, у меня есть InputStream
текст, содержащий текстовые данные, и я хочу преобразовать его в String
файл, поэтому, например, я могу записать его в файл журнала.
Какой самый простой способ взять InputStream
и преобразовать его в String
?
public String convertStreamToString(InputStream is) {
// ???
}
ByteArrayOutputStream outputBytes = new ByteArrayOutputStream();
for(byte[] b = new byte[512]; 0 < inputStream.read(b); outputBytes.write(b));
return new String(outputBytes.toByteArray(), StandardCharsets.UTF_8);
String s = Files.readString(Path.of("SomeFile.txt"));
что и язык, который никогда не будет поддерживать такие магические преобразования типов, как описанные вами.Ответы:
Хороший способ сделать это - использовать Apache Commons
IOUtils
для копированияInputStream
вStringWriter
... что-то вродеили даже
Кроме того, вы можете использовать,
ByteArrayOutputStream
если вы не хотите смешивать ваши потоки и пишущиеисточник
Обобщая другие ответы, я нашел 11 основных способов сделать это (см. Ниже). И я написал несколько тестов производительности (см. Результаты ниже):
Способы преобразования InputStream в строку:
Использование
IOUtils.toString
(Apache Utils)Использование
CharStreams
(Гуава)Использование
Scanner
(JDK)Использование Stream API (Java 8). Предупреждение . Это решение преобразует различные разрывы строк (например
\r\n
) в\n
.Использование параллельного Stream API (Java 8). Предупреждение . Это решение преобразует различные разрывы строк (например
\r\n
) в\n
.Использование
InputStreamReader
иStringBuilder
(JDK)Использование
StringWriter
иIOUtils.copy
(Apache Commons)Использование
ByteArrayOutputStream
иinputStream.read
(JDK)Использование
BufferedReader
(JDK). Предупреждение. Это решение преобразует различные разрывы строк (например\n\r
) вline.separator
системное свойство (например, в Windows в «\ r \ n»).Использование
BufferedInputStream
иByteArrayOutputStream
(JDK)Использование
inputStream.read()
иStringBuilder
(JDK). Предупреждение : это решение имеет проблемы с Unicode, например с русским текстом (работает корректно только с текстом не-Unicode)Предупреждение :
Решения 4, 5 и 9 преобразуют различные разрывы строк в один.
Решение 11 не может корректно работать с текстом Unicode
Тесты производительности
Тесты производительности для малых
String
(длина = 175), URL в github (режим = Среднее время, система = Linux, оценка 1343 является лучшим):Тесты производительности для больших
String
(длина = 50100), URL в github (режим = Среднее время, система = Linux, оценка 200,715 является лучшей):Графики (тесты производительности в зависимости от длины входного потока в системе Windows 7)
Тест производительности (среднее время) в зависимости от длины входного потока в системе Windows 7:
источник
\r\n
), в\n
которые в некоторых случаях могут быть нежелательны. Также было бы неплохо увидеть необходимую дополнительную память или, по крайней мере, давление выделения (по крайней мере, вы можете запустить JMH с-prof gc
). Для действительно классного поста было бы замечательно увидеть графики (в зависимости от длины строки в пределах одного и того же размера ввода и в зависимости от размера ввода в пределах одной и той же длины строки).reset()
в примере 11?Вот способ использования только стандартной библиотеки Java (обратите внимание, что поток не закрыт, ваш пробег может отличаться).
Я узнал этот трюк из статьи "Трюки со сканером" . Это работает потому, что Scanner перебирает токены в потоке, и в этом случае мы разделяем токены, используя «начало входной границы» (\ A), что дает нам только один токен для всего содержимого потока.
Обратите внимание: если вам нужно быть конкретным в отношении кодировки входного потока, вы можете предоставить второй аргумент
Scanner
конструктору, который указывает, какой набор символов использовать (например, «UTF-8»).Наконечник шляпы идет также к Джейкобу , который однажды указал мне на упомянутую статью.
источник
if (is == null) return "";
прямо в начале метода; Я считаю, что этот ответ необходимо обновить, чтобы лучше обрабатывать нулевые inputStreams.try(java.util.Scanner s = new java.util.Scanner(is)) { return s.useDelimiter("\\A").hasNext() ? s.next() : ""; }
Apache Commons позволяет:
Конечно, вы можете выбрать другие кодировки символов, кроме UTF-8.
Также см .: ( документация )
источник
Принимая во внимание файл, нужно сначала получить
java.io.Reader
экземпляр. Затем его можно прочитать и добавить вStringBuilder
(нам не нужно,StringBuffer
если мы не обращаемся к нему в нескольких потоках, иStringBuilder
это быстрее). Хитрость в том, что мы работаем в блоках, и поэтому не нуждаемся в других потоках буферизации. Размер блока параметризован для оптимизации производительности во время выполнения.источник
In our product, I even replaced
должно быть «мы даже заменили».Использование:
источник
readLine
читать символ за символом, чтобы искать EOL. Кроме того, если в потоке нет разрыва строки, это не имеет смысла.Если вы используете Google-Collections / Guava, вы можете сделать следующее:
Обратите внимание, что второй параметр (т. Е. Charsets.UTF_8) для объекта
InputStreamReader
необязателен, но, как правило, рекомендуется указывать кодировку, если вы ее знаете (что следует делать!)источник
Это лучшее решение на чистой Java, которое идеально подходит для Android и любой другой JVM.
Это решение работает удивительно хорошо ... оно простое, быстрое и работает с маленькими и большими потоками одинаково !! (см. контрольный показатель выше. № 8 )
источник
2*n
, где n - размер потока в соответствии сByteArrayInputStream
автоматически растущей системой.Для полноты вот решение Java 9 :
В
readAllBytes
настоящее время он находится в основной кодовой базе JDK 9, поэтому он, скорее всего, появится в релизе. Вы можете попробовать это прямо сейчас, используя сборки снимков JDK 9 .источник
byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
гдеMAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
что даетMAX_BUFFER_SIZE = 2147483639
. Google говорит, что его около 2,147 ГБ.InputStream
, а не оPath
. ОниInputStream
могут быть созданы из разных источников, а не только из файлов.byte[]
реализации , если все символы находятся в первых 256 кодовых точках. Это означает, что новая строка (byte [], "ISO-Latin-1") будет простой копией массива.Использование:
источник
BufferedInputStream
. Базовые операции чтения составляют 8192 байта за раз.BufferedInputStream
и чтение в буфер байтового массива вместо одного байта за раз. Пример: 200 мс против 60 мс при чтении файла размером 4,56 МБ.buf.toString()
.Вот самое элегантное решение на основе чистой Java (без библиотеки), которое я придумал после некоторых экспериментов:
источник
InputStream
должно быть закрыто звонящим.readLine
? если вы не используете линии как таковые, что это хорошо (кроме того, что очень медленно?)Я проверил здесь 14 различных ответов (извините, что не предоставил кредиты, но дубликатов слишком много).
Результат очень удивителен. Оказывается, что Apache IOUtils является самым медленным и
ByteArrayOutputStream
самым быстрым решением:Итак, сначала вот лучший метод:
Результаты теста 20 МБ случайных байтов за 20 циклов
Время в миллисекундах
Исходный код теста
источник
Я бы использовал некоторые трюки с Java 8.
По сути, такой же, как некоторые другие ответы, за исключением более кратких.
источник
return null
когда-либо называться? Либоbr.lines...
возврат, либо исключение.parallel()
в потоке?\r\n
закончилось бы преобразованием в\n
...System.lineSeparator()
чтобы использовать соответствующий зависимый от платформы конец строки.Я провел несколько тестов времени, потому что время имеет значение, всегда.
Я попытался получить ответ в строку 3 разными способами. (показано ниже)
Я упустил блоки try / catch для удобства чтения.
Чтобы дать контекст, это предыдущий код для всех 3 подходов:
1)
2)
3)
Итак, после запуска 500 тестов для каждого подхода с одинаковыми данными запроса / ответа, вот цифры. Опять же, это мои выводы, и ваши выводы могут не совпадать, но я написал это, чтобы дать понять другим различия в эффективности этих подходов.
Ранги:
Подход № 1
Подход № 3 - на 2,6% медленнее, чем # 1
Подход № 2 - на 4,3% медленнее, чем # 1
Любой из этих подходов является подходящим решением для получения ответа и создания из него строки.
источник
Чистое решение Java с использованием Stream s, работает с Java 8.
Как упомянуто Кристоффером Хаммарстромом ниже в другом ответе, безопаснее явно указать кодировку . Т.е. конструктор InputStreamReader может быть изменен следующим образом:
источник
Charset.forName("UTF-8")
используйтеStandardCharsets.UTF_8
(сjava.nio.charset
).Вот более или менее ответ сампата, немного приведенный в порядок и представленный в виде функции:
источник
Если вы испытываете приключения, вы можете смешать Scala и Java и получить следующее:
Смешивание Java и Scala-кода и библиотек имеет свои преимущества.
См. Полное описание здесь: идиоматический способ преобразования InputStream в строку в Scala
источник
Source.fromInputStream(...).mkString
Если вы не можете использовать Commons IO (FileUtils / IOUtils / CopyUtils), вот пример использования BufferedReader для чтения файла построчно:
Или, если вам нужна грубая скорость, я бы предложил вариант того, что предложил Пол де Вриз (в котором избегается использование StringWriter (который использует StringBuffer внутри):
источник
Это хорошо, потому что:
Как это сделать?
Для JDK 9
источник
catch (Throwable)
самом деле не должно быть пустым, если это рабочий код.Это ответ адаптирован из
org.apache.commons.io.IOUtils
исходного кода , для тех, кто хочет иметь реализацию apache, но не хочет всей библиотеки.источник
Не забудьте закрыть потоки в конце, если вы используете потоковые ридеры
РЕДАКТИРОВАТЬ: В JDK 7+, вы можете использовать конструкцию try-with-resources.
источник
iStream
действительно должен быть закрыт вызывающим, потому что создатель вызывающийiStream
. Кроме того, закрытие потоков должно выполняться вfinally
блоке или, что еще лучше, в операторе try-with-resources в Java 7. В вашем коде, когдаreadLine()
бросаетIOException
илиbuilder.append()
бросаетOutOfMemoryError
, потоки остаются открытыми.Еще один, для всех пользователей Spring:
Методы утилит in
org.springframework.util.StreamUtils
аналогичны методам inFileCopyUtils
, но по завершении они оставляют поток открытым.источник
Используйте java.io.InputStream.transferTo (OutputStream), поддерживаемый в Java 9, и ByteArrayOutputStream.toString (String), который принимает имя кодировки:
источник
Вот полный метод для преобразования
InputStream
вString
без использования какой - либо сторонней библиотеки. ИспользуйтеStringBuilder
для однопоточной среды, иначе используйтеStringBuffer
.источник
in = new InputStreamReader(inputStream)
и(char)in.read()
.Вот как это сделать, используя только JDK, используя буферы байтового массива. Вот как
IOUtils.copy()
все методы commons-io работают. Вы можете заменитьbyte[]
на,char[]
если вы копируете сReader
вместоInputStream
.источник
Пользователи Kotlin просто делают:
в то время как
является встроенным методом расширения стандартной библиотеки Kotlin.
источник
is.bufferedReader().use { it.readText() }
.Самый простой способ в JDK - использовать следующие фрагменты кода.
источник
Вот мое решение на основе Java 8 , которое использует новый Stream API для сбора всех строк из
InputStream
:источник
С точки зрения
reduce
, иconcat
это может быть выражено в Java 8 как:источник
StringBuilder
может быть более эффективным. Я проверю, но моей целью было показать более функциональный подход с неизменяемымString
.Ответ JDK 7/8, который закрывает поток и все еще выбрасывает IOException:
источник