具体来说,问题是写一个这样的方法:

int maybeRead(InputStream in, long timeout)

如果数据在 'timeout' 毫秒内可用,则返回值与 in.read() 相同,否则为 -2。在该方法返回之前,任何产生的线程都必须退出。

为了避免争论,这里的主题是 java.io.InputStream,如 Sun(任何 Java 版本)所记录的那样。请注意,这并不像看起来那么简单。以下是 Sun 文档直接支持的一些事实。
  • in.read() 方法可能是不可中断的。
  • 将 InputStream 包装在 Reader 或 InterruptibleChannel 中没有帮助,因为所有这些类都可以调用 InputStream 的方法。如果可以使用这些类,就可以编写一个直接在 InputStream 上执行相同逻辑的解决方案。
  • in.available() 返回 0 总是可以接受的。
  • in.close() 方法可能会阻塞或什么都不做。
  • 没有杀死另一个线程的通用方法。
  • 最佳答案

    使用 inputStream.available()



    我发现相反 - 它总是返回可用字节数的最佳值。 InputStream.available()的Javadoc:

    Returns an estimate of the number of bytes that can be read (or skipped over)
    from this input stream without blocking by the next invocation of a method for
    this input stream.
    

    由于时间/过时,估计是不可避免的。这个数字可能是一次性的低估,因为新数据不断到来。然而,它总是在下一次调用时“ catch ”——它应该考虑所有到达的数据,除非在新调用的那一刻到达。当有数据不符合上述条件时,永久返回 0。

    第一个警告:InputStream 的具体子类负责 available()
    InputStream 是一个抽象类。它没有数据源。拥有可用数据是没有意义的。因此,available() 的 javadoc 也指出:
    The available method for class InputStream always returns 0.
    
    This method should be overridden by subclasses.
    

    事实上,具体的输入流类确实覆盖了 available(),提供了有意义的值,而不是常量 0。

    第二个警告:确保在 Windows 中输入时使用回车。

    如果使用 System.in ,则您的程序仅在您的命令 shell 程序移交时接收输入。如果您使用文件重定向/管道(例如 somefile > java myJavaApp 或 somecommand | java myJavaApp ),则输入数据通常会立即移交。但是,如果您手动输入,则数据切换可能会延迟。例如。使用 windows cmd.exe shell,数据缓存在 cmd.exe shell 中。数据仅在回车(control-m 或 <enter> )后传递给正在执行的 java 程序。这是执行环境的限制。当然,只要 shell 缓冲数据, InputStream.available() 就会返回 0 - 这是正确的行为;那时没有可用数据。一旦 shell 中的数据可用,该方法就会返回一个 > 0 的值。注意:Cygwin 也使用 cmd.exe。

    最简单的解决方案(无阻塞,因此不需要超时)

    只需使用这个:
        byte[] inputData = new byte[1024];
        int result = is.read(inputData, 0, is.available());
        // result will indicate number of bytes read; -1 for EOF with no data read.
    

    或等效地,
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in, Charset.forName("ISO-8859-1")),1024);
        // ...
             // inside some iteration / processing logic:
             if (br.ready()) {
                 int readCount = br.read(inputData, bufferOffset, inputData.length-bufferOffset);
             }
    

    更丰富的解决方案(在超时时间内最大程度地填充缓冲区)

    声明如下:
    public static int readInputStreamWithTimeout(InputStream is, byte[] b, int timeoutMillis)
         throws IOException  {
         int bufferOffset = 0;
         long maxTimeMillis = System.currentTimeMillis() + timeoutMillis;
         while (System.currentTimeMillis() < maxTimeMillis && bufferOffset < b.length) {
             int readLength = java.lang.Math.min(is.available(),b.length-bufferOffset);
             // can alternatively use bufferedReader, guarded by isReady():
             int readResult = is.read(b, bufferOffset, readLength);
             if (readResult == -1) break;
             bufferOffset += readResult;
         }
         return bufferOffset;
     }
    

    然后使用这个:
        byte[] inputData = new byte[1024];
        int readCount = readInputStreamWithTimeout(System.in, inputData, 6000);  // 6 second timeout
        // readCount will indicate number of bytes read; -1 for EOF with no data read.
    

    关于java - 是否可以从带有超时的 InputStream 读取?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/804951/

    10-13 02:02