Bir InputStream'i Java'da bir String'e nasıl okurum / dönüştürürüm?


4063

Bir java.io.InputStreamnesneniz varsa, bu nesneyi nasıl işleyip bir String?


InputStreamMetin verileri içeren bir var ve varsa bunu bir dönüştürmek istiyorum varsayalım String, örneğin ben bunu bir günlük dosyasına yazabilirsiniz.

InputStreamOnu almanın ve dönüştürmenin en kolay yolu nedir String?

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

36
Bu sorunun yanıtları yalnızca akışın içeriğini (kapanana kadar) tamamen okumak istiyorsanız işe yarar . Bu her zaman amaçlanmadığı için (canlı bağlantıya sahip http istekleri kapatılmaz), bu yöntem bloğu çağırır (içeriği vermemeniz).
f1sh

21
Sen lüzum biliyor ve akış için karakter kodlamasını belirterek, yoksa olacaktır kullandığınız olacak, çünkü karakter kodlama hataları var rastgele makinesi / işletim sistemi / platform veya sürüm bunların kodunuzun çalıştırıldığı bağlı kodlayan seçilmiş. Olduğunu, do not platformu varsayılan kodlama bağlıdır yöntemleri kullanın.
Christoffer Hammarström

11
Sadece 9 yıl önce kendi yorum ile eğlenmek için, bu gün Groovy'ın "String s = new File (" SomeFile.txt "). Metin" kullanarak tüm dosyayı bir kerede okumak ve harika çalışıyor. Üretim dışı (script) kodum için harika kullanmaktan mutluyum ve - dürüstçe, kodlamanın ve son derece uzun dosyalarla, java'nın yaptığı şekilde üretim kodu için gerçekten iyi bir fikir olduğu için onu zorlamaya çalışıyor, bu yüzden onun için çalışıyor, Groovy, java'nın harika olmadığı hızlı komut dosyaları için çalışır - İş için doğru aracı kullanın ve hepsi işe yarar.
Bill K

Sadece basitleştirici: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

@BillK Java 11 ile, String s = Files.readString​(Path.of("SomeFile.txt"));dilin alabileceği kadar iyi olanı kullanabilirsiniz , bu da tanımladığınız gibi sihirli tür dönüşümlerini asla desteklemez.
Holger

Yanıtlar:


2530

Bunu yapmak için güzel bir yolu kullanıyor Apache commons IOUtils kopyalamak için InputStreambir içine StringWritergibi ... şey

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

ya da

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

Alternatif olarak, ByteArrayOutputStreamAkışlarınızı ve Yazarlarınızı karıştırmak istemiyorsanız kullanabilirsiniz


75
Android geliştiricileri için, android Apache'den IOUtils ile gelmiyor gibi görünüyor. Yani diğer cevaplara atıfta bulunmayı düşünebilirsiniz.
Chris.Zou

47
Bu, bu noktada inanılmaz eski bir sorudur (2008'de sorulmuştur). Daha modern cevapları okumak için zaman ayırmaya değer. Bazıları Java 8 kitaplığından yerel çağrılar kullanır.
Shadoninja

36
Bu cevap çok eskimiş ve kişi böyle işaretleyebilmelidir (ne yazık ki bu mümkün değildir atm).
codepleb

7
IOUtils.toString () uzun zamandır kullanımdan kaldırıldı. Bu cevap kesinlikle önerilen yol değildir.
Roshan

7
Sonra düzenlemek yardım edecek gelecek okuyucularına kullanımdan kaldırıldı niçin bunu.
Jean-François Fabre

2486

Diğer cevapları özetle Bunu yapmanın 11 ana yolunu buldum (aşağıya bakınız). Ve bazı performans testleri yazdım (aşağıdaki sonuçlara bakın):

Bir InputStream öğesini bir Dizeye dönüştürme yolları:

  1. IOUtils.toString(Apache Utils) uygulamasını kullanma

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

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

    Scanner s = new Scanner(inputStream).useDelimiter("\\A");
    String result = s.hasNext() ? s.next() : "";
  4. Akış API'sini kullanma (Java 8). Uyarı : Bu çözüm, farklı satır sonlarını (beğen \r\n) olarak dönüştürür \n.

    String result = new BufferedReader(new InputStreamReader(inputStream))
      .lines().collect(Collectors.joining("\n"));
  5. Paralel Akış API'sini kullanma (Java 8). Uyarı : Bu çözüm, farklı satır sonlarını (beğen \r\n) olarak dönüştürür \n.

    String result = new BufferedReader(new InputStreamReader(inputStream)).lines()
       .parallel().collect(Collectors.joining("\n"));
  6. InputStreamReaderVe StringBuilder(JDK) kullanma

    final int bufferSize = 1024;
    final char[] buffer = new char[bufferSize];
    final StringBuilder out = new StringBuilder();
    Reader in = new InputStreamReader(stream, StandardCharsets.UTF_8);
    int charsRead;
    while((charsRead = in.read(buffer, 0, buffer.length)) > 0) {
        out.append(buffer, 0, charsRead);
    }
    return out.toString();
  7. Kullanılması StringWriterve IOUtils.copy(Apache Commons)

    StringWriter writer = new StringWriter();
    IOUtils.copy(inputStream, writer, "UTF-8");
    return writer.toString();
  8. ByteArrayOutputStreamVe inputStream.read(JDK) kullanma

    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. BufferedReader(JDK) kullanarak . Uyarı: Bu çözüm, farklı satır sonlarını (like \n\r) line.separatorsistem özelliğine dönüştürür (örneğin, Windows'ta "\ r \ n" konumuna).

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

    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. inputStream.read()Ve StringBuilder(JDK) kullanarak . Uyarı : Bu çözümün Unicode ile ilgili sorunları vardır, örneğin Rusça metinlerle (yalnızca Unicode olmayan metinlerle doğru şekilde çalışır)

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

Uyarı :

  1. Çözüm 4, 5 ve 9 farklı satır sonlarını bire dönüştürür.

  2. Çözüm 11, Unicode metniyle düzgün çalışmıyor

Performans testleri

Küçük String(uzunluk = 175), github cinsinden url için performans testleri (mod = Ortalama Zaman, sistem = Linux, puan 1.343 en iyisidir):

              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

Big için performans testleri String(uzunluk = 50100), url github (mod = Ortalama Süre, sistem = Linux, 200.715 iyisi skor):

               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

Grafikler (Windows 7 sistemindeki Giriş Akışı uzunluğuna bağlı olarak performans testleri)
resim açıklamasını buraya girin

Windows 7 sistemindeki Giriş Akışı uzunluğuna bağlı olarak performans testi (Ortalama Süre):

 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

17
"Özet yanıtı" yazarken, bazı çözümlerin otomatik olarak bazı satırlarda istenmeyen bazı farklı satır (örneğin \r\n) satırlarını dönüştürdüğünü unutmayın \n. Ayrıca gerekli ek belleği veya en azından tahsis basıncını görmek de iyi olur (en azından JMH'yi çalıştırabilirsiniz -prof gc). Gerçekten havalı yazı için grafikleri görmek harika olurdu (aynı giriş boyutundaki dize uzunluğuna ve aynı dize uzunluğundaki giriş boyutuna bağlı olarak).
Tagir Valeev

16
Upvoted; en komik şey sonuçların beklenenden fazla olmasıdır: standart JDK ve / veya Apache Commons sözdizimsel şeker kullanılmalıdır.
Aleksei Matiushkin

25
Şaşırtıcı yazı. Sadece bir şey. Java 8, sizi kilitlemeye ve beklemeye zorlayacak kaynaklarda (bu giriş akışı gibi) paralel akışların kullanılmasına karşı uyarır, böylece paralel akış seçeneği oldukça hantaldır ve buna değmez mi?
mangusbrother

10
Paralel akış aslında satır sırasını koruyor mu?
Natix

6
Ne reset()örnek 11'de için?
Rob Stewart

2307

İşte yalnızca standart Java kitaplığını kullanmanın bir yolu (akışın kapalı olmadığını, kilometrenizin değişebileceğini unutmayın).

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

Bu numarayı "Aptal Tarayıcı numaralar" makalesinden . Bunun nedeni, Tarayıcı'nın akıştaki jetonları yinelemesi ve bu durumda jetonları "giriş sınırının başlangıcı" (\ A) kullanarak ayırırız, böylece bize akışın tüm içeriği için yalnızca bir jeton veririz.

Giriş akışının kodlaması hakkında spesifik olmanız gerekirse Scanner, yapıcıya hangi karakter kümesinin kullanılacağını belirten ikinci argümanı sağlayabilirsiniz (örn. "UTF-8").

Şapka ucu da beni bir zamanlar bu makaleye yönlendiren Jacob'a gidiyor .


8
Teşekkürler, bu sürümüm için giriş akışını kapatan bir nihayet blok ekledim, bu yüzden kullanıcının girişi okumayı bitirdiğinizden beri zorunda değil. Arayan kodunu önemli ölçüde basitleştirir.

4
@PavelRepin @Patrick benim durumumda, boş bir inputStream Tarayıcı yapımı sırasında bir NPE'ye neden oldu. if (is == null) return "";Yöntemin başına eklemek zorunda kaldım ; Boş girdinin daha iyi işlenmesi için bu cevabın güncellenmesi gerektiğine inanıyorum.
CFL_Jeff

115
Java 7 için bir deneme ile try(java.util.Scanner s = new java.util.Scanner(is)) { return s.useDelimiter("\\A").hasNext() ? s.next() : ""; }
kapatabilirsiniz

5
Ne yazık ki bu çözüm temel akış uygulamamda atılan istisnaları kaybediyor gibi görünüyor.
Taig

11
Konsol giriş akışlarında FYI, hasNext blokları ( buraya bakınız ). (Şu anda bu sorunla karşılaştım.) Bu çözüm aksi halde işe yarıyor ... sadece bir başa baş.
Ryan

848

Apache Commons şunları sağlar:

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

Tabii ki, UTF-8'in yanı sıra başka karakter kodlamaları da seçebilirsiniz.

Ayrıca bakınız: ( belgeler )


1
Ayrıca, varsayılan kodlamayla bulursanız, yalnızca inputStream argümanını alan bir yöntem vardır.
Guillaume Coté

13
@Guillaume Coté Sanırım buradaki mesaj asla "varsayılan kodlama ile iyi" olmamalıdır, çünkü java kodunun çalıştığı platforma bağlı olarak ne olduğundan emin olamazsınız.
Wiklander başına

7
@Per Wiklander Seninle aynı fikirde değilim. Tek bir kod üzerinde çalışacak olan kod, varsayılan kodlamanın iyi olacağından emin olabilir. Yalnızca yerel dosyayı açan kod için, bunların platform varsayılan kodlamasında kodlanmalarını istemek makul bir seçenektir.
Guillaume Coté

39
Herkesi kurtarmak için Googling - <dependency> <groupId> org.apache.commons </groupId> <artifactId> commons-io </artifactId> <version> 1.3.2 </version> </dependency>
Chris

7
Ayrıca düz dize hazır bilgisi kullanmak yerine karakter kodlaması için apache io (veya başka) sabitini kullanmak çok az iyileştirme olabilir - örneğin: IOUtils.toString (myInputStream, Charsets.UTF_8);

300

Dosya dikkate alındığında önce bir java.io.Readerörnek alınmalıdır . Bu daha sonra okunabilir ve a eklenebilir StringBuilder( StringBufferbirden fazla iş parçacığına erişmiyorsak buna ihtiyacımız yoktur ve StringBuilderdaha hızlıdır). Buradaki hile, bloklar halinde çalışmamızdır ve bu nedenle başka tamponlama akışlarına gerek yoktur. Blok boyutu, çalışma zamanı performans optimizasyonu için parametrelendirilir.

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

8
Bu çözüm çok baytlı karakterler kullanır. Örnek, tam unicode aralığının (Çince dahil) ifadesine izin veren UTF-8 kodlamasını kullanır. "UTF-8" i başka bir kodlama ile değiştirmek o kodlamanın kullanılmasına izin verecektir.
Paul de Vrieze

27
@ User1 - İşimi daha hızlı yapabilmem için kodumda kütüphaneleri kullanmayı seviyorum. Yöneticileriniz "Vay canına James! Bunu nasıl bu kadar hızlı yaptınız ?!" Ancak, tekerleği yeniden icat etmek için zaman harcamak zorunda kaldığımızda, ortak, tekrar kullanılabilir, denenmiş ve test edilmiş bir yardımcı program dahil etmek için yanlış fikirlere sahip olduğumuz için, projemizin hedeflerini ilerletmek için harcayabileceğimiz zamandan vazgeçiyoruz. Tekerleği yeniden icat ettiğimizde, iki kat daha sıkı çalışıyoruz ancak daha sonra bitiş çizgisine ulaşıyoruz. Bitiş çizgisine girdikten sonra bizi tebrik edecek kimse yok. Bir ev inşa ederken, çekiç de inşa etmeyin
jmort253

10
Üzgünüm, yorumumu tekrar okuduktan sonra biraz kibirli çıkıyor. Sadece kütüphanelerden kaçınmak için iyi bir nedene sahip olmanın önemli bir neden olduğunu ve bunun geçerli bir neden olduğunu düşünüyorum ki, çok iyi olabilir :)
jmort253

4
@ jmort253 Ürünümüzdeki bazı kütüphaneleri birkaç kez güncelledikten sonra performans gerilemesini fark ettik. Neyse ki kendi ürünümüzü inşa ediyor ve satıyoruz, bu yüzden sözde son teslim tarihlerine sahip değiliz. Ne yazık ki birçok işletim sisteminde birçok JVM, veritabanı ve uygulama sunucusunda mevcut olan bir ürün geliştiriyoruz, bu nedenle zayıf makineleri kullanan kullanıcılar için düşünmemiz gerekiyor ... Ve bir dize işlemi optimizasyonu mükemmelliği% 30 ~ 40 oranında artırabilir. Ve bir düzeltme: In our product, I even replaced'biz bile değiştirdik' olmalı.
coolcfan

10
@ jmort253 Zaten apache ortaklarını kullanırsanız, söyleyebilirim. Aynı zamanda, kütüphaneleri kullanmanın gerçek bir maliyeti vardır (birçok apache java kütüphanesinde bağımlılığın çoğalması gösterdiği gibi). Kütüphanenin tek kullanımı bu olsaydı, kütüphaneyi kullanmak aşırı derecede ağır olurdu. Öte yandan, kendi arabellek boyutlarınızı belirleyerek bellek / işlemci kullanım dengenizi ayarlayabilirsiniz.
Paul de Vrieze

248

kullanın:

InputStream in = /* Your 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();

11
Mesele şu ki, önce çizgilere ayrılıyorsunuz ve sonra geri alıyorsunuz. Sadece rastgele arabellekleri okumak daha kolay ve hızlıdır.
Paul de Vrieze

20
Ayrıca, readLine \ n ve \ r arasında ayrım yapmaz, bu nedenle tam akışı yeniden üretemezsiniz.
María Arias de Reyna Domínguez

2
readLineEOL aramak için karakter karakter okuma gibi çok verimsiz . Ayrıca, akışta satır sonu yoksa, bu gerçekten mantıklı değildir.
njzk2

3
@Gops AB: Bunu denerseniz ve örneğinizde yeni satırlar varsa, bu döngünün readline () ve StringBuilder.append () kullanılarak oluşturulma şeklinin aslında yeni satırları korumadığını göreceksiniz.
Russ Bateman

4
Bu en iyi cevap değil çünkü kesinlikle bayt çıkışı değil. Okuyucu yeni satırları keser, bu yüzden onları korumak için dikkatli olmalısınız.
Jeffrey Blattman

173

Google-Collections / Guava kullanıyorsanız aşağıdakileri yapabilirsiniz:

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

İkinci parametrenin (yani Charsets.UTF_8) InputStreamReadergerekli olmadığına dikkat edin, ancak eğer biliyorsanız kodlamayı belirtmek iyi bir fikirdir (ki bunu yapmalısınız!)


2
@harschware: Şu soru göz önüne alındığında: "java.io.InputStream nesneniz varsa, bu nesneyi nasıl işleyip Dize üretmelisiniz?" Durumda zaten bir akışın mevcut olduğunu varsaydım.
Sakuraba

Cevabınızı çok iyi açıklamadınız ve yabancı değişkenleriniz vardı; user359996 seninle aynı şeyi söyledi, ama çok daha net.
Uronym

2
Guava için +1, giriş akışının kodlamasını belirtmemek için -1. Örneğin. yeni InputStreamReader (akış, "UTF-8")
andras

@Chris Noldus Öte yandan, bazı insanlar benim gibi projelerinde zaten guava var ve bu çözümün sadece sdk versiyonundan daha zarif olduğunu düşünüyorlar.
CorayThan

@Vadzim bu cevabın aynısı - her ikisi de CharStreams.toString kullanıyor
Tom

125

Bu, Android ve diğer JVM için mükemmel uyum sağlayan en iyi saf Java çözümüdür.

Bu çözüm inanılmaz iyi çalışıyor ... basit, hızlı ve aynı şekilde küçük ve büyük akışlarda çalışıyor !! (yukarıdaki karşılaştırmaya bakın .. No. 8 )

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

4
Android'de yalnızca kurumsal Java'da çalışan diğer cevaplarla karşılaştırıldığında iyi çalışır.
vortexwolf

Kısa dizeler için her seferinde ".write" satırında OutOfMemory hatasıyla Android'de çöktü.
Adam

Kodlamayı ekledim. sadece bir yan not olarak, benim kod var orijinal readFully yöntemi String döndürmez, daha genel amaçlı işlevsellik için byte [] döndürür. Kodlama ile yeni String (...) uygulamak, API'yi kullananların sorumluluğundadır!
TacB0sS

2
Kısa not: Bunun bellek alanı 2*n, ByteArrayInputStreamotomatik büyüyen sisteme göre n'nin akımın boyutu olduğu maksimum değerdir .
njzk2

3
Mobil cihazlarda değerli olan gereksiz bellek kullanımını iki katına çıkarır. InputStreamReader'ı kullanmanız ve StringReader'a eklemeniz daha iyi olur, bayttan char'a dönüşüm sonunda toplu olarak değil, anında yapılır.
Oliv

84

Bütünlük için Java 9 çözümü:

public static String toString(InputStream input) throws IOException {
    return new String(input.readAllBytes(), StandardCharsets.UTF_8);
}

readAllBytesBüyük olasılıkla sürümde görünmesini, böylece JDK 9 ana kod temeli şu anda. JDK 9 anlık görüntü derlemelerini kullanarak hemen deneyebilirsiniz .


Yöntem okuma için çok fazla bellek ayırmıyor mu? byte[] buf = new byte[DEFAULT_BUFFER_SIZE];nerede MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;verir MAX_BUFFER_SIZE = 2147483639. Google yaklaşık 2.147 GB olduğunu söylüyor.
Rekin

Üzgünüm, hesaplamalarda hata yaptım. 2 GB. Yorumu düzenledim. Yani, bir 4kb dosyası gibi okursam bile 2GB bellek kullanır mıyım?
Rekin

2
@ChristianHujer, son jdk8u taahhüdünde görmüyorum . AFAIK yeni yöntemleri hiçbir zaman Java güncellemelerinde kullanılmaz, sadece büyük sürümlerde.
Tagir Valeev

4
@ChristianHujer, soru hakkındaydı InputStream, hakkında değil Path. InputStreamBirçok farklı kaynaktan oluşturulabilir, sadece dosyaları değil.
Tagir Valeev

5
Bu bir yıl önce yazılmıştır, bu yüzden güncellemek için, bu yöntemin gerçekten JDK 9 genel sürümünde olduğunu onaylıyorum. Ayrıca, kodlamanız "ISO-Latin-1" ise, Java 9 Strings artık kullandığından bu son derece verimli olacaktır bir byte[]uygulama tüm karakterlerin ilk 256 kod noktaları ise. Bu, yeni Dize (bayt [], "ISO-Latin-1") basit bir dizi kopyası olacağı anlamına gelir.
Klitos Kyriacou

66

kullanın:

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

@ DanielDeLeón Hayır değil. Bu bir BufferedInputStream. Temel okumalar bir seferde 8192 bayttır.
user207421

2
@EJP Ben ettik o kullanmaktan daha yavaş olduğu bulunmuştur BufferedInputStream ve bunun yerine bir seferde bir bayt tampon bir bayt dizisi okuma. Örnek: 4,56 MiB dosyasını okurken 200ms ve 60ms.
jk7

Kimsenin buradaki diğer büyük soruna işaret etmediği garip (evet, byte-byte-byte'ı okumak arabelleğe almada bile boşa harcanıyor): "varsayılan kodlama" olan her şeye dayanır - bu nadiren iyi bir yoldur. Bunun yerine, kodlamayı argüman olarak ilettiğinizden emin olun buf.toString().
StaxMan

@ jk7 4.56MB'lık bir dosyayı okuma süresi o kadar küçük ki, farklar önemli olmayabilir.
user207421

63

İşte bazı denemelerden sonra geldiğim en zarif, saf Java (kütüphane yok) çözümü:

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

8
@TorbenKohlmeier, okuyucular ve arabelleklerin kapatılması gerekmez. Sağlanan kişi InputStreamarayan tarafından kapatılmalıdır.
Drew Noakes

7
InputStreamReader'da CharSet alan daha çok tercih edilen bir kurucu olduğunu belirtmeyi unutmayın.
jontejj

7
insanlar neden kullanmaya devam ediyor readLine? Eğer çizgileri kendi
başınıza kullanmıyorsanız

4
Çizgilerle okumayın. Bir çizgi öylesine uzunsa, öbeğe sığmazsa?
voho

4
@voho, bir satır bu kadar uzunsa, dönüş değerini yine de o satıra eşit veya daha büyük olması gereken bir değer tahsis etmenin bir yolu yoktur. Büyük dosyalar ile uğraşıyorsanız, onları akış olarak almalısınız. Küçük metin dosyalarını belleğe yüklemek için birçok kullanım durumu vardır.
Drew Noakes

55

Burada 14 ayrı cevap üzerine bir kriter yaptım (kredi sağlamadığım için özür dilerim ama çok fazla kopya var).

Sonuç çok şaşırtıcı. Görünüşe göre Apache IOUtils'in en yavaş ve ByteArrayOutputStreamen hızlı çözümler olduğu :

İlk önce en iyi yöntem:

public String inputStreamToString(InputStream inputStream) throws IOException {
    try(ByteArrayOutputStream result = new ByteArrayOutputStream()) {
        byte[] buffer = new byte[1024];
        int length;
        while ((length = inputStream.read(buffer)) != -1) {
            result.write(buffer, 0, length);
        }

        return result.toString(UTF_8);
    }
}

Karşılaştırma sonuçları, 20 döngüde 20 MB rasgele bayt

Milisaniye cinsinden süre

  • ByteArrayOutputStreamTest: 194
  • NioStream: 198
  • Java9IST Aktarımı İçin: 201
  • Java9ISReadAllBytes: 205
  • BufferedInputStreamVsByteArrayOutputStream: 314
  • ApacheStringWriter2: 574
  • Akarsu: 589
  • Tarayıcı OkuyucuNoNextTest: 614
  • Tarayıcı Okuyucu: 633
  • ApacheStringWriter: 1544
  • StreamApi: Hata
  • ParallelStreamApi: Hata
  • BufferReaderTest: Hata
  • InputStreamAndStringBuilder: Hata

Karşılaştırma kaynak kodu

import com.google.common.io.CharStreams;
import org.apache.commons.io.IOUtils;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

/**
 * Created by Ilya Gazman on 2/13/18.
 */
public class InputStreamToString {


    private static final String UTF_8 = "UTF-8";

    public static void main(String... args) {
        log("App started");
        byte[] bytes = new byte[1024 * 1024];
        new Random().nextBytes(bytes);
        log("Stream is ready\n");

        try {
            test(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void test(byte[] bytes) throws IOException {
        List<Stringify> tests = Arrays.asList(
                new ApacheStringWriter(),
                new ApacheStringWriter2(),
                new NioStream(),
                new ScannerReader(),
                new ScannerReaderNoNextTest(),
                new GuavaCharStreams(),
                new StreamApi(),
                new ParallelStreamApi(),
                new ByteArrayOutputStreamTest(),
                new BufferReaderTest(),
                new BufferedInputStreamVsByteArrayOutputStream(),
                new InputStreamAndStringBuilder(),
                new Java9ISTransferTo(),
                new Java9ISReadAllBytes()
        );

        String solution = new String(bytes, "UTF-8");

        for (Stringify test : tests) {
            try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
                String s = test.inputStreamToString(inputStream);
                if (!s.equals(solution)) {
                    log(test.name() + ": Error");
                    continue;
                }
            }
            long startTime = System.currentTimeMillis();
            for (int i = 0; i < 20; i++) {
                try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
                    test.inputStreamToString(inputStream);
                }
            }
            log(test.name() + ": " + (System.currentTimeMillis() - startTime));
        }
    }

    private static void log(String message) {
        System.out.println(message);
    }

    interface Stringify {
        String inputStreamToString(InputStream inputStream) throws IOException;

        default String name() {
            return this.getClass().getSimpleName();
        }
    }

    static class ApacheStringWriter implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            StringWriter writer = new StringWriter();
            IOUtils.copy(inputStream, writer, UTF_8);
            return writer.toString();
        }
    }

    static class ApacheStringWriter2 implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            return IOUtils.toString(inputStream, UTF_8);
        }
    }

    static class NioStream implements Stringify {

        @Override
        public String inputStreamToString(InputStream in) throws IOException {
            ReadableByteChannel channel = Channels.newChannel(in);
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 16);
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            WritableByteChannel outChannel = Channels.newChannel(bout);
            while (channel.read(byteBuffer) > 0 || byteBuffer.position() > 0) {
                byteBuffer.flip();  //make buffer ready for write
                outChannel.write(byteBuffer);
                byteBuffer.compact(); //make buffer ready for reading
            }
            channel.close();
            outChannel.close();
            return bout.toString(UTF_8);
        }
    }

    static class ScannerReader implements Stringify {

        @Override
        public String inputStreamToString(InputStream is) throws IOException {
            java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
            return s.hasNext() ? s.next() : "";
        }
    }

    static class ScannerReaderNoNextTest implements Stringify {

        @Override
        public String inputStreamToString(InputStream is) throws IOException {
            java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
            return s.next();
        }
    }

    static class GuavaCharStreams implements Stringify {

        @Override
        public String inputStreamToString(InputStream is) throws IOException {
            return CharStreams.toString(new InputStreamReader(
                    is, UTF_8));
        }
    }

    static class StreamApi implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            return new BufferedReader(new InputStreamReader(inputStream))
                    .lines().collect(Collectors.joining("\n"));
        }
    }

    static class ParallelStreamApi implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            return new BufferedReader(new InputStreamReader(inputStream)).lines()
                    .parallel().collect(Collectors.joining("\n"));
        }
    }

    static class ByteArrayOutputStreamTest implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            try(ByteArrayOutputStream result = new ByteArrayOutputStream()) {
                byte[] buffer = new byte[1024];
                int length;
                while ((length = inputStream.read(buffer)) != -1) {
                    result.write(buffer, 0, length);
                }

                return result.toString(UTF_8);
            }
        }
    }

    static class BufferReaderTest implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            String newLine = System.getProperty("line.separator");
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            StringBuilder result = new StringBuilder(UTF_8);
            String line;
            boolean flag = false;
            while ((line = reader.readLine()) != null) {
                result.append(flag ? newLine : "").append(line);
                flag = true;
            }
            return result.toString();
        }
    }

    static class BufferedInputStreamVsByteArrayOutputStream implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            BufferedInputStream bis = new BufferedInputStream(inputStream);
            ByteArrayOutputStream buf = new ByteArrayOutputStream();
            int result = bis.read();
            while (result != -1) {
                buf.write((byte) result);
                result = bis.read();
            }

            return buf.toString(UTF_8);
        }
    }

    static class InputStreamAndStringBuilder implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            int ch;
            StringBuilder sb = new StringBuilder(UTF_8);
            while ((ch = inputStream.read()) != -1)
                sb.append((char) ch);
            return sb.toString();
        }
    }

    static class Java9ISTransferTo implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            inputStream.transferTo(bos);
            return bos.toString(UTF_8);
        }
    }

    static class Java9ISReadAllBytes implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            return new String(inputStream.readAllBytes(), UTF_8);
        }
    }

}

Java'da kıyaslama yapmak kolay değildir (özellikle JIT nedeniyle). Benchmark kaynak kodunu okuduktan sonra, yukarıdaki değerlerin kesin olmadığına ve herkesin onlara inanarak dikkatli olması gerektiğine ikna oldum.
Dalibor

@Dalibor muhtemelen iddianız için sadece bir link yerine daha fazla gerekçe sunmalısınız.
Ilya Gazman

Kendi kriterlerinizi oluşturmanın kolay olmadığı gerçeğinin gerçekten bilindiği düşünüyorum. Bunu bilmeyenler için bağlantı var;)
Dalibor

@Dalibor Belki de en iyisi değilim, ama Java kriterleri hakkında iyi bir anlayışa sahibim, bu yüzden belirli bir soruna işaret edemezseniz, sadece yanıltıcısınız ve bu koşullar altında sizinle konuşmaya devam etmeyeceğim.
Ilya Gazman

Çoğunlukla Dalibor'a katılıyorum. "Java kriterleri hakkında iyi bir anlayışa sahip olduğunuzu" söylüyorsunuz, ancak görünüşe göre bu yaklaşımın bilinen sorunlarından habersizken en naif yaklaşımı uygulamışsınız gibi görünüyor. Yeni başlayanlar için, bu sorudaki her
gönderiyi

41

Bazı Java 8 hileleri kullanırdım.

public static String streamToString(final InputStream inputStream) throws Exception {
    // buffering optional
    try
    (
        final BufferedReader br
           = new BufferedReader(new InputStreamReader(inputStream))
    ) {
        // parallel optional
        return br.lines().parallel().collect(Collectors.joining("\n"));
    } catch (final IOException e) {
        throw new RuntimeException(e);
        // whatever.
    }
}

Daha özlü olmak dışında aslında diğer bazı cevaplarla aynı.


5
Misiniz return nullhiç denilen olsun? Ya br.lines...iadeler ya da bir istisna atılır.
Holloway

3
@Khaled A Khunaifer: evet, oldukça emin ... belki buraya bir göz atmalısınız : docs.oracle.com/javase/tutorial/essential/exceptions/… . Yanlış düzenlediğiniz bir "kaynakları denemek" ifadesidir.
jamp

11
parallel()Akışı neden çağırıyorsunuz ?
robinst

4
Kaynak akışı Windows satır sonlarını kullandığı için verilerin dürüst bir kopyasıyla sonuçlanmayacaktır, çünkü hepsi \r\ndönüştürülecektir \n...
Lucas

2
System.lineSeparator()Platforma bağlı uygun satır sonunu kullanmak için kullanabilirsiniz.
Steve K

34

Zamanlama testleri yaptım çünkü zaman önemli, her zaman.

Bir dize 3 farklı şekillerde yanıt almaya çalıştım. (aşağıda gösterilen)
uğruna okunabilirlik için blokları denemek / yakalamak dışında bıraktım.

Bağlam vermek için, bu, 3 yaklaşımın tümü için önceki koddur:

   String response;
   String url = "www.blah.com/path?key=value";
   GetMethod method = new GetMethod(url);
   int status = client.executeMethod(method);

1)

 response = method.getResponseBodyAsString();

2)

InputStream resp = method.getResponseBodyAsStream();
InputStreamReader is=new InputStreamReader(resp);
BufferedReader br=new BufferedReader(is);
String read = null;
StringBuffer sb = new StringBuffer();
while((read = br.readLine()) != null) {
    sb.append(read);
}
response = sb.toString();

3)

InputStream iStream  = method.getResponseBodyAsStream();
StringWriter writer = new StringWriter();
IOUtils.copy(iStream, writer, "UTF-8");
response = writer.toString();

Dolayısıyla, aynı istek / yanıt verileriyle her yaklaşımda 500 test çalıştırdıktan sonra, sayılar aşağıdadır. Bir kez daha, bunlar benim bulgularım ve bulgularınız tam olarak aynı olmayabilir, ancak bunu başkalarına bu yaklaşımların verimlilik farklılıklarına dair bir gösterge vermek için yazdım.

Rütbeler:
Yaklaşım # 1
Yaklaşım # 3 -% 2.6, # 1'den daha yavaş
Yaklaşım # 2 -% 4.3, # 1'den daha yavaş

Bu yaklaşımlardan herhangi biri, bir yanıtı almak ve ondan bir String oluşturmak için uygun bir çözümdür.


2
2) bir hata içeriyorsa, her zaman bir adım daha atmanız gerektiğinden, dizenin sonuna her zaman "null" ekler. Performans yine de aynı olacak. Bu çalışması gerekir: String read = null; StringBuffer sb = new StringBuffer (); while ((read = br.readLine ())! = null) {sb.append (okuma); }
LukeSolar

GetMethod'un standart Java değil org.apache.commons.httpclient'in bir parçası olduğu belirtilmelidir
jk7

Yaklaşım # 2 dosyada çok satır varsa '\ n' tüketecektir, bu cevap olmamalı
Ninja

33

Stream s kullanarak saf Java çözümü , Java 8'den beri çalışır.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.stream.Collectors;

// ...
public static String inputStreamToString(InputStream is) throws IOException {
    try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
        return br.lines().collect(Collectors.joining(System.lineSeparator()));
    }
}

Christoffer Hammarström tarafından diğer cevabın altında belirtildiği gibi, Charset'i açıkça belirtmek daha güvenlidir . Ie InputStreamReader yapıcısı aşağıdaki gibi değiştirilebilir:

new InputStreamReader(is, Charset.forName("UTF-8"))

11
Yapmak yerine (from ) Charset.forName("UTF-8")kullanın . StandardCharsets.UTF_8java.nio.charset
robinst

26

İşte az ya da çok sampath'ın cevabı, biraz temizlendi ve bir işlev olarak temsil edildi:

String streamToString(InputStream in) throws IOException {
  StringBuilder out = new StringBuilder();
  BufferedReader br = new BufferedReader(new InputStreamReader(in));
  for(String line = br.readLine(); line != null; line = br.readLine()) 
    out.append(line);
  br.close();
  return out.toString();
}


21

Commons IO'yu (FileUtils / IOUtils / CopyUtils) kullanamıyorsanız, dosyayı satır satır okumak için bir BufferedReader kullanma örneği:

public class StringFromFile {
    public static void main(String[] args) /*throws UnsupportedEncodingException*/ {
        InputStream is = StringFromFile.class.getResourceAsStream("file.txt");
        BufferedReader br = new BufferedReader(new InputStreamReader(is/*, "UTF-8"*/));
        final int CHARS_PER_PAGE = 5000; //counting spaces
        StringBuilder builder = new StringBuilder(CHARS_PER_PAGE);
        try {
            for(String line=br.readLine(); line!=null; line=br.readLine()) {
                builder.append(line);
                builder.append('\n');
            }
        } 
        catch (IOException ignore) { }

        String text = builder.toString();
        System.out.println(text);
    }
}

Veya ham hız istiyorsanız, Paul de Vrieze'in önerdiği bir varyasyon öneririm (bir StringWriter kullanmaktan kaçınır (dahili olarak bir StringBuffer kullanır):

public class StringFromFileFast {
    public static void main(String[] args) /*throws UnsupportedEncodingException*/ {
        InputStream is = StringFromFileFast.class.getResourceAsStream("file.txt");
        InputStreamReader input = new InputStreamReader(is/*, "UTF-8"*/);
        final int CHARS_PER_PAGE = 5000; //counting spaces
        final char[] buffer = new char[CHARS_PER_PAGE];
        StringBuilder output = new StringBuilder(CHARS_PER_PAGE);
        try {
            for(int read = input.read(buffer, 0, buffer.length);
                    read != -1;
                    read = input.read(buffer, 0, buffer.length)) {
                output.append(buffer, 0, read);
            }
        } catch (IOException ignore) { }

        String text = output.toString();
        System.out.println(text);
    }
}

Kod çalışması için, ben this.getClass () kullanmak zorunda getClassLoader () getResourceAsStream () (a maven projesi ile Eclipse kullanarak)..
Greuze

19

Bu güzel çünkü:

  • Charset'i güvenle işler.
  • Okuma arabelleği boyutunu denetleyin.
  • Oluşturucunun uzunluğunu sağlayabilirsiniz ve kesin bir değer olması gerekmez.
  • Kütüphane bağımlılığı yoktur.
  • Java 7 veya üstü içindir.

Nasıl yapılır?

public static String convertStreamToString(InputStream is) throws IOException {
   StringBuilder sb = new StringBuilder(2048); // Define a size if you have an idea of it.
   char[] read = new char[128]; // Your buffer size.
   try (InputStreamReader ir = new InputStreamReader(is, StandardCharsets.UTF_8)) {
     for (int i; -1 != (i = ir.read(read)); sb.append(read, 0, i));
   }
   return sb.toString();
}

JDK 9 için

public static String inputStreamString(InputStream inputStream) throws IOException {
    try (inputStream) {
        return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
    }
}

1
Bu catch (Throwable)üretim kodu ise gerçekten boş olmamalıdır.
Christian Hujer

1
Bu yakalanabilir - atılabilir ifadeye ne yazmalı?
alex

UTF-8 kullanmak genellikle makul olsa da, karakterlerin bu şekilde kodlandığını varsaymamalısınız.
Martin

18

Bu, apache uygulamasına sahip olmak isteyen ancak kütüphanenin tamamını istemeyenler için org.apache.commons.io.IOUtils kaynak koddan uyarlanmış bir cevaptır .

private static final int BUFFER_SIZE = 4 * 1024;

public static String inputStreamToString(InputStream inputStream, String charsetName)
        throws IOException {
    StringBuilder builder = new StringBuilder();
    InputStreamReader reader = new InputStreamReader(inputStream, charsetName);
    char[] buffer = new char[BUFFER_SIZE];
    int length;
    while ((length = reader.read(buffer)) != -1) {
        builder.append(buffer, 0, length);
    }
    return builder.toString();
}

18

Akış Okuyucular kullanıyorsanız akışları sonunda kapattığınızdan emin olun

private String readStream(InputStream iStream) throws IOException {
    //build a Stream Reader, it can read char by char
    InputStreamReader iStreamReader = new InputStreamReader(iStream);
    //build a buffered Reader, so that i can read whole line at once
    BufferedReader bReader = new BufferedReader(iStreamReader);
    String line = null;
    StringBuilder builder = new StringBuilder();
    while((line = bReader.readLine()) != null) {  //Read till end
        builder.append(line);
        builder.append("\n"); // append new line to preserve lines
    }
    bReader.close();         //close all opened stuff
    iStreamReader.close();
    //iStream.close(); //EDIT: Let the creator of the stream close it!
                       // some readers may auto close the inner stream
    return builder.toString();
}

DÜZENLEME: JDK 7+ sürümünde, kaynaklarla deneme yapısını kullanabilirsiniz.

/**
 * Reads the stream into a string
 * @param iStream the input stream
 * @return the string read from the stream
 * @throws IOException when an IO error occurs
 */
private String readStream(InputStream iStream) throws IOException {

    //Buffered reader allows us to read line by line
    try (BufferedReader bReader =
                 new BufferedReader(new InputStreamReader(iStream))){
        StringBuilder builder = new StringBuilder();
        String line;
        while((line = bReader.readLine()) != null) {  //Read till end
            builder.append(line);
            builder.append("\n"); // append new line to preserve lines
        }
        return builder.toString();
    }
}

2
Akışları kapatma konusunda haklısınız, ancak akışları kapatma sorumluluğu genellikle akış oluşturucusudur (başladığınızı bitirin). Bu yüzden, iStreamgerçekten arayan tarafından kapatılmalıdır çünkü arayan yarattı iStream. Ayrıca, kapanış akışları bir finallyblokta veya daha iyisi bir Java 7 kaynaklarla deneme ifadesinde yapılmalıdır . Zaman kodunda, readLine()atar IOException, ya builder.append()atar OutOfMemoryError, akarsular açık kalmak istiyorum.
Christian Hujer

16

Bir diğeri, tüm Bahar kullanıcıları için:

import java.nio.charset.StandardCharsets;
import org.springframework.util.FileCopyUtils;

public String convertStreamToString(InputStream is) throws IOException { 
    return new String(FileCopyUtils.copyToByteArray(is), StandardCharsets.UTF_8);
}

İçindeki yarar yöntemleri , org.springframework.util.StreamUtilsdekilere benzer FileCopyUtils, ancak bittiğinde akışı açık bırakır.


16

Kullan java.io.InputStream.transferTo (OutputStream) Java 9'da desteklenen ve ByteArrayOutputStream.toString (String) charset adını alır:

public static String gobble(InputStream in, String charsetName) throws IOException {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    in.transferTo(bos);
    return bos.toString(charsetName);
}

Davanızda karakter adı için ne geçtiniz?
virsha

1
@virsha Bunu InputStream sağlayan kaynaktan belirlemeniz gerekir. Hangi kodlamayı kullandığını bilmeden bir dizeye sahip olmanın mantıklı olmadığını
jmehrens

15

İşte dönüştürmek için komple bir yöntemdir InputStreamiçine Stringherhangi bir üçüncü taraf kitaplığı kullanmadan. StringBuilderTek dişli ortam için kullanın , aksi takdirde kullanın StringBuffer.

public static String getString( InputStream is) throws IOException {
    int ch;
    StringBuilder sb = new StringBuilder();
    while((ch = is.read()) != -1)
        sb.append((char)ch);
    return sb.toString();
}

3
Bu yöntemde hiçbir kodlama uygulanmamıştır. Diyelim ki InputStream'den alınan veriler UTF-8 kullanılarak kodlandı, çıkış yanlış olacak. Bunu düzeltmek için in = new InputStreamReader(inputStream)ve kullanabilirsiniz (char)in.read().
Frederic Leitenberger

2
ve bellek yetersizliği; Bunu daha önce büyük bir girişte kullanmayı denediğime inanıyorum ve StringBuilder hafızası
bitti

1
Bir char [] tamponu kullanan ve daha verimli olan ve karakter setiyle ilgilenen benzer bir cevap daha vardır.
Guillaume Perrot

14

Bayt dizisi arabelleklerini kullanarak yalnızca JDK kullanarak bunu nasıl yapacağınız aşağıda açıklanmıştır. Aslında bu ortak IOUtils.copy()yöntemlerin hepsi böyle çalışır. Sen değiştirebilirsiniz byte[]ile char[]bir kopyalama eğer Readeryerine ait InputStream.

import java.io.ByteArrayOutputStream;
import java.io.InputStream;

...

InputStream is = ....
ByteArrayOutputStream baos = new ByteArrayOutputStream(8192);
byte[] buffer = new byte[8192];
int count = 0;
try {
  while ((count = is.read(buffer)) != -1) {
    baos.write(buffer, 0, count);
  }
}
finally {
  try {
    is.close();
  }
  catch (Exception ignore) {
  }
}

String charset = "UTF-8";
String inputStreamAsString = baos.toString(charset);

1
Lütfen neyi başarmaya çalıştığınıza dair bir açıklama yapın.
Ragunath Jawahar

14

Kotlin kullanıcıları basitçe:

println(InputStreamReader(is).readText())

buna karşılık

readText()

Kotlin standart kütüphanesinin yerleşik genişletme yöntemidir.


Bu aslında doğru değil çünkü akışı kapatmıyor. Ben tavsiye ederim is.bufferedReader().use { it.readText() }.
Maksimum

9

JDK'daki en kolay yol, aşağıdaki kod sniplet'leri kullanmaktır.

String convertToString(InputStream in){
    String resource = new Scanner(in).useDelimiter("\\Z").next();
    return resource;
}

7

İşte tüm satırları toplamak için yeni Stream API'yi kullanan Java 8 tabanlı çözümüm :InputStream

public static String toString(InputStream inputStream) {
    BufferedReader reader = new BufferedReader(
        new InputStreamReader(inputStream));
    return reader.lines().collect(Collectors.joining(
        System.getProperty("line.separator")));
}

1
Daha önce yayınlanan tüm cevapları gerçekten okumadığınız anlaşılıyor. Stream API sürümü zaten en az iki kez buradaydı .
Tagir Valeev

Tüm çözümlere baktım, ama uygun bulmadım. Kısa bir açıklama ile iki satır kesin sundu buluyorum. Diğer çözeltiden try-catch-bloğu örneğin asla kullanılmaz. Ama sen haklısın. Pek çok
cevapla

1
Orijinal dosyayı okumuyorsunuz, dosyanın sahip olduğu satır sonlarını işletim sisteminin sahip olduğu satır sonlarına dönüştürüyorsunuz, muhtemelen dosya içeriğini değiştiriyorsunuz.
Christian Hujer

7

Açısından reduceve concatJava 8'deki gibi ifade edilebilir:

String fromFile = new BufferedReader(new   
InputStreamReader(inputStream)).lines().reduce(String::concat).get();

1
Delicesine yavaş olacak.
Tagir Valeev

İlginç, neden? Açıklayabilir misiniz?
libnull-dev

1
StringBuilder kullanmak yerine döngüde dizeleri birleştirmek neden kötü bir fikir olduğunu bilmiyor musunuz?
Tagir Valeev

Haklısın. StringBuilderdaha verimli olabilir. Kontrol edeceğim, ama asıl amacım değişmez ile daha işlevsel bir yaklaşım göstermekti String.
libnull-dev

Fonksiyonel yaklaşımlar serindir ancak genellikle çok verimsizdir.
Lluis Martinez

4

Akışı kapatan ve hala bir IOException özel durumu oluşturan JDK 7/8 yanıtı:

StringBuilder build = new StringBuilder();
byte[] buf = new byte[1024];
int length;
try (InputStream is = getInputStream()) {
  while ((length = is.read(buf)) != -1) {
    build.append(new String(buf, 0, length));
  }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.