Java: accessing a List of Strings as an InputStream

前端 未结 7 1551
情深已故
情深已故 2021-02-05 11:24

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

InputStream in = new XyzInputStream( List         


        
相关标签:
7条回答
  • 2021-02-05 11:43

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

    0 讨论(0)
  • 2021-02-05 11:52

    You can create some kind of 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);
            }
        }
    }    
    
    0 讨论(0)
  • 2021-02-05 11:53

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

    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:

    
    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.

    0 讨论(0)
  • 2021-02-05 11:57

    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", "", "\n")).getBytes();
    
    InputStream inputStream = new ByteArrayInputStream(bytes);
    
    0 讨论(0)
  • 2021-02-05 11:58

    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);
    }
    
    0 讨论(0)
  • 2021-02-05 12:00

    You can read from a ByteArrayOutputStream and you can create your source byte[] array using 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 StringReader might be better.

    0 讨论(0)
提交回复
热议问题