# Pfad für Speichervorgang auswählen



## Speedjunkee (7. Nov 2015)

Guten Morgen Community!

Ich möchte eine Datei schreiben/speichern. Bisher habe ich den Nutzer einen Dateinamen angeben lassen und die Datei dann im Pfad wo auch der Quelltext liegt abgespeichert. Da der Nutzer aber zur Berechnung der Ausgabedatei den FileChooser nutzt, möchte ich auch beim speichern der Datei die Möglichkeit der Pfadauswahl herstellen.

Über die Suche bzw. auch über die API bin ich auf SAVE_DIALOG gestoßen, kann damit aber leider nicht richtig umgehen.

Mein bisheriger Code mit Angabe des Dateinamens:

```
int i =0;
           
           String Name = FileName;
  
           try (BufferedWriter bw = new BufferedWriter(new FileWriter(Name+".csv")))
         {
           bw.write("Text");
           bw.newLine();
           while (waypoint_list.size() > i)
           {
           
             bw.write("Weiterer Text");
             bw.newLine();
             i++;
           
           }
         } catch(IOException ex)
         {...}
```

In meinem aktuellen Versuch öffnet sich zwar der "Speichern unter..." Dialog, jedoch wird die Datei unter dem Pfad wo der Quelltext liegt gespeichert.


```
int i =0;
           String Name = FileName;
           JFileChooser fileChooser = new JFileChooser("./");
           fileChooser.showSaveDialog(null);
   
           try (BufferedWriter bw = new BufferedWriter(new FileWriter(Name+".csv")))
         {
           bw.write("Text");
           bw.newLine();
           while (waypoint_list.size() > i)
           {
           
             bw.write("Weiterer Text");
             bw.newLine();
             i++;
           
           }
         } catch(IOException ex)
         {...}
```

Wie kann ich nun den gewählten Dateipfad und Namen aus dem Speichern unter Dialog übernehmen?

Ich bin euch dankbar für jegliche Hilfe


----------



## Thallius (7. Nov 2015)

Indem man sich die Doku zum FileChooser durchließt?

https://docs.oracle.com/javase/7/docs/api/javax/swing/JFileChooser.html


----------



## Dompteur (7. Nov 2015)

Du rufst zwar den Dialog auf, holst aber nicht das Ergebnis ab, sondern arbeitest weiter mit deinem ursprünglichen Filenamen.

Details findest du hier : https://docs.oracle.com/javase/8/docs/api/javax/swing/JFileChooser.html

Nachtrag: ich war zu langsam...


----------



## Speedjunkee (7. Nov 2015)

Danke für die Motivation, die Anleitung nochmal zu lesen.

Hab es jetzt hinbekommen!


----------



## karlmasutra (5. Jun 2018)

Hallo zusammen,

ich habe eine ähnliche Frage. (denke ich)
Ich nutze aktuell einen FileChooser (javaFX) um den save/openDialog zu öffen. In diesem habe ich bis jetzt einen absoluten Pfad angegeben, in dem sich der FileChooser öffnet. Es funktioniert auch alles.

Nun soll ich mittels Properties die Möglichkeit schaffen, dass der Benutzer den Pfad über Einstellungen selber wählen kann. Ich habe für die Properties einen neuen Dialog mit einem Textfeld gemacht. In diesem soll der Benutzer nun seinen Pfad angeben und damit den "Default-Pfad" überschreiben. Ich habe leider noch gar keine Berührungspunkte mit Properties und stehe deshalb vollkommen auf dem Schlauch. Könnte mir einer helfen?

Danke im voraus.

Hier mal meine 2 Methoden fürs den Speicher/Laden Dialog.

```
@FXML


void click_menueLesen(ActionEvent event) throws FileNotFoundException, IOException, ClassNotFoundException {

FileChooser fcLoad = new FileChooser();

fcLoad.setTitle("Dateimanager");

fcLoad.setInitialDirectory(new File("E:/Java")); //fuer MAC /Volumes/JAVA/Java --- fuer Winddoof F:/Java

File file = fcLoad.showOpenDialog(dialogStagePerson);

ObjectInputStream ois = new ObjectInputStream(

new FileInputStream(file));

//Eintraege des Arrays in observableList

Person [] arrTemp = (Person[]) ois.readObject();

for(Person p : arrTemp ) {

if(p != null) {

ovList.add(p);


}

}

listView.refresh();

ois.close();


}
```


```
@FXML


void click_menueSpeichern(ActionEvent event) throws FileNotFoundException, IOException {

FileChooser fcSave = new FileChooser();

fcSave.setTitle("Dateimanager");

fcSave.setInitialDirectory(new File("E:/Java/")); //fuer MAC /Volumes/JAVA/Java --- fuer Winddoof F:/Java

File file = fcSave.showSaveDialog(dialogStagePerson);

ObjectOutputStream oos = new ObjectOutputStream(

new FileOutputStream(file));

//observableList in Array speichern, da observableList nicht gespeichert werden kann


Person[] arrPerson = new Person[100];

int i=0;

for(Person p : ovList) {

arrPerson[I] = p;

i++;


}

oos.writeObject(arrPerson);

oos.flush();

oos.close();


}[I][/I]
```
[/I]


----------



## Dompteur (5. Jun 2018)

Properties dienen in Java dazu, Voreinstellungen für ein Programm abzulegen. Es handelt sich dabei einfach ausgedrückt um Key-Value-Paare.
Du sollst also diesen Wert nicht erfassen, sondern aus einer Property-Datei einlesen.
Hier mehr dazu : https://docs.oracle.com/javase/tutorial/essential/environment/properties.html


----------



## karlmasutra (5. Jun 2018)

@Dompteur Danke für den Tipp, ich lese mir das mal durch und Versuche es zu verstehen


----------



## karlmasutra (6. Jun 2018)

@Dompteur
Hallo erstmal,
ich habe mich jetzt ein Zeit lang daran versucht, aber ich glaub ich raff es immer noch nicht. Mein Ansatz war jetzt folgender:

1. Ich erzeuge eine Instanz von StringProperty in meinem MainController (in diesem habe ich die Funktion zum abspeichern)
2. ich schreibe zwei getter-Methoden für die StringProperty

```
public String getDateipfad() {
    return dateipfad.get();
}

public StringProperty getDateipfadProperty() {
     return dateipfad;
}
```
3. dann weise ich dem FileChooser die ...InitialDirectory(new File(dateipfad.get()); zu
4. Jetzt übergeben ich mein StringProperty Objekt den Einstellungsdialog
Bis hier hin ist alles gut.

Jetzt möchte ich mein "dateipfad" mit dem Textfeld binden.
Also habe ich eine Methode ActionEvent auf nen Button "gelegt" und sage hier:

```
@FXML
void click_butOk(ActionEvent event) {
    dateipfad.bind(tfSpeicherort.getText());
}
```

Meine Hoffnung war, das ich jetzt den geschrieben text vom Textfeld in meinen "dateipfad" bekomme.

```
The method bind(ObservableValue<? extends String>) in the type Property<String> is not applicable for the arguments (String)
```

Leider geht das nicht, wie man an der Fehlermeldung sieht.

Wo ist mein Denkfehler?

VG


----------



## Dompteur (6. Jun 2018)

Ich bin nun etwas unsicher. Aber anscheinend verstehen wir die Aufgabenstellung unterschiedlich.
So wie ich das verstanden habe, soll das Startverzeichnis nicht hard-codiert im Programm stehen, sondern in einer Property-Datei definiert sein. Diese kann der Benutzer editieren und damit ändern.
Das Programm liest diese nun immer dann aus, wenn der FileChooser aufgerufen wird.
Ich habe nun auf die Schnelle ein JavaFx-Programm zusammengeklickt und meinen Code eingefügt.

```
package application;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import javafx.application.Application;
import javafx.stage.FileChooser;
import javafx.stage.Stage;


public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            callFileChooser();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    private static void callFileChooser() {
        String defaultDirectory = getProperty ("defaultDirectory");

        FileChooser fcSave = new FileChooser();
        fcSave.setTitle("Dateimanager");
        fcSave.setInitialDirectory(new File(defaultDirectory));
        File file = fcSave.showSaveDialog(null);
    }

    private static String getProperty (String name) {

        String defaultDirectory = "";
        Properties prop = new Properties();
        InputStream input = null;

        try {
            input = new FileInputStream("config.properties");
            prop.load(input);
            defaultDirectory = prop.getProperty("defaultDirectory");
            System.out.println(defaultDirectory);
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return defaultDirectory;
    }

    public static void main(String[] args) {
        launch(args);
    }
}
```
Von mir sind die methoden "callFileChooser" und "getProperty", alles andere hat Eclipse bei der Anlage des JavaFx Projekt angelegt.
Du brauchst dann noch im Projekt-Hauptverzeichnis die Datei "config.properties" mit folgendem Inhalt:

```
defaultDirectory=E:/Java
```

Nun zur möglichen Quelle des Missverständnisses: In JavaFx gibt es beim Binding von Model und View ebenfalls den Begriff "Property". Allerdings handelt es sich da um etwas ganz anderes...


----------



## karlmasutra (6. Jun 2018)

Okay also ein ganz anderer Ansatz als ich ihn gemacht habe.
Zum möglichen Missverständnis
Das ist ein Punkt der Aufgabenstellung:

Dialog mit JavaFX-Properties zur Festlegung von Einstellungen (z.B. das Arbeitsverzeichnis für das Speichern von Dateien sowie die Adresse des Servers).
Dazu haben wir in der Vorlesung auch kurz was angesprochen. Aber das war halt in Verbindung mit wert1.bind(wert2). Und da hieß es das wir es so auch machen können wenn es um die Zuweisung des Speicherpfades geht. Also so wie es es probiere, mit dateipfad an das Textfeld zu binden.

Ich habe deinen Vorschlag bei mir jetzt mal umgesetzt. Aber leider wirft er eine
java.io.FileNotFoundException: config.properties (No such file or directory).

Die Datei erstelle ich doch ganz normal über File-->New-->Other-->General-->File?

Hier auch nochmal der aktuelle Quellcode:

```
void click_menueSpeichern(ActionEvent event) throws FileNotFoundException, IOException {
   String defaultDirectory = getProperty ("defaultDirectory");
   FileChooser fcSave = new FileChooser();
   fcSave.setTitle("Dateimanager");
   fcSave.setInitialDirectory(new File(defaultDirectory)); //fuer MAC /Volumes/JAVA/Java ---> fuer Winddoof F:/Java

   File file = fcSave.showSaveDialog(dialogStagePerson);
   ObjectOutputStream oos = new ObjectOutputStream(
   new FileOutputStream(file));
   //observableList in Array speichern, da observableList nicht gespeichert werden kann
   Person[] arrPerson = new Person[100];
   int i=0;
   for(Person p : ovList) {
      arrPerson[i] = p;
      i++;
   }
   oos.writeObject(arrPerson);
   oos.flush();
   oos.close();
}
```


----------



## Dompteur (6. Jun 2018)

Zur Exception:
Du kannst ganz einfach das aktuelle Verzeichnis ermitteln:

```
System.out.println(new File(".").getAbsolutePath());
```
Dort muss dann die Property-Datei liegen. 

Nach deiner Klarstellung glaube ich nun auch, dass es um JavaFx geht.
Du schreibst, dass du folgende Fehlermeldung bekommst:

```
The method bind(ObservableValue<? extends String>) in the type Property<String> is not applicable for the arguments (String)
```
Und zwar zu diesem Code:

```
@FXML
void click_butOk(ActionEvent event) {
    dateipfad.bind(tfSpeicherort.getText());
}
```
Was ist "tfSpeicherort" und welchen Typ hat es ?
Falls es ein Control ist, dann müsste es so aussehen:

```
dateipfad.bind(tfSpeicherort.textProperty());
```


----------



## karlmasutra (6. Jun 2018)

tfSpeicherort ist ein Textfeld, welches ich im SceneBuilder erstellt habe.

Ich habe es gleich ausprobiert und es hat endlich geklappt. Tausend Dank!


----------

