# exception "java.io.IOException: Stream closed"



## henpara (15. Nov 2010)

Ich bekomme diese exception in folgendem try-block:


```
public void writeToLogFile(String info, boolean crt) {
		try { 
			buffWriter.write(info);
			if (crt) 
				buffWriter.newLine();
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
```
und zwar genau in der buffWriter.write(info)- zeile.

Nun sollte ich noch erwähnen, daß die writer

```
static Writer writer;
	static BufferedWriter buffWriter;
```
so aussehen und daß am Anfang des Programms

```
public void openLogFile() {
		try { 
			// von true auf false setzen, wenn man NICHT möchte, daß out.log überschrieben wird.
			writer = new FileWriter(logFile, true);
			buffWriter = new BufferedWriter(writer);
		}   
		catch (Exception e) { e.printStackTrace();
		}
```
aufgerufen wird, und erst GANZ am Ende

```
public void closeLogFile() { 
		try { 
			buffWriter.flush();
			buffWriter.close();
			writer.close();
		}   
		catch (Exception e) {
			e.printStackTrace();
		}
```

Nun meine Frage:
wie kann es zu dieser Exception kommen. Wann wird ein Stream ohne .close() geclosed? oder MUSS hier ein Programmierfehler vorliegen, das heißt daß der Stream implizit geclosed wird?!

Über jede Art von Hilfe zur Fehlerbehebung bin ich dankbar!

mfG


----------



## Cru (15. Nov 2010)

Also anhand deiner Schnipsel seh ich da nichts...

Die Exception kommt aber, dass hast du richtig erfasst, wenn der Stream zu früh geschlossen wird (z.B. das .close() ist falsch positioniert).

Eine Idee wäre:

```
if(buffWriter!=null) {
    buffWriter.close();
}

if(writer!=null) { 
    writer.close();
}
```

Vielleicht mal posten wie du deine Methoden aufrufst?


----------



## SlaterB (15. Nov 2010)

ist der Fehler reproduzierbar oder tritt er zufällig auf? im letzten Fall zumindest so oft dass man sich direkt damit beschäftigen kann?

allgemeine Möglichkeiten zur Fehlerfindung:
- überall im Programm nach close() suchen, ok zu einfach
- statt FileWriter + BufferedWriter eigene Klassen verwenden bzw. BufferedWriter erstmal rauslassen und nur statt FileWriter eine überschriebene Klasse und dort close() überschreiben und loggen ob es aufgerufen wird
- generell alle writeToLogFile()-Aufrufe loggen, wann ging es noch, wann nicht mehr, zufällig Begin/Ende einer bestimmten Aktion des Programms?
- weiter zur Eingrenzung des Zeitraums: einen Thread im Programm nebenher laufen lassen, der alle 100ms bzw. noch öfter etwas schreibt  
wann geht der nicht mehr?


----------



## henpara (15. Nov 2010)

ja, er ist reproduzierbar.

bin jetzt ein stück weiter. Und zwar:

in einem methodenaufruf wurde die closelogfile methode aufgerufen, das war aber nicht immer auch gleichzeitig das programmende.
wenn man jetzt eine andere methorde aufgerufen hatte , kam die exception.
was mich allerdings noch verwundert ist, daß in der anderen methode nochmal explizit openlogfile aufgerufen wurde.

trotzdem wurde der stream als closed gesetzt.

ich hab es jetzt so gemacht, daß der log-stream erst vor dem System.exit ausgeführt wird.
hoffentlich klappt das.


----------



## henpara (15. Nov 2010)

hmm hab den Fehler gerade etwas verschoben, dürfte aber einfacher zu erklären sein:

nach wie vor gibt es die Instanz der Klasse Log, dort wurden auch mit OpenLogFile() die writer geöffnet, bzw. instanzen erstellt 

```
public void openLogFile() {
		try { 
			writer = new FileWriter(logFile, true);
			buffWriter = new BufferedWriter(writer);
		}   
		catch (Exception e) { 
			e.printStackTrace();
		}
```

so, nun hab ich das CloseLogFile(); je vor das System.exit(0) gepackt, also zB bei Exit über Fenster-schließen:

```
this.setDefaultCloseOperation(this.close());
```
mit

```
protected int close() {
		go.Go.log.closeLogFile();
		return WindowConstants.EXIT_ON_CLOSE;
	}
```
jetzt hat das Frame aber einen Dialog, der über folgenden Konstruktor gebaut wird:

```
public Login(Frame XTFrame) {
		super(XTFrame);
		this.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
	}
```
wenn ich jetzt im Anmeldedialog meine Daten eingebe und auf den "login"-Button drücke bekomme ich oben genannte exception.

Button-Ausführung:

```
static ActionListener al0 = new ActionListener() { 
		  @Override public void actionPerformed( ActionEvent e ) { 
			User = Username.getText();
			Pwd = String.valueOf(Password.getPassword());
			//go.Go.log.print(User + " " + Pwd + " " + URL);
			//System.out.println("MUAHAH");
			if (checklogin(URL, User, Pwd)) {
				mainFrame.dispose();
				go.Go.log.println(URL + " " + User);
				try {
					gui.MTxFrame.theReportEngine.open();
				} catch (Exception e2) {
					System.exit(0);
					e2.printStackTrace();
				}
				try {
					mtx10.Ini.conn.close();
				} catch (SQLException e1) {
					e1.printStackTrace();
				}
			} else {
				Username.setText("");
				Password.setText("");
				JOptionPane.showMessageDialog(mainFrame, "Username or password is incorrect.");
			}
			
		  }
	};
```
man beachte, daß die exception genau beim mainFrame.dispose(); bzw. eben dahinter auftritt, mainFrame extends JDialog.


----------



## SlaterB (15. Nov 2010)

besteht eine Frage?

falls bei
> mainFrame.dispose();
> go.Go.log.println(URL + " " + User);
die Exception auftritt ist dazu nach wie vor wenig zu sagen, deine Codes und Erklärungen lassen nicht erkennen, ob und wo an dieser Stelle das (eine oder mehrere?) Log schon geöffnet oder bereits wieder geschlossen wurde,

wenn du schon erkannt hast, dass alles über deine normalen Methoden läuft, dann wird es ja einfach sein, nachzuvollziehen, wann was wo warum passiert,
um die Exception zu vermeiden kannst du auch eine Abfrage if (stream.isClosed()) verwenden


----------



## henpara (15. Nov 2010)

ok, ich versuch mich nochmal kurz und besser verständlich auszudrücken:

in der Main methode ganz am anfang wird EINMAL eine Instanz der Klasse Log erstellt. Daraufhin noch die methode openLogFile aufgerufen, damit der BufferedWriter instanziiert ist (richtige formulierung?).

das ist das EINZIGE mal, wo eine Instanz der Klasse Log aufgerufen bzw. instanziiert wird.
Jetzt wird nun entweder, wenn man über "optionen" (MenüEintrag im Frame) "Quit" wählt die methode closeLogFile aufgerufen, oder aber über die "setDefaultCloseOperation" des Frames.

Das sind definitiv die beiden EINZIGEN Möglichkeiten die closeLogFile methode aufzurufen, wo der BufferedWriter geschlossen wird.

Offensichtlich wird der Stream aber auch geschlossen, wenn ein JDialog, der das Frame als Parent hat disposed wird, der Stream ebenso geschlossen. 

Und das ist genau die Stelle, die ich nicht verstehe.
Was hat "dialog.dispose()" mit setDefaultCloseOperation des Parent-Frames zu tun?


Hoffe ich war diesmal etwas verständlicher 

(Der Fehler verschwindet, wenn ich die DefaultCloseOperation des Frames (nicht des Dialogs) auf "DO_NOTHING_ON_CLOSE" änder)

mfG und trotzdem Danke schonmal für die Anregungen!


----------



## SlaterB (15. Nov 2010)

nun gut, da war dann doch schon mehr vorher zu sehen, zunächst:

>  mainFrame.dispose();
>               go.Go.log.println(URL + " " + User);

hast du getestet, ob VOR dem dispose-Aufruf das Log noch geht? meiner Meinung nach hat diese Code-Zeile nichts mit dem Problem zu tun,

------

> Der Fehler verschwindet, wenn ich die DefaultCloseOperation des Frames (nicht des Dialogs) auf "DO_NOTHING_ON_CLOSE" ändere

das durchaus denn diese Einstellung ist für sich das Problem unabhängig ob später das Frame geschlossen wird oder nicht

> this.setDefaultCloseOperation(this.close());
bedeutet nämlich nicht 'merke dir diese Methode und führe sie beim close aus', das geht in Java so noch gar nicht,
tatsächlich bedeutet es:

```
int x = this.close(); // Log hier am Anfang schon geschlossen!
this.setDefaultCloseOperation(x); // Parameter ist ein int, vorkonfigurierte mögliche Einstellungen, 

z.B. 
public static final int EXIT_ON_CLOSE = 3;
```

was du brauchst ist
Java Tips - How to use WindowListener for closing JFrames


----------



## henpara (15. Nov 2010)

> hast du getestet, ob VOR dem dispose-Aufruf das Log noch geht? meiner Meinung nach hat diese Code-Zeile nichts mit dem Problem zu tun,


hab ich.

zu dem close() als setdefaultcloseoperation: danke für den hinweis, hatte schon so etwas befürchtet :/
aber trotzdem schließt er den stream anscheinend ja...
und das würde genau das erklären, weil er ja das "int" zuweist, wie du schreibst. dort führt er dann die methode aus und die schließt den stream schon lange bevor irgendwann man das fenter-schließen geklickt wird!

thx!


----------



## SlaterB (15. Nov 2010)

> hab ich.
und? dürfte doch auch nicht funktioniert haben, ergo dispose() egal


> aber trotzdem schließt er den stream anscheinend ja...

was heißt 'aber trotzdem', ist doch alles klar nun oder? siehe noch den Link am Ende des letzen Postings, sekunden später editiert


----------



## henpara (15. Nov 2010)

> > hab ich.
> und? dürfte doch auch nicht funktioniert haben, ergo dispose() egal


doch es hat funktioniert, das ist auch das einzige, was mich zZ noch stutzig macht.

und: dein link hat mir sehr geholfen! thx!


Hab es jetzt entsprechend deinem Link geändert und es läuft alles. keine Stream closed exceptions mehr 

wobei ich das mit dem stream und wann er ggf closed noch nicht ganz durchschaut habe. bzw. wann ist klar, aber wie es dazu kam, daß´genau dort die close-methode aufgerufen wurde.


----------

