Zaman aşımı ile bir InputStream'den okumak mümkün müdür?


148

Özellikle sorun şu şekilde bir yöntem yazmaktır:

int maybeRead(InputStream in, long timeout)

Burada, veriler 'zaman aşımı' milisaniye içinde mevcutsa, dönüş değeri in.read () ile aynıdır; aksi takdirde -2. Yöntem geri dönmeden önce, ortaya çıkan tüm iş parçacıkları çıkmalıdır.

Tartışmalardan kaçınmak için, Sun tarafından belgelendiği üzere java.io.InputStream buradaki konu (herhangi bir Java sürümü). Lütfen bunun göründüğü kadar basit olmadığını unutmayın. Aşağıda, doğrudan Sun'ın dokümantasyonuyla desteklenen bazı gerçekler bulunmaktadır.

  1. İn.read () yöntemi kesintiye uğramayabilir.

  2. Bir Reader veya InterruptibleChannel'da InputStream'i sarmalamak yardımcı olmaz, çünkü bu sınıfların yapabileceği tek şey InputStream yöntemlerini çağırmaktır. Bu sınıfları kullanmak mümkün olsaydı, aynı mantığı doğrudan InputStream üzerinde çalıştıran bir çözüm yazmak mümkün olurdu.

  3. İn.available () işlevinin 0 döndürmesi her zaman kabul edilebilir.

  4. İn.close () yöntemi engelleyebilir veya hiçbir şey yapmayabilir.

  5. Başka bir ipliği öldürmenin genel bir yolu yoktur.

Yanıtlar:


85

İnputStream.available () kullanma

System.in.available () 'nın 0 döndürmesi her zaman kabul edilebilir.

Bunun tersini buldum - her zaman mevcut bayt sayısı için en iyi değeri döndürür. Javadoc için 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.

Zamanlama / bayatlık nedeniyle bir tahmin kaçınılmazdır. Rakam, bir defaya mahsus eksik tahmin olabilir, çünkü sürekli yeni veriler gelmektedir. Ancak, her zaman bir sonraki aramada "yetişir" - gelen tüm verileri hesaba katmalı, yeni arama anında gelen verileri engellemelidir. Veri olduğunda kalıcı olarak 0 döndürmek yukarıdaki koşulda başarısız olur.

İlk Uyarı: InputStream'in somut alt sınıfları mevcutlardan sorumludur ()

InputStreamsoyut bir sınıftır. Veri kaynağı yoktur. Mevcut verilere sahip olmasının anlamı yok. Bu nedenle, javadoc available()ayrıca şunları belirtir:

The available method for class InputStream always returns 0.

This method should be overridden by subclasses.

Ve aslında, somut girdi akışı sınıfları available () 'u geçersiz kılar ve sabit 0'lar yerine anlamlı değerler sağlar.

İkinci Uyarı: Windows'ta giriş yazarken satır başı kullandığınızdan emin olun.

Kullanıyorsanız System.in, programınız yalnızca komut kabuğunuz onu verdiğinde girdi alır. Dosya yeniden yönlendirme / boruları kullanıyorsanız (örneğin, dosya> java myJavaApp veya bazı komutlar | java myJavaApp), bu durumda giriş verileri genellikle hemen teslim edilir. Ancak, girişi manuel olarak yazarsanız, veri aktarımı gecikebilir. Örneğin, windows cmd.exe kabuğunda veriler cmd.exe kabuğunda arabelleğe alınır. Veriler, yalnızca carriage-return (control-m veya <enter>) sonrasında yürütülen java programına aktarılır . Bu, yürütme ortamının bir sınırlamasıdır. Tabii ki, InputStream.available (), kabuk verileri tamponladığı sürece 0 döndürür - bu doğru davranış; o noktada mevcut veri yok. Veriler kabuktan elde edilir edilmez, yöntem> 0 değerini döndürür. Not: Cygwin cmd kullanır.

En basit çözüm (engelleme yok, bu nedenle zaman aşımı gerekmez)

Sadece şunu kullan:

    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.

Veya eşdeğer olarak,

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

Daha Zengin Çözüm (zaman aşımı süresi içinde tamponu en fazla doldurur)

Bunu beyan edin:

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

O zaman şunu kullan:

    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.

1
Eğer is.available() > 1024bu öneri başarısız olacaktır. Kesinlikle sıfır döndüren akışlar vardır. Örneğin yakın zamana kadar SSLSockets. Buna güvenemezsin.
Marquis of Lorne

'İs.available ()> 1024' durumu özellikle readLength aracılığıyla ele alınır.
Glen Best

Yorum SSLSockets yanlış - arabellekte veri yoksa kullanılabilir durumda 0 döndürür. Cevabıma göre. Javadoc: "Sokette arabelleğe alınmış bayt yoksa ve soket close kullanılarak kapatılmadıysa, o zaman available 0 değerini döndürür."
Glen Best

@GlenBest Yorumum yeniden SSLSocket yanlış değil. Yakın zamana kadar [vurgu] her zaman sıfır döndürüyordu. Şu andan bahsediyorsun. JSSE'nin tüm geçmişinden bahsediyorum ve 2002'de Java 1.4'e dahil edilmeden önce onunla çalıştım .
Marquis of Lorne

1
Bu aslında iyi bir cevap değil. 1) daha önce belirtildiği gibi, available () JVM, sürüm, işletim sistemi, uygulamalara bağlı olarak 0 döndürebilir. 2) Hatalı dosyalara erişmeye çalışıyorsanız, herhangi bir read () çağrısı asla geri dönmeyebilir (veya en azından makul bir zaman aşımı süresi içinde değil, bazıları 10 dakikadır). Bu yüzden bu çözümü kullanmak kötü bir fikir. Ian Jones'un yanıtı, doğru yazılırsa çok daha iyi ve daha okunaklı.
JayC667

66

Akışınızın bir soket tarafından desteklenmediğini varsayarsak (bu yüzden kullanamazsınız Socket.setSoTimeout()), bu tür problemleri çözmenin standart yolunun bir Future kullanmak olduğunu düşünüyorum.

Aşağıdaki yürütücüye ve akışlara sahip olduğumu varsayalım:

    ExecutorService executor = Executors.newFixedThreadPool(2);
    final PipedOutputStream outputStream = new PipedOutputStream();
    final PipedInputStream inputStream = new PipedInputStream(outputStream);

Bazı verileri yazan ve ardından son veri parçasını yazıp akışı kapatmadan önce 5 saniye bekleyen bir yazıcım var:

    Runnable writeTask = new Runnable() {
        @Override
        public void run() {
            try {
                outputStream.write(1);
                outputStream.write(2);
                Thread.sleep(5000);
                outputStream.write(3);
                outputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };
    executor.submit(writeTask);

Bunu okumanın normal yolu aşağıdaki gibidir. Okuma, veriler için süresiz olarak engellenecek ve bu 5 saniyede tamamlanır:

    long start = currentTimeMillis();
    int readByte = 1;
    // Read data without timeout
    while (readByte >= 0) {
        readByte = inputStream.read();
        if (readByte >= 0)
            System.out.println("Read: " + readByte);
    }
    System.out.println("Complete in " + (currentTimeMillis() - start) + "ms");

hangi çıktılar:

Read: 1
Read: 2
Read: 3
Complete in 5001ms

Yazarın yanıt vermemesi gibi daha temel bir sorun olsaydı, okuyucu sonsuza dek bloke ederdi. Okumayı ileride kaydırırsam, zaman aşımını şu şekilde kontrol edebilirim:

    int readByte = 1;
    // Read data with timeout
    Callable<Integer> readTask = new Callable<Integer>() {
        @Override
        public Integer call() throws Exception {
            return inputStream.read();
        }
    };
    while (readByte >= 0) {
        Future<Integer> future = executor.submit(readTask);
        readByte = future.get(1000, TimeUnit.MILLISECONDS);
        if (readByte >= 0)
            System.out.println("Read: " + readByte);
    }

hangi çıktılar:

Read: 1
Read: 2
Exception in thread "main" java.util.concurrent.TimeoutException
    at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:228)
    at java.util.concurrent.FutureTask.get(FutureTask.java:91)
    at test.InputStreamWithTimeoutTest.main(InputStreamWithTimeoutTest.java:74)

TimeoutException'ı yakalayabilir ve istediğim temizliği yapabilirim.


14
Peki ya engelleme ipliği ?! Uygulama sona erene kadar hafızada kalacak mı? Eğer haklıysam, bu sonsuz sayıda iş parçacığı oluşturabilir, uygulama ağır yüklüdür ve hatta daha fazla iş parçacığı meşgul ve engellenmiş havuzunuzu kullanmasını engelleyin. Yanılıyorsam lütfen beni düzeltin. Teşekkür ederim.
Muhammad Gelbana

4
Muhammad Gelbana, haklısın: bloke eden read () ileti dizisi çalışmaya devam ediyor ve bu tamam değil. Yine de bunu önlemenin bir yolunu buldum: zaman aşımı geldiğinde, giriş akışını çağıran iş parçacığından kapatın (benim durumumda giriş akışının geldiği android bluetooth soketini kapatırım). Bunu yaptığınızda, read () çağrısı hemen geri dönecektir .. Benim durumumda int okuma (bayt []) aşırı yüklemesini kullanıyorum ve bu hemen geri dönüyor. Belki int read () aşırı yüklemesi, ne döneceğini bilmediğim için bir IOException atar ... Aklıma uygun çözüm budur.
Emmanuel Touzery

5
Uygulama sona erene kadar okuma iş parçacığı bloke olarak kaldığı için -1.
Ortwin Angermeier

11
@ortang "TimeoutException'ı yakala ve her şeyi temizle ..." derken kastettiğim buydu. Örneğin, okuma iş parçacığını sonlandırmak isteyebilirim: ... catch (TimeoutException e) {executor.shutdownNow (); }
Ian Jones

12
executer.shutdownNowipliği öldürmeyecek. Hiçbir etkisi olmadan onu kesmeye çalışacaktır. Temizleme mümkün değil ve bu ciddi bir sorun.
Marko Topolnik

23

InputStream'iniz bir Soket tarafından destekleniyorsa, setSoTimeout kullanarak bir Soket zaman aşımı (milisaniye cinsinden) ayarlayabilirsiniz . Read () çağrısı belirtilen zaman aşımı süresi içinde engeli kaldırmazsa, bir SocketTimeoutException oluşturur.

Read () çağrısını yapmadan önce Soket üzerinde setSoTimeout'u çağırdığınızdan emin olun.


18

Sorun ifadesini körü körüne kabul etmek yerine sorgulardım. Yalnızca konsoldan veya ağ üzerinden zaman aşımına ihtiyacınız var. Eğer ikincisine sahipseniz Socket.setSoTimeout()ve HttpURLConnection.setReadTimeout()hangisi tam olarak gerekli olanı yapıyorsa, onları oluşturduğunuzda / edindiğinizde onları doğru bir şekilde ayarladığınız sürece. Tüm sahip olduğunuz InputStream olduğunda, uygulamada daha sonra keyfi bir noktaya bırakmak, çok garip bir uygulamaya yol açan zayıf tasarımdır.


10
Bir okumanın önemli bir süre için potansiyel olarak engellenebileceği başka durumlar da vardır; örneğin, bir teyp sürücüsünden, uzaktan bağlanmış bir ağ sürücüsünden veya arka ucunda bir teyp robotu olan bir HFS'den okurken. (Ancak cevabınızın asıl amacı doğrudur.)
Stephen C

1
Yorumunuz ve örnekler için @StephenC +1. Örneğinizden daha fazlasını eklemek için, basit bir durum soket bağlantılarının doğru yapıldığı, ancak verilerin DB'den getirileceği için okuma girişiminin engellendiği, ancak bir şekilde gerçekleşmediği (DB'nin yanıt vermediğini ve sorgu gittiğini varsayalım) Kilitli durumda). Bu senaryoda, soket üzerindeki okuma işlemini açık bir şekilde zaman aşımına uğratacak bir yola sahip olmanız gerekir.
sactiw

1
InputStream soyutlamasının tüm amacı, temelde yatan uygulama hakkında düşünmemektir. Gönderilen cevapların artıları ve eksileri hakkında tartışmak doğru. Ancak, sorun ifadesini sorgulamak tartışmaya yardımcı olmayacak
pellucide

2
InputStream bir akış üzerinde çalışır ve bloke eder, ancak bir zaman aşımı mekanizması sağlamaz. Dolayısıyla, InputStream soyutlaması uygun şekilde tasarlanmış bir soyutlama değildir. Bu nedenle bir akışta zaman aşımına uğramanın bir yolunu istemek çok fazla şey istemez. Yani soru, çok pratik bir soruna çözüm arıyor. Temeldeki uygulamaların çoğu engellenecektir. Bir derenin özü budur. Akışın diğer tarafı yeni verilerle hazır değilse Soketler, Dosyalar, Borular engellenir.
pellucide

2
@EJP. Bunu nasıl anladığını bilmiyorum. Sana katılmadım "Bir InputStream'de nasıl zaman aşımına uğrar" sorun ifadesi geçerlidir. Çerçeve, zaman aşımı için bir yol sağlamadığından, böyle bir soru sormak uygundur.
pellucide

7

Java NIO paketindeki sınıfları kullanmadım, ancak burada biraz yardımcı olabilecekleri görülüyor . Özellikle, java.nio.channels.Channels ve java.nio.channels.InterruptibleChannel .


2
+1: Yalnızca InputStream ile OP'nin istediğini yapmanın güvenilir bir yolu olduğuna inanmıyorum. Ancak, diğerleri arasında nio bu amaç için oluşturulmuştur.
Eddie

2
OP zaten temelde bunu dışladı. InputStreams doğası gereği engelleyicidir ve kesintiye uğramayabilir.
Marquis of Lorne

5

İşte System.in'den bir NIO FileChannel almanın ve soruda açıklanan sorunun özel bir durumu olan bir zaman aşımı kullanarak verilerin kullanılabilirliğini kontrol etmenin bir yolu. Konsolda çalıştırın, herhangi bir girdi yazmayın ve sonuçları bekleyin. Java 6 altında Windows ve Linux üzerinde başarıyla test edilmiştir.

import java.io.FileInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedByInterruptException;

public class Main {

    static final ByteBuffer buf = ByteBuffer.allocate(4096);

    public static void main(String[] args) {

        long timeout = 1000 * 5;

        try {
            InputStream in = extract(System.in);
            if (! (in instanceof FileInputStream))
                throw new RuntimeException(
                        "Could not extract a FileInputStream from STDIN.");

            try {
                int ret = maybeAvailable((FileInputStream)in, timeout);
                System.out.println(
                        Integer.toString(ret) + " bytes were read.");

            } finally {
                in.close();
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /* unravels all layers of FilterInputStream wrappers to get to the
     * core InputStream
     */
    public static InputStream extract(InputStream in)
            throws NoSuchFieldException, IllegalAccessException {

        Field f = FilterInputStream.class.getDeclaredField("in");
        f.setAccessible(true);

        while( in instanceof FilterInputStream )
            in = (InputStream)f.get((FilterInputStream)in);

        return in;
    }

    /* Returns the number of bytes which could be read from the stream,
     * timing out after the specified number of milliseconds.
     * Returns 0 on timeout (because no bytes could be read)
     * and -1 for end of stream.
     */
    public static int maybeAvailable(final FileInputStream in, long timeout)
            throws IOException, InterruptedException {

        final int[] dataReady = {0};
        final IOException[] maybeException = {null};
        final Thread reader = new Thread() {
            public void run() {                
                try {
                    dataReady[0] = in.getChannel().read(buf);
                } catch (ClosedByInterruptException e) {
                    System.err.println("Reader interrupted.");
                } catch (IOException e) {
                    maybeException[0] = e;
                }
            }
        };

        Thread interruptor = new Thread() {
            public void run() {
                reader.interrupt();
            }
        };

        reader.start();
        for(;;) {

            reader.join(timeout);
            if (!reader.isAlive())
                break;

            interruptor.start();
            interruptor.join(1000);
            reader.join(1000);
            if (!reader.isAlive())
                break;

            System.err.println("We're hung");
            System.exit(1);
        }

        if ( maybeException[0] != null )
            throw maybeException[0];

        return dataReady[0];
    }
}

İlginç bir şekilde, programı konsol yerine NetBeans 6.5 içinde çalıştırırken, zaman aşımı hiç çalışmıyor ve System.exit () çağrısı aslında zombi iş parçacıklarını öldürmek için gerekli. Olan, okuyucu iş parçacığının reader.interrupt () çağrısında engellemesidir (!). Başka bir test programı (burada gösterilmemiştir) ek olarak kanalı kapatmaya çalışır, ancak bu da çalışmaz.


mac os'da ne JDK 1.6 ne de JDK 1.7 ile çalışmaz. Kesme, yalnızca okuma sırasında dönüş tuşuna bastıktan sonra tanınır.
Mostowski Çöküşü

4

Jt'nin dediği gibi, NIO en iyi (ve doğru) çözümdür. Yine de bir InputStream ile takıldıysanız,

  1. Özel görevi InputStream'den okumak ve sonucu orijinal iş parçacığınızdan engellemeden okunabilen bir arabelleğe koymak olan bir iş parçacığı oluşturun. Akışın yalnızca bir örneğine sahipseniz bu iyi çalışmalıdır. Aksi takdirde, Thread sınıfındaki kullanımdan kaldırılmış yöntemleri kullanarak iş parçacığını öldürebilirsiniz, ancak bu kaynak sızıntılarına neden olabilir.

  2. Engellemeden okunabilen verileri belirtmek için isAvailable'a güvenebilirsiniz. Ancak bazı durumlarda (Soketler gibi), 0 dışında bir şeyi bildirmek için isAvailable için okuma potansiyel olarak engelleyici olabilir.


5
Socket.setSoTimeout()eşit derecede doğru ve çok daha basit bir çözümdür. Veya HttpURLConnection.setReadTimeout().
Marquis of Lorne

3
@EJP - bunlar yalnızca belirli koşullar altında "eşit derecede doğrudur"; Örneğin, giriş akışı bir soket akışı / HTTP bağlantı akışı ise.
Stephen C

1
@Stephen C NIO, yalnızca engellemez ve aynı koşullar altında seçilebilir. Örneğin, engellemeyen dosya G / Ç'si yoktur.
Marquis of Lorne

2
@EJP ancak engellemeyen boru GÇ (System.in) var, dosyalar için engellemeyen G / Ç (yerel diskte) saçma
woky

1
@EJP Çoğu (hepsinde?) Unices System.in aslında bir borudur (eğer shell'e onu dosya ile değiştirmesini söylemediyseniz) ve bir boru olarak engellemeyebilir.
woky

0

Bu cevaptan ilham alarak biraz daha nesne odaklı bir çözüm buldum.

Bu yalnızca karakterleri okumak istiyorsanız geçerlidir

BufferedReader'ı geçersiz kılabilir ve bunun gibi bir şey uygulayabilirsiniz:

public class SafeBufferedReader extends BufferedReader{

    private long millisTimeout;

    ( . . . )

    @Override
    public int read(char[] cbuf, int off, int len) throws IOException {
        try {
            waitReady();
        } catch(IllegalThreadStateException e) {
            return 0;
        }
        return super.read(cbuf, off, len);
    }

    protected void waitReady() throws IllegalThreadStateException, IOException {
        if(ready()) return;
        long timeout = System.currentTimeMillis() + millisTimeout;
        while(System.currentTimeMillis() < timeout) {
            if(ready()) return;
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                break; // Should restore flag
            }
        }
        if(ready()) return; // Just in case.
        throw new IllegalThreadStateException("Read timed out");
    }
}

İşte neredeyse eksiksiz bir örnek.

Bazı yöntemlerde 0 döndürüyorum, ihtiyaçlarınızı karşılamak için -2 olarak değiştirmelisiniz, ancak 0'ın BufferedReader sözleşmesine daha uygun olduğunu düşünüyorum. Yanlış bir şey olmadı, sadece 0 karakter okudu. readLine yöntemi korkunç bir performans katilidir. ReadLin e'yi gerçekten kullanmak istiyorsanız tamamen yeni bir BufferedReader oluşturmalısınız . Şu anda iş parçacığı için güvenli değil. ReadLines bir satırı beklerken birisi bir işlemi çağırırsa, beklenmedik sonuçlar üretecektir.

Olduğum yere -2'yi geri göndermeyi sevmiyorum. Bir istisna atardım çünkü bazı insanlar EOS'u dikkate almak için int <0 olup olmadığını kontrol ediyor olabilir. Her neyse, bu yöntemler "engelleyemez" iddiasındadır, bu ifadenin gerçekten doğru olup olmadığını kontrol etmelisiniz ve onları geçersiz kılmayın.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.nio.CharBuffer;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

/**
 * 
 * readLine
 * 
 * @author Dario
 *
 */
public class SafeBufferedReader extends BufferedReader{

    private long millisTimeout;

    private long millisInterval = 100;

    private int lookAheadLine;

    public SafeBufferedReader(Reader in, int sz, long millisTimeout) {
        super(in, sz);
        this.millisTimeout = millisTimeout;
    }

    public SafeBufferedReader(Reader in, long millisTimeout) {
        super(in);
        this.millisTimeout = millisTimeout;
    }



    /**
     * This is probably going to kill readLine performance. You should study BufferedReader and completly override the method.
     * 
     * It should mark the position, then perform its normal operation in a nonblocking way, and if it reaches the timeout then reset position and throw IllegalThreadStateException
     * 
     */
    @Override
    public String readLine() throws IOException {
        try {
            waitReadyLine();
        } catch(IllegalThreadStateException e) {
            //return null; //Null usually means EOS here, so we can't.
            throw e;
        }
        return super.readLine();
    }

    @Override
    public int read() throws IOException {
        try {
            waitReady();
        } catch(IllegalThreadStateException e) {
            return -2; // I'd throw a runtime here, as some people may just be checking if int < 0 to consider EOS
        }
        return super.read();
    }

    @Override
    public int read(char[] cbuf) throws IOException {
        try {
            waitReady();
        } catch(IllegalThreadStateException e) {
            return -2;  // I'd throw a runtime here, as some people may just be checking if int < 0 to consider EOS
        }
        return super.read(cbuf);
    }

    @Override
    public int read(char[] cbuf, int off, int len) throws IOException {
        try {
            waitReady();
        } catch(IllegalThreadStateException e) {
            return 0;
        }
        return super.read(cbuf, off, len);
    }

    @Override
    public int read(CharBuffer target) throws IOException {
        try {
            waitReady();
        } catch(IllegalThreadStateException e) {
            return 0;
        }
        return super.read(target);
    }

    @Override
    public void mark(int readAheadLimit) throws IOException {
        super.mark(readAheadLimit);
    }

    @Override
    public Stream<String> lines() {
        return super.lines();
    }

    @Override
    public void reset() throws IOException {
        super.reset();
    }

    @Override
    public long skip(long n) throws IOException {
        return super.skip(n);
    }

    public long getMillisTimeout() {
        return millisTimeout;
    }

    public void setMillisTimeout(long millisTimeout) {
        this.millisTimeout = millisTimeout;
    }

    public void setTimeout(long timeout, TimeUnit unit) {
        this.millisTimeout = TimeUnit.MILLISECONDS.convert(timeout, unit);
    }

    public long getMillisInterval() {
        return millisInterval;
    }

    public void setMillisInterval(long millisInterval) {
        this.millisInterval = millisInterval;
    }

    public void setInterval(long time, TimeUnit unit) {
        this.millisInterval = TimeUnit.MILLISECONDS.convert(time, unit);
    }

    /**
     * This is actually forcing us to read the buffer twice in order to determine a line is actually ready.
     * 
     * @throws IllegalThreadStateException
     * @throws IOException
     */
    protected void waitReadyLine() throws IllegalThreadStateException, IOException {
        long timeout = System.currentTimeMillis() + millisTimeout;
        waitReady();

        super.mark(lookAheadLine);
        try {
            while(System.currentTimeMillis() < timeout) {
                while(ready()) {
                    int charInt = super.read();
                    if(charInt==-1) return; // EOS reached
                    char character = (char) charInt;
                    if(character == '\n' || character == '\r' ) return;
                }
                try {
                    Thread.sleep(millisInterval);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt(); // Restore flag
                    break;
                }
            }
        } finally {
            super.reset();
        }
        throw new IllegalThreadStateException("readLine timed out");

    }

    protected void waitReady() throws IllegalThreadStateException, IOException {
        if(ready()) return;
        long timeout = System.currentTimeMillis() + millisTimeout;
        while(System.currentTimeMillis() < timeout) {
            if(ready()) return;
            try {
                Thread.sleep(millisInterval);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt(); // Restore flag
                break;
            }
        }
        if(ready()) return; // Just in case.
        throw new IllegalThreadStateException("read timed out");
    }

}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.