# BufferedReader.ready() immer false



## Einwegdose (8. Jun 2006)

Hallo mal wieder  :lol: 

Ich hatte bisher bei der Connection zum Server immer einen Input-Stream verwendet, und den über eine Methode bei Bedarf ausgelesen. Nun wollte ich das alles in einen BufferedReader packen um es effizienter zu machen.
Leider aber liest er nichts ein und gibt immer direkt ein "false" bei der ready()-Methode zurück.


Alte Codierung:


```
try {
    soc = new Socket(server, port);
    in = soc.getInputStream();
   } catch(Exception e) {}
...
...
// Aufruf der receive()-Methode
...
...
  public String receive() {
   int c = 0;
   text = "";
   try {
    while ( c != 10 ) {         // Eine Zeile einlesen
     c = in.read();
     text = text + ((char)c);
    }
   } catch(Exception e) {}
   return text;
  }
```

Dieser Code hat soweit auch funktioniert.
Hier der neue Ansatz:


```
try {
    soc = new Socket(server, port);
    br = new BufferedReader(new InputStreamReader(soc.getInputStream()));
   } catch(Exception e) {}
...
...
// Aufruf der receive()-Methode
...
...
  public String receive() {
   int c = 0;
   text = "";
   try {
    while ( br.ready() ) {        
     c = br.read();
     text = text + ((char)c);
    }
   } catch(Exception e) {}
   return text;
  }
```

Hier allerdings ist der Rückgabewert der br.ready() direkt false. 
Weiss einer wieso ??

Im Endeffekt geht es darum, einen langen Text einzulesen, und dies sollte ja mit dem BufferedReader einiges effezienter sein als direkt mit dem InputStream !


----------



## meez (8. Jun 2006)

So wird das gemacht: 


```
public String receive() {
  text = ""
   try {
    String s;
    while ( (s = br.readLine()) !=null) {       
     text = text + s;
    }
   } catch(Exception e) {}
   return text;
  }
```

Anstatt text so zusammen zu setzen, solltest du einen StringBuffer nehmen; ist ja aber hier nicht das Subjekt.
Du hättest bei deinem "alten" Code auch einfach den InputStream in einen BufferedInputStream "einpacken" können.


----------



## Einwegdose (8. Jun 2006)

Danke schonmal für die Antwort. Leider scheint es aber so auch nicht zu klappen.

Ich habe dazu mal ein kleines Test-Programm geschrieben:



```
import java.net.*;
import java.io.*;

public class ServerTest {

 String text="",s;

  public void test() {
   try {
    Socket soc = new Socket("ftp.microsoft.com", 21);
    BufferedReader br = new BufferedReader(new InputStreamReader(soc.getInputStream()));
    while ( (s = br.readLine()) !=null) {
     text = text + s;
    }
   } catch(Exception e) {}
   System.out.println("Empfangen: " + text);
  }

  public static void main(String[] args) {
   ServerTest st = new ServerTest();
   st.test();
  }
}
```

Leider kommt das Programm garnicht zu der Sop-Zeile .. eine Ausgabe erscheint nie. Testen wir das ganze mit Telnet, kommt die Anzeige "220 Microsoft FTP Service" dabei heraus !
Das liegt wohl daran, dass er immer noch was liest, obwohl überhaupt nichts da ist. Selbst wenn ich "s" als int ausgebe, erscheint nichts .. er hängt in der while-Schleife ohne irgend etwas zu machen !?!


----------



## meez (8. Jun 2006)

Ach du hast da ja Socket...Was erwartest du...
Da ist kein FTP Protokoll implemetiert...das musst du schon selber machen 

Socket OSI Layer 4 .... FTP OSI Layer 6 ... Du siehst also, da Fehlen noch zwei  

Aber anstatt:

```
Socket soc = new Socket("ftp.microsoft.com", 21);
BufferedReader br = new BufferedReader(new InputStreamReader(soc.getInputStream()));
```

schreib mal:

```
URL soc = new URL("ftp://ftp.microsoft.com"); 
BufferedReader br = new BufferedReader(new InputStreamReader(soc.openStream()));
```


btw. Lass dir den Stack ausgeben: Im catch-Block e.printStackTrace(); einfuegen.


----------



## Einwegdose (8. Jun 2006)

Ok, ich glaube ich muss mich etwas präzisieren 

Kurz zu deiner Hilfestellung:
Jetzt kommt zwar was, allerdings kein "220 Microsoft FTP Service" sondern 



> Empfangen: dr-xr-xr-x   1 owner    group               0 Feb  1 17:31 bussysdr-x
> r-xr-x   1 owner    group               0 Feb  1 19:02 deskappsdr-xr-xr-x   1 ow
> ner    group               0 Feb  1 19:16 developrdr-xr-xr-x   1 owner    group
> 0 Feb  1 19:16 KBHelpdr-xr-xr-x   1 owner    group               0
> ...




Aaaaaaaaalso, es geht atm darum zu einem POP-Server zu connecten.
Das ganze hat mit der "alten" receive() (und dem InputStream und dem "reinen" Socket) auch soweit geklappt, die Abfrage nach c==10 (Line Feed) war so, weil die Methode nur für einzeilige Antworten gedacht war und weil nie ein "-1" (InputStream leer) auftrat. Nun wollte ich es eben auf einen BufferedReader umstellen und stehe vor der selben Problematik .. er hört nicht auf zu lesen  Da komm ich mit dem URL wohl auch nicht weiter


----------



## meez (8. Jun 2006)

Nimm den readLine halt aus der while schlaufe raus...Einfach text = in.readLine() ... Liest einfach die erste Linie...
Das "Service" kommt nicht mehr, da du jetzt das Protokoll (URL) implemtiert hast, und dies jetzt vom Protokollhandler weggeschnitten wird...
Vorher hast du einfach einen Teil des FTP Protokolls gelesen...Wenn du aber das willst kannst du Socket nehmen...
Da kriegst du einfach das was der Server dir zuerst sendet...(220 servername FTP ready o.ä)
Da er aber nachher was von dir erwartet, wird der Stream nicht vom Server geschlossen, sondern du musst ihn schliessen (daher auch kein -1)


----------



## Einwegdose (8. Jun 2006)

OK für eine Zeile klappt das jetzt auch  :### 


```
public String receive() {
   try {
    text = br.readLine();
   } catch(Exception e) {}
   System.out.println(text);
   return text;
  }
```


Jetzt aber die Problematik bei mehreren Zeilen  :autsch: 
Ich weiss nicht, ob 50 Zeilen, 100 Zeilen oder 33 Zeilen kommen. Leider funktioniert ja die Methode br.ready() nicht, da diese ja immer "false" zurückgibt (wieso eigentlich ?).

Ich hab bisher einen Versuch gemacht, allerdings funktioniert er nicht  ???:L 


```
text = br.readLine();
     String oldtext="";
     do {
      oldtext = text;
      text = text + (char)10 + br.readLine();
     } while ( !oldtext.equals(text+(char)10) );
```


Es liegt wohl daran, dass er nie von Zeile 5 wegkommt, da br.readLine() nie fertig wird wenn es nichts mehr zu holen gibt .. nur wie kann ich das verhindern  :?:


----------



## Murray (8. Jun 2006)

Einwegdose hat gesagt.:
			
		

> Leider funktioniert ja die Methode br.ready() nicht, da diese ja immer "false" zurückgibt (wieso eigentlich ?).


ready() liefert dann true, wenn man aus dem Stream mindestens ein Zeichen lesen kann, ohne dass die read-Methode blockiert (also wartet, bis wieder Daten zur Verfügung stehen).
Wenn ready() false liefert, dann kann man in diesem Moment keine Daten lesen; das bedeutet aber nicht, dass nicht irgendwann nochmal Daten kommen.

Wenn Du von einem Server so Daten lesen willst, dann musst Du entweder vorab wissen, wieviel Bytes oder auch Zeilen kommen werden, beim Lesen der Daten diese Information ermitteln (siehe den Content-Length-Heder in HTTP), oder aber einen Timeout verwenden (also wenn ready() eine gewisse Zeit lang immer false zurückgeliefert hat annehmen, dass keine Daten mehr kommen werdn).


----------



## meez (9. Jun 2006)

Einwegdose hat gesagt.:
			
		

> Ich weiss nicht, ob 50 Zeilen, 100 Zeilen oder 33 Zeilen kommen. Leider funktioniert ja die Methode br.ready() nicht, da diese ja immer "false"



Wie schonmal gesegt, wird, wenn du auf einen FTP Server connectest, nie mehr als eine Zeile kommen.



			
				Einwegdose hat gesagt.:
			
		

> Es liegt wohl daran, dass er nie von Zeile 5 wegkommt, da br.readLine() nie fertig wird wenn es nichts mehr zu holen gibt .. nur wie kann ich das verhindern  :?:



Schliessen des Streams...das würde aber bedeuten, dass dein Program an mindestens einer Stelle weiterlaufen müsste Threads...
Du könntest natürlich auch ein wenig faken...Schick dem Server halt einen FTP quit Befehl...(SocketOutputStream)


Oder, geh halt auf einen HTTP Server, bis du genau weisst, wie man mit Protokollen umgehen muss  (Erleichtert für den Anfang einiges)


----------

