Эквивалент Guava для IOUtils.toString(InputStream)

Apache Commons IO имеет приятный удобный метод IOUtils.toString(), чтобы прочитать InputStream для строки.

Так как я пытаюсь отойти от Apache Commons и Guava: есть ли эквивалент в Guava? Я просмотрел все классы в пакете com.google.common.io, и я не мог найти ничего почти простого.

Изменить: Я понимаю и ценю проблемы с кодировками. Так получилось, что я знаю, что все мои источники находятся в ASCII (да, ASCII, а не ANSI и т.д.), Поэтому в этом случае кодирование не является проблемой для меня.

Ответ 1

В своем комментарии к Calum вы сказали, что собираетесь использовать

CharStreams.toString(new InputStreamReader(supplier.get(), Charsets.UTF_8))

Этот код проблематичен, потому что перегрузка CharStreams.toString(Readable) гласит:

Не закрывает Readable.

Это означает, что ваш InputStreamReader и по расширению InputStream, возвращаемый supplier.get(), не будет закрыт после завершения этого кода.

Если, с другой стороны, вы воспользуетесь тем фактом, что у вас уже есть InputSupplier<InputStream> и используется перегрузка CharStreams.toString(InputSupplier<R extends Readable & Closeable>), метод toString будет обрабатывать как создание, так и закрытие Reader для вас.

Это именно то, что предложил Джон Скит, за исключением того, что на самом деле нет перегрузки CharStreams.newReaderSupplier, которая принимает вход InputStream... вы должны дать ему InputSupplier:

InputSupplier<? extends InputStream> supplier = ...
InputSupplier<InputStreamReader> readerSupplier = 
    CharStreams.newReaderSupplier(supplier, Charsets.UTF_8);

// InputStream and Reader are both created and closed in this single call
String text = CharStreams.toString(readerSupplier);

Точка InputSupplier состоит в том, чтобы упростить вашу жизнь, разрешив Guava обрабатывать части, для которых требуется уродливый блок try-finally, чтобы обеспечить правильное закрытие ресурсов.

Изменить: Лично я нахожу следующее (как я его на самом деле написал, просто отменил шаги в коде выше)

String text = CharStreams.toString(
    CharStreams.newReaderSupplier(supplier, Charsets.UTF_8));

будет гораздо менее подробным, чем это:

String text;
InputStreamReader reader = new InputStreamReader(supplier.get(), 
    Charsets.UTF_8);
boolean threw = true;
try {
  text = CharStreams.toString(reader);
  threw = false;
}
finally {
  Closeables.close(reader, threw);
}

Что более или менее то, что вам нужно было бы написать, чтобы правильно справляться с этим.


Изменить: февраль 2014

InputSupplier и OutputSupplier, а методы, которые их используют, устарели в Guava 16.0. Их замены: ByteSource, CharSource, ByteSink и CharSink. Учитывая ByteSource, вы можете теперь получить его содержимое как String следующим образом:

ByteSource source = ...
String text = source.asCharSource(Charsets.UTF_8).read();

Ответ 2

Если у вас есть Readable, вы можете использовать CharStreams.toString(Readable). Поэтому вы можете сделать следующее:

String string = CharStreams.toString( new InputStreamReader( inputStream, "UTF-8" ) );

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

Ответ 3

Почти. Вы можете использовать что-то вроде этого:

InputSupplier<InputStreamReader> readerSupplier = CharStreams.newReaderSupplier
    (streamSupplier, Charsets.UTF_8);
String text = CharStreams.toString(readerSupplier);

Лично я не думаю, что IOUtils.toString(InputStream) является "приятным", потому что он всегда использует стандартную кодировку платформы, которая почти никогда не нужна вам. Там перегрузка, которая берет имя кодировки, но использует имена, не является отличной идеей IMO. Вот почему мне нравится Charsets.*.

РЕДАКТИРОВАНИЕ: не то, что для этого требуется InputSupplier<InputStream> как streamSupplier. Если у вас уже есть поток, вы можете реализовать это достаточно легко, хотя:

InputSupplier<InputStream> supplier = new InputSupplier<InputStream>() {
    @Override public InputStream getInput() {
        return stream;
    }
};

Ответ 4

ОБНОВЛЕНИЕ. Оглядываясь назад, мне не нравится мое старое решение. Кроме того, сейчас 2013 год, и теперь для Java7 есть лучшие альтернативы. Итак, вот что я сейчас использую:

InputStream fis = ...;
String text;
try (  InputStreamReader reader = new InputStreamReader(fis, Charsets.UTF_8)){
        text = CharStreams.toString(reader);
}

или если с InputSupplier

InputSupplier<InputStreamReader> spl = ...
try (  InputStreamReader reader = spl.getInput()){
        text = CharStreams.toString(reader);
    }

Ответ 5

Другой вариант - прочитать байты из Stream и создать из них строку:

new String(ByteStreams.toByteArray(inputStream))
new String(ByteStreams.toByteArray(inputStream), Charsets.UTF_8)

Это не "чистый" Гуава, но он немного короче.

Ответ 6

В соответствии с принятым ответом, это утилитный метод, который издевается над поведением IOUtils.toString() (и перегруженной версии с кодировкой). Эта версия должна быть безопасной, не так ли?

public static String toString(final InputStream is) throws IOException{
    return toString(is, Charsets.UTF_8);
}


public static String toString(final InputStream is, final Charset cs)
throws IOException{
    Closeable closeMe = is;
    try{
        final InputStreamReader isr = new InputStreamReader(is, cs);
        closeMe = isr;
        return CharStreams.toString(isr);
    } finally{
        Closeables.closeQuietly(closeMe);
    }
}

Ответ 7

В случае, когда поток ввода поступает из ресурса classpath, существует гораздо более короткое решение для автозаполнения:

URL resource = classLoader.getResource(path);
byte[] bytes = Resources.toByteArray(resource);
String text = Resources.toString(resource, StandardCharsets.UTF_8);

Использует Guava Resources, вдохновленный IOExplained.

Ответ 8

EDIT (2015): Okio - лучшая абстракция и инструменты для ввода-вывода в Java/Android, о котором я знаю. Я использую его все время.

FWIW здесь, что я использую.

Если у меня уже есть поток в руке, то:

final InputStream stream; // this is received from somewhere
String s = CharStreams.toString(CharStreams.newReaderSupplier(new InputSupplier<InputStream>() {
    public InputStream getInput() throws IOException {
        return stream;
    }
}, Charsets.UTF_8));

Если я создаю поток:

String s = CharStreams.toString(CharStreams.newReaderSupplier(new InputSupplier<InputStream>() {
    public InputStream getInput() throws IOException {
        return <expression creating the stream>;
    }
}, Charsets.UTF_8));

В качестве конкретного примера я могу прочитать текстовый файл Android так:

final Context context = ...;
String s = CharStreams.toString(CharStreams.newReaderSupplier(new InputSupplier<InputStream>() {
    public InputStream getInput() throws IOException {
        return context.getAssets().open("my_asset.txt");
    }
}, Charsets.UTF_8));

Ответ 9

Для конкретного примера, здесь, как я могу прочитать текстовый файл Android:

public static String getAssetContent(Context context, String file) {
    InputStreamReader reader = null;
    InputStream stream = null;
    String output = "";

    try {
        stream = context.getAssets().open(file);
        reader = new InputStreamReader(stream, Charsets.UTF_8);
        output = CharStreams.toString(reader);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    return output;
}