# Datei einlesen



## Smoothi (8. Nov 2011)

Es ist schon fast peinlich zu Fragen, da ich schon länger mit Java programmier... XD Aber ich bekomm es einfach nicht gebacken eine Datei einzulesen.


```
BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader(new File("test.txt")));
            String line = null;
            String text = "";
            while((line = br.readLine()) != null) {
                text += line;
            }
            br.close();
            System.out.println(text);
        } catch(FileNotFoundException e) {
            e.printStackTrace();
        } catch(IOException e) {
            e.printStackTrace();
        }
```

Hier (Aus Dateien lesen - Java als erste Programmiersprache - Javaschublade) zum Beispiel steht:
Leg eine Datei mit dem Namen test.txt in demselben Ordner an, in dem du die java-Datei gleich speichern wirst.

Nun habe ich eine Datei erstellt und innerhalb von Netbeans in den Ordner mit der aufrufenden Klasse gezogen. Also sie liegt dann in "..\[Projekt]\src\java\presentation"

Aber es kommt jedesmal eine FileNotFoundException... Wo pack ich die Text-Datei denn sonst hin?


----------



## nrg (8. Nov 2011)

finds heraus:


```
System.out.println(new File("").getAbsolutePath());
```


----------



## faetzminator (8. Nov 2011)

Du solltest Dateien immer per [c]getClass().getResource("....");[/c] laden. Und die Datei muss natürlich von der IDE in den bin Ordner kopiert werden.


----------



## Smoothi (8. Nov 2011)

Ok, gut zu wissen 

Also wies aussieht funktioniert das. 

```
getClass().getResource("");
```
Da gibt er mir [...]/WEB-INF/classes/mail/ aus

ich müßte jetzt nur noch in [...]/WEB-INF/mailtemplates/
So wär mir der Pfad jedenfalls am liebsten


```
URL url = getClass().getResource("../../mailtemplates/");
```
Das funktioniert leider nicht...


----------



## faetzminator (8. Nov 2011)

Sagen wir, du hast eine Datei [c]/resources/templates/foo.template[/c]. Deine Klassen sind in [c]/src[/c], und Output ist [c]/bin[/c]. In Eclipse kann ich einfach [c]/resources[/c] als zweiter Source Ordner angeben, und die darin befindlichen Dateien werden - wie die kompilierten Klassen - nach [c]/bin[/c] kopiert. Somit kann ich danach einfach mit [c]getClass.getResource("/templates/foo.template");[/c] (oder wars [c]"templates/foo.template"[/c]?) auf die Datei zugreifen. Das sollte in Netbeans sicher auch irgendwie so gemacht werden.


----------



## Smoothi (8. Nov 2011)

Naja... der Hintergrund ist folgender

Ich programmier mit Java EE (habe es aber nicht in den Java EE-Bereich geschrieben, da es für mich recht allgemein war  )

Die Struktur ist


```
-Web Pages
    -WEB-INF
        -template (Seitenlayout)
        -mailtemplates [COLOR="Red"](und hier hätte ich gern diese TXT-Dateien)[/COLOR]
        -web.xml
        -[...]
    -[XHTML-Seiten]
-Source Packages
-Test Packages
-Libraries
```
usw.

Meinst du nun einfach den mailtemplates-Ordner irgendwie als Source zu definieren?
Wenn ich dich richtig versteh, wird das dann aber in /bin kopiert.

Ich würde den Pfad beim Deployen gern beibehalten. Insofern das halt irgendwie möglich ist?!
Man sollte die Templates gegebenenfalls auch per Hand ändern können, ohne sich durch die Ordnerstruktur zu hangeln.


----------



## faetzminator (8. Nov 2011)

Smoothi hat gesagt.:


> Ich würde den Pfad beim Deployen gern beibehalten. Insofern das halt irgendwie möglich ist?!
> Man sollte die Templates gegebenenfalls auch per Hand ändern können, ohne sich durch die Ordnerstruktur zu hangeln.



Na gut, bei Webprojekten sieht das ganze wieder ein Bisschen anders aus. Aber nein, natürlich ändert sich für den Entwickler nichts, da die Dateien beim Buildprozess kopiert werden sollen.
Ich hab ein Beispiel gesucht, gerade aber leider nichts gefunden. Wir haben die Hiarchie [c]/WebContent/WEB-INF[/c]. IMHO kann man alle Resourcen, welche in [c]/WebContent[/c] liegen, einfach per [c]getResource()[/c] auslesen.


----------



## Smoothi (8. Nov 2011)

> Aber nein, natürlich ändert sich für den Entwickler nichts, da die Dateien beim Buildprozess kopiert werden sollen.



Ich habe mich eventuell bißchen ungünstig ausgedrückt oder wir reden da aneinander vorbei. 
Ich meinte, man sollte die Template-Dateien auch problemlos verändern können, ohne sich durch die ganze Ordnerstruktur zu hangeln und ohne eine IDE zu verwenden. Ich finde das ungünstig, wenn diese dann mit bei den Klassen liegen, deswegen wollte ich es unter 
	
	
	
	





```
WEB-INF/mailtemplates
```
 machen.



> IMHO kann man alle Resourcen, welche in /WebContent liegen, einfach per getResource() auslesen.



Also wenn meine "test.txt" direkt im WEB-INF liegt (der Einfachheit halber) sollte ich ja direkt drauf zugreifen können:

```
getClass().getResource("WebContent/WEB-INF/test.txt"); 
getClass().getResource("/WebContent/WEB-INF/test.txt");
```

funktioniert aber leider beides nicht. So wars doch gemeint oder?


----------



## faetzminator (8. Nov 2011)

Ich behaupt, es würde mit einer von diesen Varianten funktionieren:

```
getClass().getResource("WEB-INF/test.txt"); 
getClass().getResource("/WEB-INF/test.txt");
```
Vielleicht muss man aber statt [c]getClass()[/c] folgendes verwenden, je nach dem wie die CLs miteinander spielen:

```
Thread.currentThread().getContextClassLoader().getResource("...");
```


----------



## nillehammer (8. Nov 2011)

Der Hinweis von faetzminator bezog sich auf die Annahme, dass Du eine Resource laden willst, die direkt neben Deiner Klasse (also im sog. Classpath) liegt. Das ist ja aber garnicht so. Du willst die Datei ja aus einem ganz anderen Ordner laden. Dann geht es mit getClass().getResource() nicht.

Man muss gedanklich ganz klar Trennen zwischen dem Zugriff auf Rsourcen im Classpath und dem Zugriff allgemein auf das Filesystem. Mit getResource() bekommst Du nur Resourcen aus dem Klassenpfad. Das können *zufällig* Files sein, wenn die Anwendung komplett ausgepackt ist. Wenn die Anwendung in ein jar verpackt ist, ist die Resource kein File mehr.

Der Ordner "/WebContent/WEB-INF/test.txt" liegt nicht im Classpath. Deswegen geht getResource() hier nicht. Du hast jetzt zwei Möglichkeiten. Finde den Ordner im Filesystem heraus und greife darauf zu. (bei Webanwendugnen gibt es dafür die Methode ServletContext.getRealpath) oder sorge dafür, dass Deine Datei im Klassenpfad landet. Bei Webanwendungen ist das entweder /WEB-INF/classes oder ein jar in /WEB-INF/lib
Letzteres kann Dir die IDE abnehmen, wenn Du parallel zu Deinem Java-Ornder einen resources-Ordner als src-Folder konfigurierst. Die IDE kopiert dann die Datei dorthin, wo auch die kompilierten Java-class Dateien landen. Wie bei Java-Code auch, musst Du hier die packages beachten.


----------



## nillehammer (8. Nov 2011)

faetzminator hat gesagt.:
			
		

> ch behaupt, es würde mit einer von diesen Varianten funktionieren:
> getClass().getResource("WEB-INF/test.txt");
> getClass().getResource("/WEB-INF/test.txt");


Das geht leider nicht. Die genannten Ordner liegen nicht im Classpath (siehe letzter Post)

Und nochmal ganz deutlich:
Vermische nie den Zugriff auf Resourcen mit dem Zugriff auf Dateien:
- Wenn Zugriff auf Resourcen, dann getResourceAsStream und mit InputStreamReader lesen, *niemals* mit FileReader
- Wenn Zugriff auf Dateisystem, dann mit FileReader arbeiten.


----------



## faetzminator (8. Nov 2011)

Wieso differenzierst du zwischen "Files" und "Resources"? Ein Webprojekt wird normalerweise per WAR deployt und kennt darum nur "Resources"!?


----------



## Smoothi (8. Nov 2011)

@Nillehammer
Doof gefragt... wieso sollte man das nicht machen, wenn man nur liest? Ganz ehrlich... ich hab jetzt keine Ahnung als was diese Templatedateien gelten. In gewisser Weise sind es ja Ressourcen, andererseits sind es mehr oder weniger externe Dateien. 

EDIT: Ach, du beziehst dich auf die getResource()-Methode oder? Du meinst, wenn man die verwendet, sollte man nicht mit dem FileReader arbeiten?!

Die Methode die Datei aus dem Filesystem zu holen, ist mir lieber, aus den oben genannten Gründen. 
Bist du dir mit ServletContext.getRealpath sicher? ServletContext ist Abstrakt und enthält keine statischen Methoden.

@faetzminator
Geht leider nicht. Ich habe alle erdenklichen Pfade probiert.
Mit der ThreadFunktion lande ich im Glassfish-Ordner. Das ist das gleiche als wenn ich 
	
	
	
	





```
getClass().getResource("/");
```
 mach. Dabei landet er auch im Glassfish-Ordner und nicht im Projektordner.

Bei 
	
	
	
	





```
getClass().getResource("");
```
 landet er im richtigen Ordner, aber ich kann mich nicht in übergeordnete Verzeichnisse begeben


----------



## nillehammer (8. Nov 2011)

Smooti hat gesagt.:
			
		

> EDIT: Ach, du beziehst dich auf die getResource()-Methode oder? Du meinst, wenn man die verwendet, sollte man nicht mit dem FileReader arbeiten?!


Exakt.


			
				Smoothi hat gesagt.:
			
		

> Bist du dir mit ServletContext.getRealpath sicher? ServletContext ist Abstrakt und enthält keine statischen Methoden.


Alter, ich hab das so geschrieben, damit Du weißt, wo Du schauen musst. Du kannst das natürlich so nicht aufrufen. Den ServletContext bekommst Du von Deinem Container. Und auf der konkreten Instanz kannst Du die Methode dann aufrufen.

// Edit: Een ServletContext bekommst Du über das Request-Objekt, dass Du immer irgendwie zu fassen bekommst, egal mit welchem Framework Du arbeitest. (Schließlich ist es ja der Sinn von  Webanwendungen, Requests zu verarbeiten und dann irgend einen schlauen Response zu generieren)



			
				faetzminator hat gesagt.:
			
		

> Wieso differenzierst du zwischen "Files" und "Resources"? Ein Webprojekt wird normalerweise per WAR deployt und kennt darum nur "Resources"!?


Erstmal nur, um den Unterschied ganz deutlich zu machen. Wenn die txt-Datei nämlich zugreifbar gewesen wäre, wäre es trotzdem nicht gegangen, weil Smoothi es mit einem FileReader versucht hätte. Und wenn man das Webprojekt als war deployt und keinen externen Speicherordner benutzen will, dann muss man dafür sorgen, dass die txt-Datei irgendwo landet, wo man sie per getResource() erreicht. Direkt in WEB-INF geht es nicht.


----------



## faetzminator (8. Nov 2011)

nillehammer hat gesagt.:


> [...] dass die txt-Datei irgendwo landet, wo man sie per getResource() erreicht. Direkt in WEB-INF geht es nicht.



Ich weiss nicht, was wir da für Modifikationen gemacht haben, aber ich kann alles aus [c]/WebContent[/c] einlesen...


----------



## nillehammer (8. Nov 2011)

faetzminator hat gesagt.:
			
		

> Ich weiss nicht, was wir da für Modifikationen gemacht haben, aber ich kann alles aus /WebContent einlesen...


Ich hab hier im Moment keine Entwicklnungsumgebung für Webanwendungen. Werde es aber heut Abend zu Hause mal unter Tomcat und Jetty ausprobieren. Wenn es geht, wäre ich sehr überrascht und würde mein Haupt in Demut senken. Schreibe dann, was rausgekommen ist...


----------



## Smoothi (8. Nov 2011)

Also es funktioniert mit der Version von Nillehammer ;D


```
public String getMailPath(String mailTemplate) {
        FacesContext fc = FacesContext.getCurrentInstance();
        HttpServletRequest request = (HttpServletRequest) fc.getExternalContext().getRequest();
        ServletContext context = request.getSession().getServletContext();
        return context.getRealPath("WEB-INF/" + mailTemplate);
    }
```

Am Auslesen habe ich nichts verändert.

Jedoch würdem ich noch die andere Version interessieren. Was genau hast du denn eingegeben zum Auslesen?


```
getClass().getResource("WEB-INF/test.txt");
```
 ?


----------



## nillehammer (8. Nov 2011)

Hallo Smoothi,

noch eine kleine Verbesserung habe ich. Du brauchst nicht den Umweg über die Session zu gehen. Damit erzeugst Du evtl sogar eine Session, obwohl Du sie garnicht brauchst (zumindest nicht dafür). Änder Deine Zeile 4 wie folgt um:
[Java]
ServletContext context = request.getServletContext();
[/Java]


----------



## Smoothi (8. Nov 2011)

Ok danke 

Die Sache mit der Session hatte ich von meiner Benutzerauthentifizierung übernommen. Dafür brauchte ich es ja. Eigentlich hätte ich oben merken müssen, was du mit dem ServletContext meintest, da ich es schon verwendet hatte. Aber ich habs einfach nich mitgeschnitten :lol:

Jetzt habe ich noch eine Kleinigkeit, die deine Problematik mit den Ressourcen und dem Dateisystem betrifft.

Du schriebst ja:


> - Wenn Zugriff auf Resourcen, dann getResourceAsStream und mit InputStreamReader lesen, niemals mit FileReader
> - Wenn Zugriff auf Dateisystem, dann mit FileReader arbeiten.



Nun habe ich es mit einem FileReader gemacht, jedoch habe ich das Problem, dass er beim Auslesen die Umlaute nicht nicht ordentlich ausgibt. (Die TXT hat UTF-8)

Nun habe ich es mal so probiert:

```
File file = new File(mailTemplatePath);
FileInputStream fis = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fis, Charset.forName("UTF-8"));
BufferedReader br = new BufferedReader(isr);
```

da man beim InputStreamReader ein Charset übergeben kann.

Damit funktioniert es auch wunderbar. Jedoch wiederspricht das jetzt ja deiner Aussage man sollte beim Zugriff auf das Dateisysetm mit dem FileReader arbeiten. 

Sollte ich das doch lieber anders lösen?


----------



## nillehammer (8. Nov 2011)

> Damit funktioniert es auch wunderbar. Jedoch wiederspricht das jetzt ja deiner Aussage man sollte beim Zugriff auf das Dateisysetm mit dem FileReader arbeiten.


Ich habe geschrieben, wenn Resource, dann *niemals* FileReader. Das ist der wichtige Teil.

Das mit dem FileReader war *eine* Möglichkeit an den Inhalt eines Files ranzukommen. Du hast eine zweite gefunden, die absolut in Ordnung ist. Ich hätte das genauso gemacht, wenn ich das Charset hätte selbst setzen wollen. Nur das Erzeugen des Fileobjekts kannst Du Dir sparen. Der FileInputStream akzeptiert auch den Pfad als String als Konstruktorparameter. Also lösche Zeile 1 und schreibe Zeile 2 um in:
[Java]
FileInputStream fis = new FileInputStream(mailTemplatePath);
[/Java]


----------



## Smoothi (8. Nov 2011)

ach ok...ich dachte das sollte man strikt trennen... Nun gut, dann wär das gelöst. Vielen Dank und auch für die Geduld  

EDIT: Deine Anmerkung habe ich noch editiert...immer gut, wenn sich Code kürzen lässt


----------



## nillehammer (8. Nov 2011)

Smoothi hat gesagt.:
			
		

> ach ok...ich dachte das sollte man strikt trennen...


Naja gedanklich sollte man halt Files strikt von Resourcen trennen. Das mit den Readern ist mehr ein "Benutzungsverbot" sämtlicher File-orientierter Reader im Zusammenhang mit Resourcen. Werde das in Zukunft besser erklären...


----------

