Java: доступ к списку строк как InputStream

Есть ли способ, которым InputStream обертывает список String UTF-8? Я хотел бы сделать что-то вроде:

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

Ответ 1

Вы можете объединить все строки вместе, чтобы создать String, а затем преобразовать его в массив байтов, используя String#getBytes и передать его в ByteArrayInputStream. Однако это не самый эффективный способ сделать это.

Ответ 2

Вы можете читать из ByteArrayOutputStream и создавать свой исходный массив byte[] с помощью ByteArrayInputStream.

Итак, создайте массив следующим образом:

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

И читать из него так же просто, как:

 InputStream in = new ByteArrayInputStream(bytes);

Кроме того, в зависимости от того, что вы пытаетесь сделать, StringReader может быть лучше.

Ответ 3

Короче говоря, нет, нет никакого способа сделать это, используя существующие классы JDK. Однако вы могли бы реализовать свой собственный InputStream, который читается из списка строк.

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

Это в основном адаптер для ByteArrayInputStream.

Ответ 4

вы также можете сделать это, создав Сериализуемый список

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

Ответ 5

Вы можете сделать что-то похожее на это:

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

Он просто реализует метод read() InputStream и имеет список InputStreams, который он объединяет. Когда он читает EOF, он начинает считывать из следующего InputStream. Просто преобразуйте строки в ByteArrayInputStreams.

Ответ 6

Вы можете создать какой-то 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;
    }
}

Использовать его

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

Ответ 7

В моем случае мне пришлось преобразовать список строк в эквивалентный файл (с переводом строки для каждой строки).

Это было мое решение:

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

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

InputStream inputStream = new ByteArrayInputStream(bytes);