Nhận một OutputStream thành một chuỗi


580

Cách tốt nhất để chuyển đầu ra từ java.io.OutputStream sang String trong Java là gì?

Nói rằng tôi có phương pháp:

  writeToStream(Object o, OutputStream out)

Mà ghi dữ liệu nhất định từ đối tượng vào luồng đã cho. Tuy nhiên, tôi muốn đưa đầu ra này vào Chuỗi dễ dàng nhất có thể.

Tôi đang xem xét viết một lớp như thế này (chưa được kiểm tra):

class StringOutputStream extends OutputStream {

  StringBuilder mBuf;

  public void write(int byte) throws IOException {
    mBuf.append((char) byte);
  }

  public String getString() {
    return mBuf.toString();
  }
}

Nhưng có cách nào tốt hơn không? Tôi chỉ muốn chạy thử nghiệm!


6
Bạn chỉ có byte ASCII? Bạn không cần Codepage?
Horcrux7

Trong trường hợp này, có. Tuy nhiên, điểm tốt - tôi đã không nghĩ về nó.
Adrian Mouat

Câu trả lời:


607

Tôi sẽ sử dụng một ByteArrayOutputStream. Và khi kết thúc, bạn có thể gọi:

new String( baos.toByteArray(), codepage );

hoặc tốt hơn:

baos.toString( codepage );

Đối với hàm Stringtạo, codepagecó thể là một Stringhoặc một thể hiện của java.nio.charset.Charset . Một giá trị có thể là java.nio.charset.St ChuẩnCharsets.UTF_8 .

Phương thức toString()chỉ chấp nhận Stringmột codepagetham số (đứng Java 8).


8
ByteArrayOutputStream không có phương thức toArray (); nó không có toByteArray (). Bạn có thể sửa câu trả lời không? Ngoài ra, tại sao không sử dụng baos.toString (String charsetName) sẽ đơn giản hơn một chút.
Jonik

35
Một bytearray chỉ là dữ liệu nhị phân. Vì văn bản (unicode) có thể được mã hóa nhị phân theo nhiều cách khác nhau, ByteArrayOutputStream cần biết mã hóa nào đã được sử dụng để mã hóa các byte, do đó nó có thể sử dụng cùng một mã hóa để giải mã lại byte thành một chuỗi. Đơn giản chỉ cần sử dụng toString mà không có đối số là không khôn ngoan vì bạn chỉ cần bỏ qua vấn đề thay vì giải quyết nó; Java sẽ sử dụng mã hóa nền tảng có thể đúng ... hoặc không. Về cơ bản là ngẫu nhiên. Bạn cần tìm ra mã hóa nào đã được sử dụng để viết văn bản thành byte và chuyển mã hóa đó sang toString.
Stijn de Witt

10
Chỉ cần làm rõ về codepage được tham chiếu ở đây: trong Java, bạn có thể sử dụng Charset.defaultCharset () hoặc Charset.forName ("bộ ký tự cụ thể"); Những gì làm việc cho tôi là: Chuỗi mới (baos.toByteArray (), Charset.defaultCharset ());
Wallace Brown

7
@WallaceBrown sử dụng defaultCharsetkhông tốt hơn là bỏ qua bộ ký tự hoàn toàn - bạn cần tìm hiểu xem nó là gì trước khi bạn sử dụngtoString
artbristol

4
StandardCharsets.UTF_8là a Charset, không phải a String. Hơn nữa, tham số được gọi charsetName, không codepage.
OrangeDog

46

Tôi thích thư viện IO Commons IO. Hãy xem phiên bản ByteArrayOutputStream của nó , có một toString(String enc)phương thức cũng như toByteArray(). Sử dụng các thành phần hiện có và đáng tin cậy như dự án Commons cho phép mã của bạn nhỏ hơn và dễ dàng mở rộng và tái sử dụng hơn.


10
Hãy tiết kiệm cho mình một năm cuộc đời và đọc qua tất cả các API phổ biến để khi bạn gặp sự cố, bạn có thể giải phóng một giải pháp thuộc sở hữu cộng đồng và đã được thử nghiệm đầy đủ.
Bob Herrmann

15
Hmm, tôi là một người dùng Apache Commons cuồng nhiệt, nhưng trong trường hợp này tôi không hiểu tại sao bạn nên sử dụng ByteArrayOutputStream của Commons thay vì java.io.ByteArrayOutputStream của JDK. Cái sau cũng cung cấp các phương thức toString (String charsetName) và toByteArray (). Quan tâm đến công phu?
Jonik

1
Vâng, vì bối cảnh ban đầu là một cách tốt hơn để truyền phát và trích xuất nội dung, tôi đã đưa vào ví dụ Commons IO vì nó bao gồm một phương thức 'write (InputStream)' cho một cơ chế nghi vấn / không xác định sau đó để điền vào OutputStream. Tôi cũng sẽ đi với JDK.
Joe Liversedge

23

Điều này làm việc độc đáo

OutputStream output = new OutputStream() {
    private StringBuilder string = new StringBuilder();

    @Override
    public void write(int b) throws IOException {
        this.string.append((char) b );
    }

    //Netbeans IDE automatically overrides this toString()
    public String toString() {
        return this.string.toString();
    }
};

gọi phương thức = >> marshaller.marshal( (Object) toWrite , (OutputStream) output);

sau đó để in chuỗi hoặc lấy nó chỉ cần tham chiếu chính luồng "đầu ra" Ví dụ, để in chuỗi ra ra console = >> System.out.println(output);

FYI: cuộc gọi phương thức của tôi marshaller.marshal(Object,Outputstream)là để làm việc với XML. Nó không liên quan đến chủ đề này.

Điều này rất lãng phí cho sử dụng sản xuất, có một cách quá nhiều chuyển đổi và nó hơi lỏng lẻo. Điều này chỉ được mã hóa để chứng minh với bạn rằng hoàn toàn có thể tạo OuputStream tùy chỉnh và xuất ra một chuỗi. Nhưng chỉ cần đi theo đường Horcrux7 và tất cả đều tốt chỉ với hai cuộc gọi phương thức.

Và thế giới sống vào một ngày khác ....


9
Chỉ cần truyền một byte thành char sẽ chỉ hoạt động trên ascii. Sử dụng ByteArrayOutputStream như Horcrux7
Dave Ray

2
Đồng ý với Dave Ray. Bạn không thể cho rằng byte của bạn là ký tự ASCII. Bạn cần diễn giải các byte bằng cách sử dụng mã hóa. Sử dụng byteArrayOutputStream.toString ("UTF-8") hoặc Chuỗi mới (byteArrayOutputStream.toByteArray (), "UTF-8").
Martin Dow

16

Đây là những gì tôi đã làm:

Obj.writeToStream(toWrite, os);
try {
    String out = new String(os.toByteArray(), "UTF-8");
    assertTrue(out.contains("testString"));
} catch (UnsupportedEncondingException e) {
    fail("Caught exception: " + e.getMessage());
}

Trong đó os là a ByteArrayOutputStream.


2
@JavaJigs Tôi đã làm rõ điều này ở cuối câu trả lời của tôi gần 5 năm trước :)
Adrian Mouat

19
Xem xét thay thế "UTF-8"bằng StandardCharsets.UTF_8.
james.garriss

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.