Java — How to read an unknown number of bytes from an inputStream (socket/socketServer)?

后端 未结 11 1000
梦如初夏
梦如初夏 2020-12-15 07:42

Looking to read in some bytes over a socket using an inputStream. The bytes sent by the server may be of variable quantity, and the client doesn\'t know in advance the lengt

相关标签:
11条回答
  • 2020-12-15 08:28

    Here is a simpler example using ByteArrayOutputStream...

            socketInputStream = socket.getInputStream();
            int expectedDataLength = 128; //todo - set accordingly/experiment. Does not have to be precise value.
            ByteArrayOutputStream baos = new ByteArrayOutputStream(expectedDataLength);
            byte[] chunk = new byte[expectedDataLength];
            int numBytesJustRead;
            while((numBytesJustRead = socketInputStream.read(chunk)) != -1) {
                baos.write(chunk, 0, numBytesJustRead);
            }
            return baos.toString("UTF-8");
    

    However, if the server does not return a -1, you will need to detect the end of the data some other way - e.g., maybe the returned content always ends with a certain marker (e.g., ""), or you could possibly solve using socket.setSoTimeout(). (Mentioning this as it is seems to be a common problem.)

    0 讨论(0)
  • 2020-12-15 08:31

    Without re-inventing the wheel, using Apache Commons:

    IOUtils.toByteArray(inputStream);
    

    For example, complete code with error handling:

        public static byte[] readInputStreamToByteArray(InputStream inputStream) {
        if (inputStream == null) {
            // normally, the caller should check for null after getting the InputStream object from a resource
            throw new FileProcessingException("Cannot read from InputStream that is NULL. The resource requested by the caller may not exist or was not looked up correctly.");
        }
        try {
            return IOUtils.toByteArray(inputStream);
        } catch (IOException e) {
            throw new FileProcessingException("Error reading input stream.", e);
        } finally {
            closeStream(inputStream);
        }
    }
    
    private static void closeStream(Closeable closeable) {
        try {
            if (closeable != null) {
                closeable.close();
            }
        } catch (Exception e) {
            throw new FileProcessingException("IO Error closing a stream.", e);
        }
    }
    

    Where FileProcessingException is your app-specific meaningful RT exception that will travel uninterrupted to your proper handler w/o polluting the code in between.

    0 讨论(0)
  • 2020-12-15 08:33

    Stream all Input data into Output stream. Here is working example:

        InputStream inputStream = null;
        byte[] tempStorage = new byte[1024];//try to read 1Kb at time
        int bLength;
        try{
    
            ByteArrayOutputStream outputByteArrayStream =  new ByteArrayOutputStream();     
            if (fileName.startsWith("http"))
                inputStream = new URL(fileName).openStream();
            else
                inputStream = new FileInputStream(fileName);            
    
            while ((bLength = inputStream.read(tempStorage)) != -1) {
                    outputByteArrayStream.write(tempStorage, 0, bLength);
            }
            outputByteArrayStream.flush();
            //Here is the byte array at the end
            byte[] finalByteArray = outputByteArrayStream.toByteArray();
            outputByteArrayStream.close();
            inputStream.close();
        }catch(Exception e){
            e.printStackTrace();
            if (inputStream != null) inputStream.close();
        }
    
    0 讨论(0)
  • 2020-12-15 08:34

    Either:

    1. Have the sender close the socket after transferring the bytes. Then at the receiver just keep reading until EOS.

    2. Have the sender prefix a length word as per Chris's suggestion, then read that many bytes.

    3. Use a self-describing protocol such as XML, Serialization, ...

    0 讨论(0)
  • 2020-12-15 08:35

    Assuming the sender closes the stream at the end of the data:

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    
    byte[] buf = new byte[4096];
    while(true) {
      int n = is.read(buf);
      if( n < 0 ) break;
      baos.write(buf,0,n);
    }
    
    byte data[] = baos.toByteArray();
    
    0 讨论(0)
提交回复
热议问题