Java:将字符串列表作为 InputStream 访问

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9837754/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 08:24:04  来源:igfitidea点击:

Java: accessing a List of Strings as an InputStream

javajava-io

提问by Marc Polizzi

Is there any way InputStreamwrapping a list of UTF-8 String? I'd like to do something like:

有没有办法InputStream包装一个 UTF-8 列表String?我想做类似的事情:

InputStream in = new XyzInputStream( List<String> lines )

采纳答案by benmmurphy

You can concatenate all the lines together to create a String then convert it to a byte array using String#getBytesand pass it into ByteArrayInputStream. However this is not the most efficient way of doing it.

您可以将所有行连接在一起以创建一个字符串,然后使用将其转换为字节数组String#getBytes并将其传递给ByteArrayInputStream。然而,这并不是最有效的方法。

回答by Dave Webb

You can read from a ByteArrayOutputStreamand you can create your source byte[]array using a ByteArrayInputStream.

您可以从 a 读取ByteArrayOutputStream,也可以byte[]使用 a创建源数组ByteArrayInputStream

So create the array as follows:

所以创建数组如下:

 List<String> source = new ArrayList<String>();
 source.add("one");
 source.add("two");
 source.add("three");
 ByteArrayOutputStream baos = new ByteArrayOutputStream();

 for (String line : source) {
   baos.write(line.getBytes());
 }

 byte[] bytes = baos.toByteArray();

And reading from it is as simple as:

从中阅读就像这样简单:

 InputStream in = new ByteArrayInputStream(bytes);

Alternatively, depending on what you're trying to do, a StringReadermight be better.

或者,根据您尝试执行的操作,aStringReader可能更好。

回答by Jon

In short, no, there is no way of doing this using existing JDK classes. You could, however, implement your own InputStreamthat read from a List of Strings.

简而言之,不,使用现有的 JDK 类无法做到这一点。但是,您可以实现自己的从字符串列表中读取的InputStream

EDIT: Dave Web has an answer above, which I think is the way to go. If you need a reusable class, then something like this might do:

编辑:Dave Web 上面有一个答案,我认为这是要走的路。如果你需要一个可重用的类,那么这样的事情可能会做:


public class StringsInputStream<T extends Iterable<String>> extends InputStream {

   private ByteArrayInputStream bais = null;

   public StringsInputStream(final T strings) throws IOException {
      ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
      for (String line : strings) {
         outputStream.write(line.getBytes());
      }
      bais = new ByteArrayInputStream(outputStream.toByteArray());
   }

   @Override
   public int read() throws IOException {
      return bais.read();
   }

   @Override
   public int read(byte[] b) throws IOException {
      return bais.read(b);
   }

   @Override
   public int read(byte[] b, int off, int len) throws IOException {
      return bais.read(b, off, len);
   }

   @Override
   public long skip(long n) throws IOException {
      return bais.skip(n);
   }

   @Override
   public int available() throws IOException {
      return bais.available();
   }

   @Override
   public void close() throws IOException {
      bais.close();
   }

   @Override
   public synchronized void mark(int readlimit) {
      bais.mark(readlimit);
   }

   @Override
   public synchronized void reset() throws IOException {
      bais.reset();
   }

   @Override
   public boolean markSupported() {
      return bais.markSupported();
   }

   public static void main(String[] args) throws Exception {
      List source = new ArrayList();
      source.add("foo ");
      source.add("bar ");
      source.add("baz");

      StringsInputStream<List<String>> in = new StringsInputStream<List<String>>(source);

      int read = in.read();
      while (read != -1) {
         System.out.print((char) read);
         read = in.read();
      }
   }
}

This basically an adapter for ByteArrayInputStream.

这基本上是ByteArrayInputStream.

回答by Riddhish.Chaudhari

you can also do this way create a Serializable List

您也可以通过这种方式创建一个可序列化的列表

List<String> quarks = Arrays.asList(
      "up", "down", "strange", "charm", "top", "bottom"
    );

//serialize the List
//note the use of abstract base class references

try{
  //use buffering
  OutputStream file = new FileOutputStream( "quarks.ser" );
  OutputStream buffer = new BufferedOutputStream( file );
  ObjectOutput output = new ObjectOutputStream( buffer );
  try{
    output.writeObject(quarks);
  }
  finally{
    output.close();
  }
}  
catch(IOException ex){
  fLogger.log(Level.SEVERE, "Cannot perform output.", ex);
}

//deserialize the quarks.ser file
//note the use of abstract base class references

try{
  //use buffering
  InputStream file = new FileInputStream( "quarks.ser" );
  InputStream buffer = new BufferedInputStream( file );
  ObjectInput input = new ObjectInputStream ( buffer );
  try{
    //deserialize the List
    List<String> recoveredQuarks = (List<String>)input.readObject();
    //display its data
    for(String quark: recoveredQuarks){
      System.out.println("Recovered Quark: " + quark);
    }
  }
  finally{
    input.close();
  }
}
catch(ClassNotFoundException ex){
  fLogger.log(Level.SEVERE, "Cannot perform input. Class not found.", ex);
}
catch(IOException ex){
  fLogger.log(Level.SEVERE, "Cannot perform input.", ex);
}

回答by benmmurphy

You can do something similar to this:

你可以做类似的事情:

https://commons.apache.org/sandbox/flatfile/xref/org/apache/commons/flatfile/util/ConcatenatedInputStream.html

https://commons.apache.org/sandbox/flatfile/xref/org/apache/commons/flatfile/util/ConcatenatedInputStream.html

It just implements the read() method of InputStream and has a list of InputStreams it is concatenating. Once it reads an EOF it starts reading from the next InputStream. Just convert the Strings to ByteArrayInputStreams.

它只是实现了 InputStream 的 read() 方法,并有一个它正在连接的 InputStreams 列表。一旦它读取一个 EOF,它就会从下一个 InputStream 开始读取。只需将字符串转换为 ByteArrayInputStreams。

回答by Mike Shauneu

You can create some kind of IterableInputStream

您可以创建某种 IterableInputStream

public class IterableInputStream<T> extends InputStream {

    public static final int EOF = -1;

    private static final InputStream EOF_IS = new InputStream() {
        @Override public int read() throws IOException {
            return EOF;
        }
    };

    private final Iterator<T> iterator;
    private final Function<T, byte[]> mapper;

    private InputStream current;

    public IterableInputStream(Iterable<T> iterable, Function<T, byte[]> mapper) {
        this.iterator = iterable.iterator();
        this.mapper = mapper;
        next();
    }

    @Override
    public int read() throws IOException {
        int n = current.read();
        while (n == EOF && current != EOF_IS) {
            next();
            n = current.read();
        }
        return n;
    }

    private void next() {
        current = iterator.hasNext() 
            ? new ByteArrayInputStream(mapper.apply(iterator.next())) 
            : EOF_IS;
    }
}

To use it

使用它

public static void main(String[] args) throws IOException {
    Iterable<String> strings = Arrays.asList("1", "22", "333", "4444");
    try (InputStream is = new IterableInputStream<String>(strings, String::getBytes)) {
        for (int b = is.read(); b != -1; b = is.read()) {
            System.out.print((char) b);
        }
    }
}    

回答by freedev

In my case I had to convert a list of string in the equivalent file (with a line feed for each line).

在我的情况下,我必须转换等效文件中的字符串列表(每行都有一个换行符)。

This was my solution:

这是我的解决方案:

List<String> inputList = Arrays.asList("line1", "line2", "line3");

byte[] bytes = inputList.stream().collect(Collectors.joining("\n")).getBytes();

InputStream inputStream = new ByteArrayInputStream(bytes);