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


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

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

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

9 98

9 ответов:

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

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 чтобы сделать вашу жизнь проще, позволяя гуава обрабатывать части, которые требуют уродливый try-finally блок, чтобы убедиться, что ресурсы закрыты должным образом.

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

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

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


Edit: Feb.

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

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

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

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

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

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

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

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

EDIT: не то, что выше нуждается в InputSupplier<InputStream> как streamSupplier. Если у вас уже есть поток вы можете реализовать это достаточно легко, хотя:

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

обновление: оглядываясь назад, мне не нравится мое старое решение. Кроме того, это 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);
    }

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

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

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

на основе принятого ответа, вот утилита метод, который издевается над поведением 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);
    }
}

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

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

Использует Гуавы ресурсы, вдохновленная IOExplained.

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

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