Pytanie Odczytaj / przekonwertuj parametr InputStream na ciąg


Jeśli masz java.io.InputStream obiekt, jak powinieneś przetwarzać ten obiekt i tworzyć String?


Załóżmy, że mam InputStream zawiera dane tekstowe i chcę przekonwertować je na String, więc na przykład mogę to zapisać w pliku dziennika.

Jaki jest najłatwiejszy sposób na zrobienie tego InputStream i przekonwertuj go na String?

public String convertStreamToString(InputStream is) { 
    // ???
}

3267
2017-11-21 16:47


pochodzenie


Chłopcze, jestem absolutnie zakochany w Javie, ale to pytanie pojawia się tak często, że można by pomyśleć, że łańcuchy strumieni są dość trudne i czynią pomocników w tworzeniu różnych kombinacji lub przemyślenia całej sprawy. - Bill K
Odpowiedzi na to pytanie działają tylko wtedy, gdy chcesz przeczytać zawartość strumienia całkowicie (dopóki nie zostanie zamknięte). Ponieważ nie zawsze jest to zamierzone (żądania HTTP z podtrzymującym połączenie nie zostaną zamknięte), te wywołania metody blokują (nie dając ci zawartości). - f1sh
ty potrzeba znać i określać kodowanie znaków dla strumienia lub ciebie będzie mieć błędy kodowania znaków, ponieważ będziesz używać losowo wybranego kodowania w zależności od tego, która maszyna / system operacyjny / platforma lub jej wersja jest uruchamiana. To znaczy, zrób nie użyj metod, które zależą od domyślnego kodowania platformy. - Christoffer Hammarström
Aby dobrze się bawić z moim własnym komentarzem sprzed 9 lat, w dzisiejszych czasach używam "String s = new File" ("SomeFile.txt") Groovy. "Text", aby przeczytać cały plik naraz i działa świetnie. Cieszę się, że używam groovy do mojego nieprodukcyjnego (skryptowego) kodu i - szczerze mówiąc zmuszanie cię do zajmowania się kodowaniem i niezwykle długimi plikami tak, jak robi to java, jest dobrym pomysłem na kod produkcyjny, więc działa to w tym celu, Groovy pracuje dla szybkich skryptów, których java nie jest świetny w - Wystarczy użyć odpowiedniego narzędzia do pracy i to wszystko działa. - Bill K
Upraszczając: 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); - Felypp Oliveira


Odpowiedzi:


Dobrym sposobem na to jest użycie Apache commons  IOUtils skopiować InputStream do a StringWriter... coś jak

StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, encoding);
String theString = writer.toString();

lub nawet

// NB: does not close inputStream, you'll have to use try-with-resources for that
String theString = IOUtils.toString(inputStream, encoding); 

Ewentualnie możesz użyć ByteArrayOutputStream jeśli nie chcesz mieszać swoich strumieni i pisarzy


2048
2017-11-21 16:54



znalazłem wyjątek filenotfound podczas gdy próbuję odczytać nazwę pliku z "До_свидания" nazwa pliku (język rosyjski) próbuję z FileInputstream, ale nie kabel do odczytu tej nazwy pliku z sdcard. - Bhanu Sharma
Dla programistów Androida, wygląda na to, że Android nie jest wyposażony w IOUtils z Apache. Możesz więc rozważyć odnoszenie się do innych odpowiedzi. - Chris.Zou
Pracuję w środowisku o ograniczonym zasięgu, więc rozwiązanie @PavelRepin poniżej, używając bibliotek java io / util, ma więcej sensu. - James
Jest to niezwykle stare pytanie w tej kwestii (zostało zadane w 2008 roku). Warto poświęcić czas na przeczytanie bardziej nowoczesnych odpowiedzi. Niektóre używają połączeń natywnych z biblioteki Java 8. - Shadoninja
Ta odpowiedź jest mocno przestarzała i należy ją oznaczyć jako taką (niestety nie jest to możliwe). - codepleb


Oto sposób korzystania tylko ze standardowej biblioteki Java (zauważ, że strumień nie jest zamknięty, YMMV).

static String convertStreamToString(java.io.InputStream is) {
    java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
    return s.hasNext() ? s.next() : "";
}

Nauczyłem się tej sztuczki od "Głupie sztuczki ze skanera" artykuł. Powodem, dla którego to działa, jest ponieważ Skaner Iteruje nad żetonami w strumieniu, w tym przypadku oddzielamy tokeny za pomocą "początku granicy wejściowej" (\ A), co daje nam tylko jeden token dla całej zawartości strumienia.

Uwaga: jeśli potrzebujesz specyfiki kodowania strumienia wejściowego, możesz podać drugi argument Scanner konstruktor, który wskazuje, jakiego zestawu znaków użyć (np. "UTF-8").

Końcówka kapelusza również trafia Jakub, który raz wskazał mi ten artykuł.

EDYTOWANE: Dzięki sugestii od Patrick, sprawił, że funkcja była bardziej niezawodna podczas obsługi pustego strumienia wejściowego. Jeszcze jedna edycja: nixed try / catch, sposób Patricka jest bardziej lakoniczny.


2093
2018-03-26 20:40



Dzięki, dla mojej wersji dodałem ostatni blok, który zamyka strumień wejściowy, więc użytkownik nie musi tego robić, odkąd skończyłeś czytać dane wejściowe. Znacznie upraszcza kod wywołujący.
@PavelRepin @Patrick w moim przypadku pusty inputStream spowodował NPE podczas budowy skanera. Musiałem dodać if (is == null) return ""; tuż na początku metody; Wierzę, że ta odpowiedź musi zostać zaktualizowana, aby lepiej obsłużyć null inputStreams. - CFL_Jeff
W przypadku języka Java 7 można zamknąć w trybie próbnym: try(java.util.Scanner s = new java.util.Scanner(is)) { return s.useDelimiter("\\A").hasNext() ? s.next() : ""; } - earcam
Niestety to rozwiązanie wydaje się gubić wyjątki rzucane w mojej implementacji strumienia bazowego. - Taig
FYI, hasNext bloki na wejściach konsolowych (patrz tutaj). (Właśnie wpadł na ten problem już teraz.) To rozwiązanie działa dobrze inaczej ... tylko heads up. - Ryan


Podsumowując inne odpowiedzi znalazłem 11 głównych sposobów, aby to zrobić (patrz poniżej). Napisałem kilka testów wydajności (zobacz wyniki poniżej):

Sposoby konwersji obiektu InputStream na ciąg:

  1. Za pomocą IOUtils.toString (Apache Utils)

    String result = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
    
  2. Za pomocą CharStreams (Guava)

    String result = CharStreams.toString(new InputStreamReader(
          inputStream, Charsets.UTF_8));
    
  3. Za pomocą Scanner (JDK)

    Scanner s = new Scanner(inputStream).useDelimiter("\\A");
    String result = s.hasNext() ? s.next() : "";
    
  4. Za pomocą Stream API (Java 8). Ostrzeżenie: To rozwiązanie konwertuje różne podziały wierszy (np \r\n) do \n.

    String result = new BufferedReader(new InputStreamReader(inputStream))
      .lines().collect(Collectors.joining("\n"));
    
  5. Za pomocą równoległy Stream API (Java 8). Ostrzeżenie: To rozwiązanie konwertuje różne podziały wierszy (np \r\n) do \n.

    String result = new BufferedReader(new InputStreamReader(inputStream)).lines()
       .parallel().collect(Collectors.joining("\n"));
    
  6. Za pomocą InputStreamReader i StringBuilder (JDK)

    final int bufferSize = 1024;
    final char[] buffer = new char[bufferSize];
    final StringBuilder out = new StringBuilder();
    Reader in = new InputStreamReader(inputStream, "UTF-8");
    for (; ; ) {
        int rsz = in.read(buffer, 0, buffer.length);
        if (rsz < 0)
            break;
        out.append(buffer, 0, rsz);
    }
    return out.toString();
    
  7. Za pomocą StringWriter i IOUtils.copy (Apache Commons)

    StringWriter writer = new StringWriter();
    IOUtils.copy(inputStream, writer, "UTF-8");
    return writer.toString();
    
  8. Za pomocą ByteArrayOutputStream i inputStream.read (JDK)

    ByteArrayOutputStream result = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int length;
    while ((length = inputStream.read(buffer)) != -1) {
        result.write(buffer, 0, length);
    }
    // StandardCharsets.UTF_8.name() > JDK 7
    return result.toString("UTF-8");
    
  9. Za pomocą BufferedReader (JDK). Ostrzeżenie: To rozwiązanie konwertuje różne podziały wierszy (np \n\r) do line.separator właściwość systemowa (na przykład w systemie Windows do "\ r \ n").

    String newLine = System.getProperty("line.separator");
    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
    StringBuilder result = new StringBuilder();
    String line; boolean flag = false;
    while ((line = reader.readLine()) != null) {
        result.append(flag? newLine: "").append(line);
        flag = true;
    }
    return result.toString();
    
  10. Za pomocą BufferedInputStream i ByteArrayOutputStream (JDK)

    BufferedInputStream bis = new BufferedInputStream(inputStream);
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    int result = bis.read();
    while(result != -1) {
        buf.write((byte) result);
        result = bis.read();
    }
    // StandardCharsets.UTF_8.name() > JDK 7
    return buf.toString("UTF-8");
    
  11. Za pomocą inputStream.read() i StringBuilder (JDK). Ostrzeżenie: To rozwiązanie ma problemy z Unicode, na przykład z rosyjskim tekstem (działa poprawnie tylko z tekstem nieobsługującym kodu Unicode)

    int ch;
    StringBuilder sb = new StringBuilder();
    while((ch = inputStream.read()) != -1)
        sb.append((char)ch);
    reset();
    return sb.toString();
    

Ostrzeżenie:

  1. Rozwiązania 4, 5 i 9 konwertują różne podziały wierszy na jeden.

  2. Rozwiązanie 11 nie działa poprawnie z tekstem Unicode

Testy wydajności

Testy wydajności dla małych String (długość = 175), adres URL w github (mode = średni czas, system = Linux, wynik 1 343 jest najlepszy):

              Benchmark                         Mode  Cnt   Score   Error  Units
 8. ByteArrayOutputStream and read (JDK)        avgt   10   1,343 ± 0,028  us/op
 6. InputStreamReader and StringBuilder (JDK)   avgt   10   6,980 ± 0,404  us/op
10. BufferedInputStream, ByteArrayOutputStream  avgt   10   7,437 ± 0,735  us/op
11. InputStream.read() and StringBuilder (JDK)  avgt   10   8,977 ± 0,328  us/op
 7. StringWriter and IOUtils.copy (Apache)      avgt   10  10,613 ± 0,599  us/op
 1. IOUtils.toString (Apache Utils)             avgt   10  10,605 ± 0,527  us/op
 3. Scanner (JDK)                               avgt   10  12,083 ± 0,293  us/op
 2. CharStreams (guava)                         avgt   10  12,999 ± 0,514  us/op
 4. Stream Api (Java 8)                         avgt   10  15,811 ± 0,605  us/op
 9. BufferedReader (JDK)                        avgt   10  16,038 ± 0,711  us/op
 5. parallel Stream Api (Java 8)                avgt   10  21,544 ± 0,583  us/op

Testy wydajności dla dużych String (długość = 50100), adres URL w github (mode = średni czas, system = Linux, wynik 200 715 jest najlepszy):

               Benchmark                        Mode  Cnt   Score        Error  Units
 8. ByteArrayOutputStream and read (JDK)        avgt   10   200,715 ±   18,103  us/op
 1. IOUtils.toString (Apache Utils)             avgt   10   300,019 ±    8,751  us/op
 6. InputStreamReader and StringBuilder (JDK)   avgt   10   347,616 ±  130,348  us/op
 7. StringWriter and IOUtils.copy (Apache)      avgt   10   352,791 ±  105,337  us/op
 2. CharStreams (guava)                         avgt   10   420,137 ±   59,877  us/op
 9. BufferedReader (JDK)                        avgt   10   632,028 ±   17,002  us/op
 5. parallel Stream Api (Java 8)                avgt   10   662,999 ±   46,199  us/op
 4. Stream Api (Java 8)                         avgt   10   701,269 ±   82,296  us/op
10. BufferedInputStream, ByteArrayOutputStream  avgt   10   740,837 ±    5,613  us/op
 3. Scanner (JDK)                               avgt   10   751,417 ±   62,026  us/op
11. InputStream.read() and StringBuilder (JDK)  avgt   10  2919,350 ± 1101,942  us/op

Wykresy (testy wydajności w zależności od długości strumienia wejściowego w systemie Windows 7)
enter image description here

Test wydajności (średni czas) w zależności od długości strumienia wejściowego w systemie Windows 7:

 length  182    546     1092    3276    9828    29484   58968

 test8  0.38    0.938   1.868   4.448   13.412  36.459  72.708
 test4  2.362   3.609   5.573   12.769  40.74   81.415  159.864
 test5  3.881   5.075   6.904   14.123  50.258  129.937 166.162
 test9  2.237   3.493   5.422   11.977  45.98   89.336  177.39
 test6  1.261   2.12    4.38    10.698  31.821  86.106  186.636
 test7  1.601   2.391   3.646   8.367   38.196  110.221 211.016
 test1  1.529   2.381   3.527   8.411   40.551  105.16  212.573
 test3  3.035   3.934   8.606   20.858  61.571  118.744 235.428
 test2  3.136   6.238   10.508  33.48   43.532  118.044 239.481
 test10 1.593   4.736   7.527   20.557  59.856  162.907 323.147
 test11 3.913   11.506  23.26   68.644  207.591 600.444 1211.545

1656
2018-02-17 00:58



Podczas pisania "odpowiedzi podsumowującej" należy zauważyć, że niektóre rozwiązania automatycznie konwertują różne łamania linii (np \r\n) do \n co może być niepożądane w niektórych przypadkach. Również miło byłoby zobaczyć dodatkową pamięć wymaganą lub przynajmniej alokację ciśnienia (przynajmniej możesz uruchomić JMH z -prof gc). Dla naprawdę fajnego posta świetnie byłoby zobaczyć wykresy (w zależności od długości napisu w tym samym rozmiarze wejściowym i w zależności od rozmiaru wejściowego w obrębie tej samej długości ciągu znaków). - Tagir Valeev
Rewizja; najśmieszniejsze jest to, że wyniki są większe niż oczekiwano: należy używać standardowego cukru syntaktycznego JDK i / lub Apache Commons. - mudasobwa
Niesamowity post. Jeszcze jedna rzecz. Java 8 ostrzega przed korzystaniem z równoległych strumieni na zasobach, które zmuszą Cię do zablokowania i oczekiwania (takich jak ten strumień wejściowy), więc opcja strumienia równoległego jest raczej uciążliwa i nie warta tego nie? - mangusbrother
Czy strumień równoległy faktycznie utrzymuje kolejność linii? - Natix
Co jest reset() na przykład w 11? - Rob Stewart


Apache Commons pozwala:

String myString = IOUtils.toString(myInputStream, "UTF-8");

Oczywiście możesz wybrać inne kodowanie znaków oprócz UTF-8.

Zobacz także: (Dokumenty)


794
2017-12-08 20:13



Istnieje również metoda, która pobiera tylko argument inputStream, jeśli znajdujemy kodowanie domyślne. - Guillaume Coté
@Guillaume Cote Przypuszczam, że wiadomością jest to, że nigdy nie powinieneś być "w porządku z domyślnym kodowaniem", ponieważ nie możesz być pewien, co to jest, w zależności od platformy, na której działa kod java. - Per Wiklander
@Per Wiklander Nie zgadzam się z tobą. Kod, który będzie działał na jednym, może być całkiem pewny, że domyślne kodowanie będzie w porządku. W przypadku kodu, który otwiera tylko plik lokalny, rozsądną opcją jest poprosić o zakodowanie w domyślnym kodowaniu platformy. - Guillaume Coté
Aby zaoszczędzić komukolwiek kłopotów z Google - <dependency> <groupId> org.apache.commons </ groupId> <artifactId> commons-io </ artifactId> <wersja> 1.3.2 </ version> </ dependency> - Chris
Niewielka poprawa polegałaby na używaniu stałej Apache io (lub innej) do kodowania znaków, zamiast używania zwykłego ciągu literowego - np .: IOUtils.toString (myInputStream, Charsets.UTF_8);


Biorąc pod uwagę plik należy najpierw uzyskać java.io.Reader instancja. To można następnie odczytać i dodać do StringBuilder (nie potrzebujemy StringBuffer jeśli nie uzyskujemy dostępu do niego w wielu wątkach, i StringBuilder jest szybszy). Sztuczka polega na tym, że pracujemy w blokach i jako takie nie potrzebujemy innych strumieni buforujących. Rozmiar bloku jest sparametryzowany w celu optymalizacji wydajności w czasie wykonywania.

public static String slurp(final InputStream is, final int bufferSize) {
    final char[] buffer = new char[bufferSize];
    final StringBuilder out = new StringBuilder();
    try (Reader in = new InputStreamReader(is, "UTF-8")) {
        for (;;) {
            int rsz = in.read(buffer, 0, buffer.length);
            if (rsz < 0)
                break;
            out.append(buffer, 0, rsz);
        }
    }
    catch (UnsupportedEncodingException ex) {
        /* ... */
    }
    catch (IOException ex) {
        /* ... */
    }
    return out.toString();
}

263
2017-08-04 08:29



To rozwiązanie używa znaków wielobajtowych. W przykładzie zastosowano kodowanie UTF-8, które umożliwia ekspresję pełnego zakresu Unicode (w tym chiński). Zastąpienie "UTF-8" innym kodowaniem umożliwiłoby użycie tego kodowania. - Paul de Vrieze
@ User1 - Lubię korzystać z bibliotek w moim kodzie, dzięki czemu mogę szybciej wykonywać swoją pracę. To niesamowite, gdy twoi menadżerowie mówią "Wow James! Jak to się stało, że zrobiłeś to tak szybko ?!". Ale kiedy musimy poświęcić czas na wymyślanie koła tylko dlatego, że błędnie wpadliśmy na pomysł, aby włączyć wspólne, wielokrotnego użytku, wypróbowane i przetestowane narzędzie, rezygnujemy z czasu, który możemy poświęcić na realizację celów naszego projektu. Kiedy odkrywamy nowe koło, pracujemy dwa razy ciężko, a później do mety. Gdy jesteśmy na mecie, nie ma nikogo, kto by nam pogratulował. Budując dom, nie buduj też młota - jmort253
Przepraszam, po ponownym przeczytaniu mojego komentarza, to wygląda trochę arogancko. Po prostu uważam, że ważne jest, aby mieć dobry powód, aby unikać bibliotek, i że powód jest ważny, co może być bardzo dobre :) - jmort253
@ jmort253 Zauważyliśmy regresję wydajności po kilkukrotnym uaktualnieniu biblioteki w naszym produkcie. Na szczęście budujemy i sprzedajemy nasz własny produkt, więc tak naprawdę nie mamy tak zwanych terminów. Niestety budujemy produkt dostępny na wielu maszynach JVM, bazach danych i serwerach aplikacji w wielu systemach operacyjnych, więc musimy myśleć o użytkownikach używających słabych maszyn ... A optymalizacja operacji łańcuchowych może poprawić wydajność o 30 ~ 40%. I poprawka: In our product, I even replaced powinno być "my nawet zastąpione". - coolcfan
@ Jmort253 Gdybyś już używał Apache commons, powiedziałbym, idź do niego. W tym samym czasie korzystanie z bibliotek wiąże się z prawdziwym kosztem (w miarę rozprzestrzeniania zależności w wielu bibliotekach apache java). Gdyby to było jedyne wykorzystanie biblioteki, używanie biblioteki byłoby przesadą. Z drugiej strony, ustalając własny rozmiar bufora, możesz dostroić saldo użytkowania pamięci / procesora. - Paul de Vrieze


Co powiesz na to?

InputStream in = / * Twój InputStream * /;
StringBuilder sb=new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String read;

while((read=br.readLine()) != null) {
    //System.out.println(read);
    sb.append(read);   
}

br.close();
return sb.toString();

226
2017-07-13 15:56



Chodzi o to, że najpierw dzielisz się na linie, a potem je cofasz. Łatwiejsze i szybsze jest po prostu odczytanie dowolnych buforów. - Paul de Vrieze
Ponadto readLine nie rozróżnia między \ n a \ r, więc nie można odtworzyć dokładnego strumienia ponownie. - María Arias de Reyna Domínguez
@PauldeVrieze, ile linii i jak szybko trzeba je przetworzyć !? Zaryzykowałbym przypuszczenie, że jakakolwiek utrata wydajności byłaby niewielka lub mogłaby być obsługiwana przez co jakiś czas, logując ją do pliku i niszcząc stare String obj. - Thufir
bardzo nieefektywne, jak readLine czytaj znak po znaku, aby wyszukać EOL. Ponadto, jeśli w strumieniu nie ma linii podziału, nie ma to większego sensu. - njzk2
To nie jest najlepsza odpowiedź, ponieważ nie jest ściśle bajt po bajcie. Czytelnik wymienia nowe znaki, więc musisz zachować ostrożność, aby je zachować. - Jeffrey Blattman


Jeśli korzystasz z Kolekcji Google / Guava, możesz wykonać następujące czynności:

InputStream stream = ...
String content = CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8));
Closeables.closeQuietly(stream);

Zauważ, że drugi parametr (tj. Charsets.UTF_8) dla InputStreamReader nie jest konieczne, ale ogólnie dobrym pomysłem jest określenie kodowania, jeśli je znasz (co powinieneś!)


153
2018-05-08 20:24



@harschware: Zadajesz pytanie: "Jeśli masz obiekt java.io.InputStream, jak powinieneś przetworzyć ten obiekt i utworzyć ciąg?" Zakładałem, że strumień jest już obecny w tej sytuacji. - Sakuraba
Nie wyjaśniłeś swojej odpowiedzi bardzo dobrze i miał ona zmienne zewnętrzne; user359996 powiedział to samo co ty, ale znacznie wyraźniej. - Uronym
+1 dla guava, -1 dla nieokreślania kodowania strumienia wejściowego. na przykład. nowy InputStreamReader (strumień, "UTF-8") - andras
@Chris Noldus Z drugiej strony niektórzy ludzie mają już guava w swoim projekcie, tak jak ja, i uważają, że to rozwiązanie jest bardziej eleganckie niż wersja tylko SDK. - CorayThan
@Vadzim ta odpowiedź jest taka sama jak ta - oba używają funkcji CharStreams.toString - Tom


To jest moje czyste rozwiązanie Java i Android, działa dobrze ...

public String readFullyAsString(InputStream inputStream, String encoding)
        throws IOException {
    return readFully(inputStream).toString(encoding);
}    

public byte[] readFullyAsBytes(InputStream inputStream)
        throws IOException {
    return readFully(inputStream).toByteArray();
}    

private ByteArrayOutputStream readFully(InputStream inputStream)
        throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int length = 0;
    while ((length = inputStream.read(buffer)) != -1) {
        baos.write(buffer, 0, length);
    }
    return baos;
}

107
2018-06-10 21:07



Działa dobrze na Androida w porównaniu z innymi odpowiedziami, które działają tylko w korporacyjnej wersji java. - vorrtex
Rozbił się w systemie Android z błędem OutOfMemory w wierszu ".write", za każdym razem, dla krótkich łańcuchów. - Adam
Dodałem kodowanie. tak jak na marginesie, oryginalna metoda readFully, którą mam w swoim kodzie, nie zwraca String, zwraca bajt [] dla bardziej ogólnego zastosowania. Wdrożenie nowego ciągu (...) z kodowaniem jest obowiązkiem tego, który używa API! - TacB0sS
Szybka uwaga: Objętość pamięci tego jest ograniczona przez 2*n, gdzie n jest wielkością strumienia, jak na ByteArrayInputStream system automatycznego wzrostu. - njzk2
Niepotrzebnie podwaja zużycie pamięci, co jest cenne na urządzeniach mobilnych. Lepiej użyj InputStreamReader i dołącz do StringReader, bajt do konwersji będzie wykonywany w locie, a nie zbiorczo na końcu. - Oliv


Co powiesz na:

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;    

public static String readInputStreamAsString(InputStream in) 
    throws IOException {

    BufferedInputStream bis = new BufferedInputStream(in);
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    int result = bis.read();
    while(result != -1) {
      byte b = (byte)result;
      buf.write(b);
      result = bis.read();
    }        
    return buf.toString();
}

56
2018-01-01 03:43



Ten jest powolny, ponieważ czyta bajt po bajcie. - Daniel De León
@ DanielDeLeón Nie, nie jest. To jest BufferedInputStream. Bazowe odczyty to 8192 bajtów na raz. - user207421
@EJP Znalazłem go wolniej niż przy użyciu BufferedInputStream  i odczytywanie do bufora tablic bajtów zamiast jednego bajtu na raz. Przykład: 200ms vs 60ms podczas czytania pliku 4,56 MiB. - jk7


Oto najbardziej eleganckie, czysto Java (bez biblioteki) rozwiązanie, które wymyśliłem po kilku eksperymentach:

public static String fromStream(InputStream in) throws IOException
{
    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    StringBuilder out = new StringBuilder();
    String newLine = System.getProperty("line.separator");
    String line;
    while ((line = reader.readLine()) != null) {
        out.append(line);
        out.append(newLine);
    }
    return out.toString();
}

55
2017-09-02 11:50



Czy brakuje pliku reader.close ()? Idealnie z try / finally ... - Torben Kohlmeier
@TorbenKohlmeier, czytniki i bufory nie muszą być zamknięte. Zapewnione InputStream powinien zostać zamknięty przez dzwoniącego. - Drew Noakes
Nie zapomnij wspomnieć, że istnieje bardziej preferowany konstruktor w InputStreamReader, który pobiera CharSet. - jontejj
dlaczego ludzie nadal używają readLine? jeśli nie używasz linii per se, co to jest dobre (z wyjątkiem tego, że jest bardzo wolne?) - njzk2
@voho, jeśli jedna linia jest tak długa, to nie ma możliwości alokacji wartości zwracanej, która musi być równa lub większa od tej linii. Jeśli masz do czynienia z dużymi plikami, powinieneś je przesyłać strumieniowo. Istnieje wiele przypadków użycia do ładowania małych plików tekstowych do pamięci. - Drew Noakes