# Excelfile bearbeiten ohne zu überschreiben?



## c_sidi90 (1. Feb 2011)

Ich habe ein Programm in dem mehrere Exceldatein ausgelesen werden. Diese werden an dynamisch erzeugte Tables übergeben.

Wenn ich jetzt jedoch in diese Exceldatei z.B eine Zeile hinzufügen will und diese Zeile demnach in die selbe Exceldatei einfügen möchte, überschreibt das Program immer die vorhandenen Daten und alles geht verloren.

In den Exceldatein die geladen werden wurden schon meist vorher manuell Daten via Excel direkt eingetragen.

Ich arbeite mit der POI Lib von Apache. Also geladen werden die "Datensätze" über ein FileInputStream und einem definierten Workbook (HSSFWorkbook) welches den Dateipfad übergeben bekommt.

Hoffe jemand kennt sich damit aus, hab mich mit Excel und Java nicht wirklich viel auseinandergesetzt.

Mfg:toll:

EDIT: Ps falls etwas unklar : Dateien schreiben via POI funktioniert ja wie ich es verstanden habe mit einem OutputStream welcher auch den Pfad der Datei beinhalten muss, dadurch entsteht die Überschreibung.


----------



## SlaterB (1. Feb 2011)

was genau ist das Problem?
du veränderst ein Excel, willst in eine neue Datei schreiben, und das Original wird fälschlicherweise (auch) geändert?
zeig ein bisschen Code dazu, am besten ein vollständiges Dummy-Programm in dem du nur einen kleinen Wert änderst

wäre es allgemein nicht eine Lösung, das Original am Anfang zu kopieren und dann nur die neue Datei zu bearbeiten?


----------



## Skad (1. Feb 2011)

So wie ich das verstanden habe, hast du z.B. 20 Zeilen. Wenn du jetzt eine 21. Zeile hinzufügen willst, sind die anderen 20 Zeilen verloren. 
Richtig verstanden?

Wenn ja, hilft das vielleicht:
1. Du liest alle Zeilen aus deiner Excel-Datei aus, uns speicherst die in deinem Java Programm.
2. Die Zeilen, die du bearbeiten musst, veränderst du und überschreibst sie sozusagen in Java.
3. Du exportierst alle Dateien aus Java nach Excel und überschreibst alle Zeilen von Excel.

Im obigen Bsp:
1. Alle 20 Zeilen auslesen in Java speichern.
2. 21. Zeile zufügen.
3. Alle 21 Zeilen überschreiben.

Somit hättest du die Zeilen, wo du nichts veränderst mit den gleichen gespeicherten Zeilen überschrieben.
Ich denke, dass das nicht sehr schön programmiert ist, aber wenn du nur paar Excel-Dateien aus- und einliest, wird man vom Zeitaufwand des Programms kaum was merken.


----------



## c_sidi90 (3. Feb 2011)

Danke für die Tipps Skad hat es richtig verstanden. Gibt es keine Lösung ohne immer die Datei erst in ein Array zu speichern und alle Werte in eine neue Datei zu speichern die den selben Namen trägt?


----------



## Empire Phoenix (3. Feb 2011)

JDBC auf Exel treiber sag ich nur, dann kannste die SQL ähnlich ansprechen.


----------



## SlaterB (3. Feb 2011)

kommt drauf an was du machst und wie du es machst (Code!),
allgemein ist es möglich ein Excel-Film zu öffnen, eine Zelle zu bearbeiten oder unten neue hinzuzufügen,
ohne andere Zellen kaputt zu machen


----------



## c_sidi90 (3. Feb 2011)

Hier kann hier nicht den kompletten Source posten, die Einträge erfolgen an verschiedenen Stellen im Programm( sollen es mal).

Hier zum Beispiel:

```
public void erstelleKommentar(){
			
			String geräteString;
			String datumString;
			String autorString;
		try {	
			FileInputStream myInput = new FileInputStream("files/comments/comments.xls");
			POIFSFileSystem myFileSystem = new POIFSFileSystem(myInput);
			HSSFWorkbook myWorkbook = new HSSFWorkbook(myFileSystem);
			HSSFSheet mySheet = myWorkbook.getSheetAt(kategorieBox.getSelectedIndex());
			HSSFRow row = mySheet.getRow(3); // Reihe "3" hab ich zum Test genommen und wird später mit einem Iterator festgelegt.
			
			geräteString = gerätFeld.getText();
			autorString = autorFeld.getText();
			datumString = datumFeld.getText();
			
			/*
			 * Hier müssten dann ja die Einträge in die neuen Zellen gemacht werden
			 */
     
		}catch (Exception e) {
			e.printStackTrace();
			System.out.println("Datei nicht gefunden, bitte Pfad überprüfen");
		}
```


----------



## SlaterB (3. Feb 2011)

dein kompliziertes Hauptprogramm ist ja auch nicht ganz entscheidend dafür,
erstelle dir ein neues Dummy-Excel mit ein paar Daten, sowie ein neues Mini-Programm das daran etwas ändert

mögliche Folgen:
-> alles funktioniert wie gewünscht, dann musst du schauen was in deinem Hauptprogramm dagegen nicht stimmt, evtl. schwierig,
aber zumindest ist bewiesen dass es grundsätzlich möglich ist

-> es verschwinden immer noch Daten, dann diesen nun problemlos zu postenen Code posten + die Excel-Datei,
so dass es jeder nachvollziehen und korrigieren kann, falls es denn korrigierbar ist

bisher hast du quasi nichts gepostet,
natürlich könnte ich selber ein Beispiel zusammenstellen, aber das wäre ja etwas kontraproduktiv arbeitsintensiv für mich


----------



## c_sidi90 (3. Feb 2011)

Lach das will ich dir auch nicht zumuten .

Es muss ja möglich sein mit zB row.getPhysicalNumberOfRows()
und dann setCellValueAt(siehe oben +1) (inhalt).

Wenn man sich die Methoden durchliest sollte dies eigentlich funktionieren, die Befehle eignen sich ja dafür. Ich kann mir nicht vorstellen, dass die POI Lib nicht in der Lage ist, ohne per OutputStream eine Kopie der Datei zu erstellen, einfach ein geladenes Sheet zu editieren :S


----------



## c_sidi90 (3. Feb 2011)

Hab hier ein kleines Beispiel Programm gebastelt, funktioniert jedoch nicht. 


```
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.apache.poi.*;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;

public class EditExcel{
	
	static void test(String fileName) throws IOException{
		
		FileInputStream myInput = new FileInputStream(fileName);
		POIFSFileSystem fileSystem = new POIFSFileSystem(myInput);
		HSSFWorkbook workbook = new HSSFWorkbook(fileSystem);
		HSSFSheet sheet = workbook.getSheetAt(0);
		
		System.out.println(sheet.getPhysicalNumberOfRows()); //return anzahl gefüllte Reihen
		int rows = sheet.getPhysicalNumberOfRows();
		HSSFRow row = sheet.getRow(rows+1);
		HSSFCell cell = row.createCell(0); //soll Zelle in Spalte 0 erstellen
		cell.setCellValue("test b"); //Wert der gesetzt werden soll.
	}
	
	
	public static void main(String[]args) throws IOException{
		
		String fileName = "files/Mappe1.xls";
		test(fileName);
		
	}
}
```

Die Methode ist ziemlich vereinfacht aber enthält alles was ich für mein Hauptprogramm auch benötige um eine Zelle in eine bestehende Datei zu schreiben.


----------



## SlaterB (3. Feb 2011)

was ist jetzt die Frage dazu?
es dürfte weder das Original-Excel noch eine neue Datei erstellt werden ohne jeden Speicher-Aufruf,

ergo passiert im Grunde nix, ist das das Problem?
es wird jedenfalls nichts überschrieben wie in den ersten Postings angedeutet, oder doch?


----------



## c_sidi90 (3. Feb 2011)

Das hier geladene XLS im Stream besteht schon und wurde manuell angelegt, da sind 2 spalten und 2 zeilen gefüllt.

Es soll in der 3ten Reihe in Spalte 0 eine angelegt werden. Das funktioniert jedoch nicht.


----------



## SlaterB (3. Feb 2011)

definiere 'Das funktioniert jedoch nicht.'
meinst du damit dass nach Ausführen des Programm das eingelesene Excel unverändert ist?
das klingt ja ganz anders als bisher 'Daten werden überschrieben' usw.

wie gesagt: wenn eine Festplattendatei geändert werden soll musst du sie speichern, 
prinzipiell nicht anders als beim Bearbeiten einer TXT-Datei,

HSSFWorkbook.write(OutputStream);
OutputStream.close();


----------



## c_sidi90 (3. Feb 2011)

Es soll ja wie schon beschrieben, in eine bestehende gefüllte Exceldatei, eine Zeile bzw evtl auch Spalten ergänzt werden, ohne das die alten schon gefüllten Zellen überschrieben bzw gelöscht werden.

Es funktioniert NICHT in eine bestehende Exceldatei Daten anzuhängen (neue Zelle erstellen & füllen) ohne das die alten Daten verloren gehen. 

In dem Beispielprogramm wird ja auch eine bestehende gefüllte Datei geladen, und soll eine neue gefüllte Zelle hinzugefügt bekommen.

Mit einem Outputstream wird ja die Datei neu erzeugt, somit sind die alten Daten weg und nur die neuen stehen drin. Ich will ja nicht eine Kopie von den alten Daten macen zB via Array und in das neue File samt neuen Zellen importieren.

Hoffe dir ist es jetzt klarer.


----------



## SlaterB (3. Feb 2011)

zum dritten Mal: was genau passiert? es wird doch überhaupt nicht gespeichert? du kannst doch nicht sagen dass Daten verloren gehen?
was ist der Unterschied zwischen verlorenen und nicht verlorenen Daten, was hat das Programm für reale Folgen?

ich habe nun selber ein Test-Excel erstellt und das Programm laufen lassen,
wie ich sicher auch so hätte sehen sollen führt das zu Exceptions, zumindest bei mir, 
in meiner POI-Version kompiliert das aber nicht mal, row.createCell(0) verlangt short als Parameter, int geht nicht

> HSSFRow row = sheet.getRow(rows+1);
row ist in dieser Zeile bei mir null, führt zu NullPointerException später,
denn diese Row existiert nicht nicht, es gibt nur genau 'rows' Zeilen, dahinter ist alles null,
um eine neue Zeile anzulegen musst du  sheet.createRow(rows+1) schreiben, analog zum createCell-Befehl

ist das deine Frage?


----------



## c_sidi90 (3. Feb 2011)

zum 4ten mal, Daten wurden bereits MANUELL in eine XLS eingetragen! Hier lese ich nur die Dateien aus, möchte aber aus dem Programm auch neue Zellen in die bestehende Datei einfügen können.

In dem Programm versuche ich einfach nur in ein bestehendes XLS Zellen hinzuzufügen.

In meinem Beispielprogramm wird eine Datei gelesen, die bereits 2 spalten und jeweils 2 zellen gefüllt hat.

Also möchte ich an "PhysicalNumberOfRows+1" (rückgabe = 3, da bereits 2 reihen gefüllt sind) eine neue Zelle erstellen und diese füllen.


----------



## FetterOtter (3. Feb 2011)

Versuchs mal damit, bei mir klappts wunderbar. Die Eingabe enthält zwei gefüllte Zeilen, diese werden ins workbook eingelesen, eine neue Zeile mit einer neuen Zelle erzeugt, und dann wird der Kram wieder rausgeschrieben. So wie Slater schon sagte...


```
static void test(String fileName) throws IOException{
    
    FileInputStream myInput = new FileInputStream(fileName);
    POIFSFileSystem fileSystem = new POIFSFileSystem(myInput);
    HSSFWorkbook workbook = new HSSFWorkbook(fileSystem);
    HSSFSheet sheet = workbook.getSheetAt(0);
    
    System.out.println(sheet.getPhysicalNumberOfRows()); //return anzahl gefüllte Reihen
    int rows = sheet.getPhysicalNumberOfRows();
    HSSFRow row = sheet.createRow(rows);
    HSSFCell cell = row.createCell(0); //soll Zelle in Spalte 0 erstellen
    cell.setCellValue("test b"); //Wert der gesetzt werden soll.
    
    FileOutputStream myOutput = new FileOutputStream(new File(fileName));   
    workbook.write(myOutput);
    myOutput.close();
}
```


----------



## SlaterB (3. Feb 2011)

c_sidi90 hat gesagt.:


> zum 4ten mal, Daten wurden bereits MANUELL in eine XLS eingetragen!


dem widerspreche ich nirgendwo? ist doch klar, warum sonst ein bestehendes Excel einlesen



> Also möchte ich an "PhysicalNumberOfRows+1" (rückgabe = 3, da bereits 2 reihen gefüllt sind) eine neue Zelle erstellen und diese füllen.


du sagst aber nicht ob das klappt oder nicht, was die genaue Folge ist,
meine Hinweise zum Speichern ignorierst du bisher weitgehend,
ich kann solange nichts neues sagen, mich nur wiederholen


----------



## c_sidi90 (3. Feb 2011)

Super so hats geklappt! Vielen dank, nun mus ich es nurnoch an den etwas komplizierteren Source vom Hauptprogramm anpasen. Hast mir ne Menge Arbeit erspart


----------



## Tinga (5. Apr 2014)

Auch wenn das Thema schon 3 Jahre alt ist, hoffe ich, dass mir noch jemand helfen kann.

Ich bin relativ neu in Java, also entschuldigt bitte die etwas dumme Frage:
Ich habe immer recht große Probleme, wenn ich Codebeispiele aus dem Netz übernehmen möchte. Mir geht es um den Code von „FetterOtter“, den ich testen möchte.  Die PIO Library von Apache habe ich korrekt eingebunden (in anderen Programmen kann ich mit Excel-Dateien arbeiten). Wenn ich nun den Code in meine Klasse kopiere und kompiliere, erscheint die Fehlermeldung, dass die main Methode fehlt – soweit so logisch. Es werden aber keine weiteren Fehler in Eclipse angezeigt. Setze ich den Code in

public static void main (String[] args) { 
	…
};

so erscheinen in dem von „FetterOtter“ geposteten Code in Zeile 1 folgende Fehler:

Multiple Markers at this line
-	Syntax error on token „(„ , ; expected
-	Syntax error, insert ; to complete LocalVariableDeclarationStatement
-	void is an invalid type fort he variable test

Was mache ich falsch?
Eine weitere Frage, die ich dem Zusammenhang habe, ist, ob ich an den Stellen fileName (Zeile 3), myInput (Zeile 4) etc. eine konkrete Datei eingeben muss. Wenn ja ist mir nämlich nicht klar, was ich z. B. bei myInput oder fileSystem (Zeile 5) eingeben muss.

Hoffe, es ist verständlich beschrieben.

Vielen, vielen Dank für Eure Hilfe und Mühe,

Tinga


----------



## FetterOtter (7. Apr 2014)

Hallo Tinga,

wenn du das komplette Code-Beispiel aus Post #17 in deine Main-Methode kopiert hast, dann klappt es so auch nicht. Denn dann hast du eine Methode in eine Methode kopiert.
Pack das alles hinter die Main-Methode, und aus der Main rufst du dann die Test-Methode auf:

```
test("C:/MeinExcelFile.xls");
```
Die Datei muss es natürlich geben.
Aber ansonsten musst du nichts weiter vorgeben.


----------



## Tinga (8. Apr 2014)

Hallo Fetter Otter,


vielen Dank für Deine Hilfe. 

Ich sitze schon über eine Stunde dran und bekomme es wieder nicht hin, daher entschuldige bitte, wenn ich nochmal frage. 
Die Methoden hätte ich nicht ineinander kopieren dürfen, das ist mir mittlerweile klar. 
Wenn ich Dich richtig verstanden habe, ist das

test("C:/MeinExcelFile.xls");

der Methodenaufruf, der in die Main Methode soll. Ich habe nur noch den Dateipfad geändert. Die Datei ist ebenfalls vorhanden. Importiert ist auch alles. Trotzdem bekomme ich diese Fehlermeldung: 

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
	Unhandled exception type IOException

	at App.main(App.java:18)

Ich weiß auch, was die IOException ist. Trotzdem weiß ich nicht, was falsch ist. Das ist der komplette Code dazu:

[JAVA=42]
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;


public class App {



	public static void main (String[] args) {
		test("C:/Users/max/Desktop/Max/Studium/Master/00_Hiwi/20140307_Eclipse/140407_Test/Excel.xls");

	}



    public static void test(String fileName) throws IOException{

        FileInputStream myInput = new FileInputStream("C:/Users/max/Desktop/Max/Studium/Master/00_Hiwi/20140307_Eclipse/140407_Test/Excel.xls");
        POIFSFileSystem fileSystem = new POIFSFileSystem(myInput);
        HSSFWorkbook workbook = new HSSFWorkbook(fileSystem);
        HSSFSheet sheet = workbook.getSheetAt(0);

        System.out.println(sheet.getPhysicalNumberOfRows()); //return anzahl gefüllte Reihen
        int rows = sheet.getPhysicalNumberOfRows();
        HSSFRow row = sheet.createRow(rows);
        HSSFCell cell = row.createCell(0); //soll Zelle in Spalte 0 erstellen
        cell.setCellValue("test b"); //Wert der gesetzt werden soll.

        FileOutputStream myOutput = new FileOutputStream(new File("C:/Users/max/Desktop/Max/Studium/Master/00_Hiwi/20140307_Eclipse/140407_Test/Excel.xls"));  
        workbook.write(myOutput);
        myOutput.close();
    } 


}

[/code]

Was mache ich falsch?
Ich habe deinen Code bereits letzte Woche verwenden wollen und hatte eben besagtes Problem. Ich habe den Code dann so modifiziert, dass ich den Methodenaufruf „test“ weggelassen habe und stattdessen den Rest des Codes in einen try-catch Block gepackt habe. Damit war alles auch schon letzte Woche lauffähig. Aber ich bekomme den Code Stand jetzt so nicht zum Laufen.
Das ist der Ausschnitt des von mir modifizierten Codes, der funktioniert, falls das hilfreich ist:

[JAVA=42]
 try {
            		FileInputStream myInput = new FileInputStream("C:/Users/max/Desktop/Max/Studium/Master/00_Hiwi/20140307_Eclipse/140405_ActionListener/Excel.xls");
            	    POIFSFileSystem fileSystem = new POIFSFileSystem(myInput);
            	    HSSFWorkbook workbook = new HSSFWorkbook(fileSystem);
            	    HSSFSheet sheet = workbook.getSheetAt(0);


            		    System.out.println(sheet.getPhysicalNumberOfRows()); //return anzahl gefüllte Reihen
            		    int rows = sheet.getPhysicalNumberOfRows();
            		    HSSFRow row = sheet.createRow(rows);
            		    HSSFCell cell = row.createCell(1); //soll Zelle in Spalte 1 erstellen
            		    cell.setCellValue(bezeichnung); //Wert der gesetzt werden soll.
            		    //HSSFCell cell1 = row.createCell(2); //soll Zelle in Spalte 2 erstellen
            		    //cell1.setCellValue(art); //Wert der gesetzt werden soll.
            		    //HSSFCell cell2 = row.createCell(3); //soll Zelle in Spalte 1 erstellen
            		    //cell2.setCellValue(material); //Wert der gesetzt werden soll.


            		    FileOutputStream myOutput = new FileOutputStream(new File("C:/Users/max/Desktop/Max/Studium/Master/00_Hiwi/20140307_Eclipse/140405_ActionListener/Excel.xls"));  
            		    workbook.write(myOutput);
            		    myOutput.close();
            		} catch (Exception ex) {

            		};
[/code]


Hoffe, es ist verständlich beschrieben.

Vielen Dank nochmals für Deine Hilfe,
Tinga


----------



## FetterOtter (8. Apr 2014)

Sorry, hätte ich der Vollständigkeit halber mitposten sollen.
Wie du siehst, schmeißt die Methode "test" ggf. eine IOException (Zeile 24).
Wenn du diese Methode aufrufst (Zeile 18), müsstest du einen Try-/Catch-Block drumherumbauen:

```
try
{
  test("C:/Users/max/Desktop/Max/Studium/Master/00_Hiwi/20140307_Eclipse/140407_Test/Excel.xls");
} 
catch (IOException e)
{
  System.out.println(e.getMessage());
  e.printStackTrace();
}
```


----------



## Tinga (8. Apr 2014)

Super, es funktioniert. Vielen, vielen Dank.
Jetzt ist mir auch vom Verständnis her einiges klarer geworden.
Danke Dir.

Tinga


----------



## ms_cikar (22. Jun 2015)

Hallo Leute,

Vielen Dank für die Informationen. 

ich habe das Problem wenn ich das ganze für neuere Excel Version probiere mit dem XSSFworkbook statt HSSFworkbook
kriege ich permanent  Fehlermeldung. 


POIFSFileSystem fileSystem = new POIFSFileSystem(myInput);
XSSFWorkbook workbook = new XSSFWorkbook(fileSystem);
XSSFSheet sheet = workbook.getSheetAt(0);

hmmm was muss ich machen 

Vielen dank


----------



## Harry Kane (22. Jun 2015)

Doku lesen und einen gültigen Konstruktor verwenden.
XSSFWorkbook kann entweder mit einer Instanz von java.io.File, oder mit java.io.InputStream oder mit einem String oder mit einer Instanz von org.apache.poi.openxml4j.opc.OPCPackage konstruiert werden. POIFSFileSystem ist keines von den vieren.


----------

