Эквивалент гуавы для IOUtils.toString (InputStream) - PullRequest
103 голосов
/ 15 ноября 2010

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

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

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

Ответы [ 9 ]

82 голосов
/ 15 ноября 2010

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

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();
55 голосов
/ 15 ноября 2010

Если у вас есть Readable, вы можете использовать CharStreams.toString(Readable).Таким образом, вы, вероятно, можете сделать следующее:

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

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

15 голосов
/ 23 июля 2012

ОБНОВЛЕНИЕ : Оглядываясь назад, мне не нравится мое старое решение.Кроме того, сейчас 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);
    }
15 голосов
/ 15 ноября 2010

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

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;
    }
};
12 голосов
/ 30 июля 2014

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

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

Это не «чистая» гуава, но она немного короче.

4 голосов
/ 15 ноября 2010

Основываясь на принятом ответе, вот служебный метод, который высмеивает поведение 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);
    }
}
3 голосов
/ 09 июля 2015

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

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

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

2 голосов
/ 06 августа 2013

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

Вот что я использую.

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

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));
0 голосов
/ 03 июля 2015

Для конкретного примера, вот как я могу прочитать актив текстового файла 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;
}
...