Usando inputStream.available ()
É sempre aceitável que System.in.available () retorne 0.
Eu descobri o contrário - ele sempre retorna o melhor valor para o número de bytes disponíveis. Javadoc para InputStream.available()
:
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.
Uma estimativa é inevitável devido ao tempo / estabilidade. A figura pode ser uma subestimação pontual porque novos dados estão chegando constantemente. No entanto, ele sempre "alcança" a próxima chamada - deve ser responsável por todos os dados recebidos, exceto pelos que chegam exatamente no momento da nova chamada. Retornar permanentemente 0 quando houver dados falha na condição acima.
Primeira advertência: as subclasses de concreto do InputStream são responsáveis pela disponibilidade ()
InputStream
é uma classe abstrata. Não possui fonte de dados. Não faz sentido ter dados disponíveis. Portanto, o javadoc para available()
também declara:
The available method for class InputStream always returns 0.
This method should be overridden by subclasses.
E, de fato, as classes concretas do fluxo de entrada substituem available (), fornecendo valores significativos, não 0s constantes.
Segunda Advertência: Certifique-se de usar retorno de carro ao digitar entrada no Windows.
Se estiver usando System.in
, seu programa só recebe entrada quando seu shell de comando o entrega. Se você estiver usando redirecionamentos de arquivo / pipes (por exemplo, somefile> java myJavaApp ou algum comando | java myJavaApp), os dados de entrada geralmente são entregues imediatamente. No entanto, se você digitar manualmente a entrada, a transferência de dados poderá ser atrasada. Por exemplo, com o shell do cmd.exe do windows, os dados são armazenados em buffer no shell do cmd.exe. Os dados são passados apenas para o programa java em execução após retorno de carro (control-m ou <enter>
). Essa é uma limitação do ambiente de execução. Obviamente, InputStream.available () retornará 0 enquanto o shell armazenar em buffer os dados - esse é o comportamento correto; não há dados disponíveis nesse ponto. Assim que os dados estiverem disponíveis no shell, o método retornará um valor> 0. NB: Cygwin usa cmd.
Solução mais simples (sem bloqueio, portanto, não é necessário tempo limite)
Apenas use isto:
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.
Ou equivalente,
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);
}
Solução mais rica (preenche o buffer no máximo dentro do período de tempo limite)
Declare isso:
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;
}
Então use isto:
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.
is.available() > 1024
essa sugestão falhar. Certamente existem fluxos que retornam zero. SSLSockets, por exemplo, até recentemente. Você não pode confiar nisso.