Làm cách nào để lấy java.io.InputStream từ java.lang.String?


95

Tôi có một Stringmà tôi muốn sử dụng như một InputStream. Trong Java 1.0, bạn có thể sử dụng java.io.StringBufferInputStream, nhưng điều đó đã xảy ra @Deprecrated(có lý do chính đáng - bạn không thể chỉ định mã hóa bộ ký tự):

Lớp này không chuyển đổi đúng các ký tự thành byte. Kể từ JDK 1.1, cách ưu tiên để tạo luồng từ một chuỗi là thông qua StringReader lớp.

Bạn có thể tạo một java.io.Readervới java.io.StringReader, nhưng không có bộ điều hợp nào để lấy Readervà tạo một InputStream.

Tôi đã tìm thấy một lỗi cổ xưa yêu cầu một sự thay thế phù hợp, nhưng không có thứ gì tồn tại - theo như tôi có thể nói.

Cách giải quyết được đề xuất của oft là sử dụng java.lang.String.getBytes()làm đầu vào cho java.io.ByteArrayInputStream:

public InputStream createInputStream(String s, String charset)
    throws java.io.UnsupportedEncodingException {

    return new ByteArrayInputStream(s.getBytes(charset));
}

nhưng điều đó có nghĩa là hiện thực hóa toàn bộ Stringtrong bộ nhớ dưới dạng một mảng byte và đánh bại mục đích của một luồng. Trong hầu hết các trường hợp, đây không phải là vấn đề lớn, nhưng tôi đang tìm kiếm thứ gì đó có thể duy trì ý định của một luồng - rằng càng ít dữ liệu càng tốt được (lại) hiện thực hóa trong bộ nhớ.

Câu trả lời:


78

Cập nhật: Câu trả lời này chính xác là những gì OP không muốn. Vui lòng đọc các câu trả lời khác.

Đối với những trường hợp khi chúng tôi không quan tâm đến việc dữ liệu được tái hiện trong bộ nhớ, vui lòng sử dụng:

new ByteArrayInputStream(str.getBytes("UTF-8"))

3
Giải pháp được đề xuất bởi câu trả lời này đã được dự đoán, suy tính và bác bỏ câu hỏi. Vì vậy, theo tôi, câu trả lời này nên được xóa.
Mike Nakis

1
Bạn có thể đúng. Ban đầu tôi đưa ra nhận xét có lẽ vì nó không phải là câu trả lời thực sự cho câu hỏi của OP.
Andres Riofrio,

28
Là một du khách đến đây vì tiêu đề câu hỏi, tôi rất vui vì câu trả lời này ở đây. Vì vậy: Vui lòng không xóa câu trả lời này. Nhận xét ở đầu "Câu trả lời này chính xác là điều OP không muốn. Vui lòng đọc các câu trả lời khác." là đủ.
Yaakov Belch

10
Đối với java7:new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8))
chậm

19

Nếu bạn không ngại sự phụ thuộc vào gói commons-io , thì bạn có thể sử dụng phương thức IOUtils.toInputStream (Chuỗi văn bản) .


11
Trong trường hợp đó, bạn thêm một phụ thuộc không có tác dụng gì khác ngoài việc `` trả về ByteArrayInputStream mới '(input.getBytes ());' Điều đó có thực sự đáng để phụ thuộc? Thành thật mà nói, không - không phải vậy.
whaefelinger

3
Đúng, ngoài ra nó chính xác là cách giải quyết mà op không nên sử dụng vì anh ấy không muốn "hiện thực hóa chuỗi vào bộ nhớ" đã chọn chuỗi được thực hiện ở một nơi khác trong hệ thống :)
Fotis Paraskevopoulos

Chúng tôi có bất kỳ thư viện nào chuyển đổi đối tượng tùy chỉnh thành nguồn của luồng đầu vào; một cái gì đó như IOUtils.toInputStream (đối tượng MyObject)?
nawazish-stackoverflow

5

Có một bộ điều hợp từ Apache Commons-IO chuyển đổi từ Reader sang InputStream, được đặt tên là ReaderInputStream .

Mã ví dụ:

@Test
public void testReaderInputStream() throws IOException {
    InputStream inputStream = new ReaderInputStream(new StringReader("largeString"), StandardCharsets.UTF_8);
    Assert.assertEquals("largeString", IOUtils.toString(inputStream, StandardCharsets.UTF_8));
}

Tham khảo: https://stackoverflow.com/a/27909221/5658642


3

Theo suy nghĩ của tôi, cách dễ nhất để làm điều này là đẩy dữ liệu qua Writer:

public class StringEmitter {
  public static void main(String[] args) throws IOException {
    class DataHandler extends OutputStream {
      @Override
      public void write(final int b) throws IOException {
        write(new byte[] { (byte) b });
      }
      @Override
      public void write(byte[] b) throws IOException {
        write(b, 0, b.length);
      }
      @Override
      public void write(byte[] b, int off, int len)
          throws IOException {
        System.out.println("bytecount=" + len);
      }
    }

    StringBuilder sample = new StringBuilder();
    while (sample.length() < 100 * 1000) {
      sample.append("sample");
    }

    Writer writer = new OutputStreamWriter(
        new DataHandler(), "UTF-16");
    writer.write(sample.toString());
    writer.close();
  }
}

Việc triển khai JVM mà tôi đang sử dụng dữ liệu được đẩy qua 8K khối, nhưng bạn có thể có một số ảnh hưởng đến kích thước bộ đệm bằng cách giảm số lượng ký tự được viết cùng một lúc và gọi tuôn ra.


Một giải pháp thay thế cho việc viết trình bao bọc CharsetEncoder của riêng bạn để sử dụng Writer để mã hóa dữ liệu, mặc dù việc làm đúng là điều khó khăn. Đây phải là một triển khai đáng tin cậy (nếu không hiệu quả):

/** Inefficient string stream implementation */
public class StringInputStream extends InputStream {

  /* # of characters to buffer - must be >=2 to handle surrogate pairs */
  private static final int CHAR_CAP = 8;

  private final Queue<Byte> buffer = new LinkedList<Byte>();
  private final Writer encoder;
  private final String data;
  private int index;

  public StringInputStream(String sequence, Charset charset) {
    data = sequence;
    encoder = new OutputStreamWriter(
        new OutputStreamBuffer(), charset);
  }

  private int buffer() throws IOException {
    if (index >= data.length()) {
      return -1;
    }
    int rlen = index + CHAR_CAP;
    if (rlen > data.length()) {
      rlen = data.length();
    }
    for (; index < rlen; index++) {
      char ch = data.charAt(index);
      encoder.append(ch);
      // ensure data enters buffer
      encoder.flush();
    }
    if (index >= data.length()) {
      encoder.close();
    }
    return buffer.size();
  }

  @Override
  public int read() throws IOException {
    if (buffer.size() == 0) {
      int r = buffer();
      if (r == -1) {
        return -1;
      }
    }
    return 0xFF & buffer.remove();
  }

  private class OutputStreamBuffer extends OutputStream {

    @Override
    public void write(int i) throws IOException {
      byte b = (byte) i;
      buffer.add(b);
    }

  }

}

2

Chà, một cách khả thi là:

  • Tạo một PipedOutputStream
  • Đưa nó vào một PipedInputStream
  • Bao OutputStreamWriterquanh PipedOutputStream(bạn có thể chỉ định mã hóa trong hàm tạo)
  • Et voilá, bất cứ điều gì bạn viết vào OutputStreamWritercó thể được đọc từ PipedInputStream!

Tất nhiên, điều này có vẻ như là một cách khá khó hiểu để làm điều đó, nhưng ít nhất nó là một cách.


1
Thật thú vị ... tất nhiên, với giải pháp này, tôi tin rằng bạn sẽ hiện thực hóa toàn bộ chuỗi trong bộ nhớ, hoặc bị chết đói trên chuỗi đọc. Vẫn hy vọng rằng có một triển khai thực sự ở đâu đó.
Jared Oberhaus

5
Bạn phải cẩn thận với Luồng Piped (Đầu vào | Đầu ra). Theo tài liệu: "... Không nên cố gắng sử dụng cả hai đối tượng từ một luồng duy nhất, vì nó có thể làm tắc nghẽn luồng ..." java.sun.com/j2se/1.4.2/docs/api/java/ io / PipedInputStream.html
Bryan Kyle

1

Một giải pháp là cuộn của riêng bạn, tạo một InputStreamtriển khai có thể sẽ sử dụng java.nio.charset.CharsetEncoderđể mã hóa từng charhoặc từng đoạn chars thành một mảng byte cho những trường hợp InputStreamcần thiết.


1
Làm mọi thứ một nhân vật tại một thời điểm là tốn kém. Đó là lý do tại sao chúng tôi có "trình vòng lặp phân đoạn" như InputStream cho phép chúng tôi đọc bộ đệm tại một thời điểm.
Tom Hawtin - đường chuyền vào

Tôi đồng ý với Tom - bạn thực sự không muốn làm nhân vật này cùng một lúc.
Eddie

1
Trừ khi dữ liệu thực sự nhỏ và những thứ khác (ví dụ: độ trễ mạng) mất nhiều thời gian hơn. Vậy thì không thành vấn đề. :)
Andres Riofrio

0

Bạn có thể nhờ thư viện org.hsqldb.lib trợ giúp.

public StringInputStream(String paramString)
  {
    this.str = paramString;
    this.available = (paramString.length() * 2);
  }

1
Nói chung, các câu hỏi hữu ích hơn nhiều nếu chúng bao gồm lời giải thích về những gì mã dự định làm.
Peter

-1

Tôi biết đây là một câu hỏi cũ nhưng hôm nay tôi cũng gặp phải vấn đề tương tự và đây là giải pháp của tôi:

public static InputStream getStream(final CharSequence charSequence) {
 return new InputStream() {
  int index = 0;
  int length = charSequence.length();
  @Override public int read() throws IOException {
   return index>=length ? -1 : charSequence.charAt(index++);
  }
 };
}
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.