Verzeichnisse mit Inhalt nach SMB-Share kopieren

lal000r

Mitglied
Hallo zusammen,

ich hänge seit längerer Zeit an einer bestimmten Stelle bei der Implementierung eines Kopierprogramms fest.
Zur Einbindung von SMB-Shares greife ich auf die Jcifs Bibliothek zurück - hier ist auch mein Problem:

Ich bekomme es nicht hin, die zu kopierenden Verzeichnisse mit SmbFile.mkdirs() zu erstellen. Laut API-Doc soll das auch nicht funktionieren - wenn die SMB-Url aber in einem bestimmten Format vorliegt, soll es funktionieren.

Zunächst mach ich also Folgendes:
File-Objekte instanziieren und an die Methode copyDir() übergeben:
Java:
LocalFile file = new LocalFile("C:/Neuer Ordner");
SmbFile smbfile = new SmbFile("smb://192.168.178.250/Daten/ISOs/",new NtlmPasswordAuthentication("", "user", "pass"));

try {
		FileOperation.copyDir(file, smbfile);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

Diese Methode kopiert die Verzeichnisse rekursiv, scheitert aber direkt am dest.mkdir(). :
Java:
	public static void copyDir(File src, SmbFile dest)
			throws FileNotFoundException, IOException {
		if (src.isDirectory()) {
			File[] files = src.listFiles();
			if (files != null) {
				for (File f : files) {
					dest.mkdir(); // Erstelle gegebenfalls neuen Unterordner am Zielort.
					copyDir(f, new SmbFile(dest.getPath()+ f.getName())); // Kopiere alles in diesem Unterordner
				}
			}
		}
		else {
			copyFile(src, dest);
		}
	}

Und zu guter Letzt noch die CopyFile-Methode:
Java:
   public static void copyFile(File src, SmbFile dest) throws FileNotFoundException, IOException {
        SmbFileOutputStream fileout = null;
        FileInputStream filein = null;
        new File(dest.getPath().replaceAll(dest.getName(), "")).mkdirs();
        System.out.println(dest.getPath().replaceAll(dest.getName(), ""));
        try {
            filein = new FileInputStream(src);
            fileout = new SmbFileOutputStream(dest);
            int count;
            byte[] data = new byte[8192];
            while ((count = filein.read(data)) != -1) {
                fileout.write(data, 0, count);
            }
        } finally {
            safeClose(fileout);
            safeClose(filein);
        }
    }

Das Problem ist also, dass ich kein Verzeichnis im SMB-Share erstellen kann und folgende Exception bekomme:

jcifs.smb.SmbException: Cannot create a file when that file already exists.
at jcifs.smb.SmbTransport.checkStatus(SmbTransport.java:563)

Die zu spiegelnden Ordner sind natürlich im SMB-Share noch nicht vorhanden (auch wenn die Exception das vermuten lässt).
Hat jemand Erfahrung mit Jcifs und kann mir sagen, wie es am besten möglich ist, Verzeichnisse in ein SMB-Share zu spiegeln? :)
Vielen Dank schonmal!
 
Zuletzt bearbeitet:
M

maki

Gast
Code:
jcifs.smb.SmbException: Cannot create a file when that file already exists.
at jcifs.smb.SmbTransport.checkStatus(SmbTransport.java:563)
Was steht denn in dieser Zeile?

Ins Blaue geraten:
Solltest wohl besser prüfen ob der Ordner nicht schon erstellt wurde (zB. durch einen vorherigen Aufruf der copyDir Methode) bevor du mkdirs aufrufst.
 

lal000r

Mitglied
Code:
jcifs.smb.SmbException: Cannot create a file when that file already exists.
at jcifs.smb.SmbTransport.checkStatus(SmbTransport.java:563)
Was steht denn in dieser Zeile?

Ins Blaue geraten:
Solltest wohl besser prüfen ob der Ordner nicht schon erstellt wurde (zB. durch einen vorherigen Aufruf der copyDir Methode) bevor du mkdirs aufrufst.

Die angegebene Zeile in der Exception steht irgendwo in der SmbTransport-Klasse, die ich jedoch nicht geschrieben habe, sondern lediglich mit der Jcifs.jar benutze. Bei mir im Code tritt es direkt beim ersten dest.mkdir() auf.

Später werde ich sicherlich vorher noch prüfen, ob diese Ordner bereits existieren, aber derzeit ist der Zielordner leer. (Alles nur zum Testen)
Vielleicht sollte ich noch erwähnen, dass diese Methoden bei normalen File-Objekten einwandfrei funktionieren.
Es hat eindeutig was mit dem SMB-Share und vielleicht dessen URL zu tun.
 
Zuletzt bearbeitet:
N

nillehammer

Gast
Kenne mich mit dem SMBFile-Krams jetzt nicht so aus, aber das hier sieht merkwürdig aus (siehe mein Kommentar im Code):
Java:
public static void copyDir(File src, SmbFile dest)
            throws FileNotFoundException, IOException {
        if (src.isDirectory()) {
            File[] files = src.listFiles();
            if (files != null) {
                for (File f : files) {
                    // Hier legst Du wiederholt denselben Ordner auf dem Ziel an, denn "dest" ändert sich während
                    // des Schleifendurchlaufs nicht. Das gehört meiner Meinung nach aus der for-Schleife raus,
                    // direkt vor "File[] files = src.listFiles();"
                    dest.mkdir(); // Erstelle gegebenfalls neuen Unterordner am Zielort.
                    
                    copyDir(f, new SmbFile(dest.getPath()+ f.getName())); // Kopiere alles in diesem Unterordner
                }
        }
        else {
            copyFile(src, dest);
        }
    }
 
Zuletzt bearbeitet von einem Moderator:

lal000r

Mitglied
Ja danke, da hast du recht. Das hat wahrscheinlich den Effekt, dass in dem Moment die gleichnamigen bereits erstellten Ordner wieder überschrieben werden, richtig? Denn hier kommt auf lokalen Verzeichnissen keine Exception, wenn ich das in der Schleife lasse.
Den eigentlichen Fehler behebt das allerdings nicht. Das Erstellen der Ordner auf einem SMB-Share funktioniert weiterhin nicht.
 
Zuletzt bearbeitet:
N

nillehammer

Gast
Ja danke, da hast du recht. Das hat wahrscheinlich den Effekt, dass in dem Moment die gleichnamigen bereits erstellten Ordner wieder überschrieben werden, richtig?
Wie gesagt, kenne die SMB-Lib nicht. Aber ich denke, das ist nicht richtig. Ich glaube eher, dass es beim ersten Durchlauf noch funktioniert und beim zweiten dann die von Dir in der Ursprungsfrage erwähnte Exception fliegt.
Denn hier kommt auf lokalen Verzeichnissen keine Exception,
Dazu hat maki schon die Antwort geschrieben. Vielleicht nicht ausführlich genug. Nur, weil ein SMBFile sich wegen der gleichnamigen Methoden so "anfühlt", wie ein normales File, heißt das nicht, dass sich die Methoden absolut identisch verhalten müssen. Die File-mkdir ist eben so implementiert, dass sie durch returnen von false signalisiert, dass das Dir nicht erzeugt werden konnte. Währen SMBFile das mit einer Exception macht. Du kannst nicht erwarten, dass Code,der die File-API aufruft, sich genauso verhält, wie Code, der letztendlich ja über Netzwerk arbeitet.
 

lal000r

Mitglied
Wie gesagt, kenne die SMB-Lib nicht. Aber ich denke, das ist nicht richtig. Ich glaube eher, dass es beim ersten Durchlauf noch funktioniert und beim zweiten dann die von Dir in der Ursprungsfrage erwähnte Exception fliegt.

Also nach Debugging und Einbau von Testausgaben erweckt es eher den Eindruck, als wenn die Exception direkt beim ersten Aufruf geworfen wird. Eine dahinter liegende Ausgabe wird dann gar nicht erst ausgeführt.

Dazu hat maki schon die Antwort geschrieben. Vielleicht nicht ausführlich genug. Nur, weil ein SMBFile sich wegen der gleichnamigen Methoden so "anfühlt", wie ein normales File, heißt das nicht, dass sich die Methoden absolut identisch verhalten müssen. Die File-mkdir ist eben so implementiert, dass sie durch returnen von false signalisiert, dass das Dir nicht erzeugt werden konnte. Währen SMBFile das mit einer Exception macht. Du kannst nicht erwarten, dass Code,der die File-API aufruft, sich genauso verhält, wie Code, der letztendlich ja über Netzwerk arbeitet.

Das ist mir bewusst. Wenn also die Ordnerstruktur in letzter Konsequenz korrekt erzeugt wurde, wurde vielleicht zwischendurch einige Male "false" zurückgegeben anstatt einer Exception. Das meintest du, oder?

In der Zwischenzeit habe ich noch folgende Aussagen gefunden (meine URL liegt aber eigentlich im letztgenannten Format vor):
Java:
(new SmbFile("smb://server/share/")).mkdir()  // not possible
(new SmbFile("smb://server/")).mkdir()  // not possible
(new SmbFile("smb://workgroup/")).mkdir()  // not possible
(new SmbFile("smb://server/share/directory/")).mkdir()  // ok if you have permission
 
N

nillehammer

Gast
Also nach Debugging und Einbau von Testausgaben erweckt es eher den Eindruck, als wenn die Exception direkt beim ersten Aufruf geworfen wird. Eine dahinter liegende Ausgabe wird dann gar nicht erst ausgeführt.
Es ist immer gut, Debugging und Testausgaben zu benutzen, aber da wir ja beide schon festgestellt haben, dass die Verzeichniserzeugung aus der Schleife raus gehört, ist es vielleicht eine gute Idee, das mal zu machen und dann den neuen Code zu debuggen.
Wenn also die Ordnerstruktur in letzter Konsequenz korrekt erzeugt wurde, wurde vielleicht zwischendurch einige Male "false" zurückgegeben anstatt einer Exception. Das meintest du, oder?
Ja, genau das meinte ich. Und, weil Du dieses "false" wahrscheinlich nirgends speicherst und auswertest, ist es Dir wahrscheinlich nicht aufgefallen. Das ist übrigens auch der Grund, warum ICH das returnen spezieller Werte zur Anzeige von Fehlern fragwürdig finde. Eine Exception ist in Java nunmal das eindeutige Mittel, um einen Fehler anzuzeigen. Aber es gibt ja auch Exception-schmeißende Methoden in der File-API.... ich schweife gerade ab...
 
Zuletzt bearbeitet von einem Moderator:
T

tröööt

Gast
@TO
lesen ... und das gelesene verstehen ist nicht deine stärke oder ?

Was steht denn in dieser Zeile?

mit dieser frage war nicht gemeint wo die exception auftritt ... sondern was deren aussage ist :

jcifs.smb.SmbException: Cannot create a file when that file already exists

oder auf deutsch : die exception wird geworfen weil eine datei / ein ordner an einer bestimmten stelle nicht neu erstellt werden kann WEIL DIESER BEREITS EXISTIERT
 
N

nillehammer

Gast
Ok, dann nächste Baustelle Du übergibst dieses SMBFile an Deine copyDir-Methode:
Java:
SmbFile smbfile = new SmbFile("smb://192.168.178.250/Daten/ISOs/",new NtlmPasswordAuthentication("", "user", "pass"));
 
try {
        FileOperation.copyDir(file, smbfile);
Da dieser Pfad so hart verdrahtet ist, nehme ich an, dass das ein Share ist, den es genauso schon gibt. Genau auf diesem Objekt rufst Du dann mkdir() auf. Du willst doch eigentlich erst die Unterordner des o.g. Pfades erzeugen oder?
 

lal000r

Mitglied
@TO
lesen ... und das gelesene verstehen ist nicht deine stärke oder ?



mit dieser frage war nicht gemeint wo die exception auftritt ... sondern was deren aussage ist :

jcifs.smb.SmbException: Cannot create a file when that file already exists

oder auf deutsch : die exception wird geworfen weil eine datei / ein ordner an einer bestimmten stelle nicht neu erstellt werden kann WEIL DIESER BEREITS EXISTIERT


Jaa okay, ganz locker bleiben. Ich habe schon verstanden, dass laut Exception der Pfad schon existiert. Nur tut er es eben nicht, es sei denn, die Methode arbeitet mit falschen Parametern... und da kommt das ins Spiel. Autsch.

Ok, dann nächste Baustelle Du übergibst dieses SMBFile an Deine copyDir-Methode:
Java:
SmbFile smbfile = new SmbFile("smb://192.168.178.250/Daten/ISOs/",new NtlmPasswordAuthentication("", "user", "pass"));
 
try {
        FileOperation.copyDir(file, smbfile);
Da dieser Pfad so hart verdrahtet ist, nehme ich an, dass das ein Share ist, den es genauso schon gibt. Genau auf diesem Objekt rufst Du dann mkdir() auf. Du willst doch eigentlich erst die Unterordner des o.g. Pfades erzeugen oder?

Richtig... der Share ist: "smb://192.168.178.250/Daten/" und ein bereits vorhandener Ordner im Share ist "ISOs". :shock: Das würde auch erklären, warum direkt das erste mkdir() fehlschlägt. Trotzdem stehe ich auf dem Schlauch, wie ich hier direkt das zu erstellende Unterverzeichnis mitgebe. :)
 
N

nillehammer

Gast
Trotzdem stehe ich auf dem Schlauch, wie ich hier direkt das zu erstellende Unterverzeichnis mitgebe.
Java:
static final String USER = "user";
static final String PASS = "pass";
static final NtlmPasswordAuthentication AUTH = new NtlmPasswordAuthentication("",USER , PASS);
static final String BASE_PATH = "smb://192.168.178.250/Daten/ISOs/";


... dann in irgend einer Methode...
final String subPath = ermittleSubPath(); // wie auch immer Du den SubPath ermittelst, 
                                                    // kann auch ein Methodenparameter sein
final String newPath = BASE_PATH + subPath;
final SmbFile smbfile = new SmbFile(newPath,AUTH);

if(!smbfile.exists()) {
  smbfile.mkdir();
}
...
Du wunderst Dich vielleicht, warum Du jetzt relativ oft neue SmbFiles erzeugst. Aber das sind ja auch genau die, die es auf dem Server noch nicht gibt. Je neuem File auf dem Server ein new SmbFile. Darauf wird es glaube ich hinauslaufen.

P.S. Ach ja, und ein Blick in die API-Dokumentation lohnt wirklich. Ist auch recht übersichtlich, weil es nicht sehr viele Klassen sind: JCIFS API
 
Zuletzt bearbeitet von einem Moderator:

lal000r

Mitglied
Java:
static final String USER = "user";
static final String PASS = "pass";
static final NtlmPasswordAuthentication AUTH = new NtlmPasswordAuthentication("",USER , PASS);
static final String BASE_PATH = "smb://192.168.178.250/Daten/ISOs/";


... dann in irgend einer Methode...
final String subPath = ermittleSubPath(); // wie auch immer Du den SubPath ermittelst, 
                                                    // kann auch ein Methodenparameter sein
final String newPath = BASE_PATH + subPath;
final SmbFile smbfile = new SmbFile(newPath,AUTH);

if(!smbfile.exists()) {
  smbfile.mkdir();
}
...
Du wunderst Dich vielleicht, warum Du jetzt relativ oft neue SmbFiles erzeugst. Aber das sind ja auch genau die, die es auf dem Server noch nicht gibt. Je neuem File auf dem Server ein new SmbFile. Darauf wird es glaube ich hinauslaufen.

P.S. Ach ja, und ein Blick in die API-Dokumentation lohnt wirklich. Ist auch recht übersichtlich, weil es nicht sehr viele Klassen sind: JCIFS API


Danke für deine Anregungen. Wenn ich die Methode copyDir() erstmal nicht verändern würde, würde es meiner Meinung nach schon folgender Aufruf tun, um beim ersten Ausführen ein passendes dest-SmbFile zu übergeben. In diesem Fall habe ich einfach den Namen des aktuellen File-Objekts angehangen.
Java:
SmbFile smbfile = new SmbFile("smb://192.168.178.250/Daten/ISOs/"+file.getName(),new NtlmPasswordAuthentication("", "user", "pass"));
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
J [SCP mit Java] wie kann ich Verzeichnisse anlegen? Netzwerkprogrammierung 2
J Java Server empfängt php inhalt nicht Netzwerkprogrammierung 1
C Inhalt einer .JPG Datei in einen OutputStream schreiben? Netzwerkprogrammierung 10
P Variablen(inhalt) Abgleich Java und PHP schlägt fehl Netzwerkprogrammierung 6
O TCP Paketverlust? bzw inhalt Verlust Netzwerkprogrammierung 17
L Web-Seiten Inhalt auslesen und in textfile speichern Netzwerkprogrammierung 2
G inputstream hat plötzlich weniger inhalt Netzwerkprogrammierung 8
Y Inhalt aus Textfield in OutputStream packen Netzwerkprogrammierung 4
Dann07 Audio streamen bricht immer ab nach kurzer Zeit Netzwerkprogrammierung 6
G seite nach posten eines html-forms laden Netzwerkprogrammierung 0
N websocket - keine Daten mehr nach ca 80 Sekunden Netzwerkprogrammierung 0
C Gerenderte Website nach der ausführung von JavaScript als HTML Code aus lesen Netzwerkprogrammierung 4
F Wiederverbinden nach socket Abbruch Netzwerkprogrammierung 1
T Socket sendet erst nach socket.close() Netzwerkprogrammierung 2
B Nach Verbindung gleich ObjectStream empfangen Netzwerkprogrammierung 1
N HTTP Apache 4.2.1 HttpClient 302 nach Login und auf den weiteren Seiten. Netzwerkprogrammierung 5
K Socket Chat-GUI eigenes Event nach Empfangen Netzwerkprogrammierung 2
G Cookie Verwaltungs Problem nach Login auf InetSeite (Wo utma-Cookie?) Netzwerkprogrammierung 18
P Datenpakete nach Australien Netzwerkprogrammierung 7
C Socket Identifikation des clients nach der accept() Methode Netzwerkprogrammierung 2
J Nach Dateiversand werden keine Nachrichten mehr übertragen Netzwerkprogrammierung 11
J Nachricht kommt erst nach beendigung der Anwendung an Netzwerkprogrammierung 4
D Socket Automatischer Reconnect nach einem Disconnect. Netzwerkprogrammierung 4
S Socket nach anderen clients im netzwerk suchen Netzwerkprogrammierung 3
B IP nach gewissen Kriterien überprüfen Netzwerkprogrammierung 5
V JNLP startet nicht !!?!! (je nach PC) Netzwerkprogrammierung 1
H Object Cast Problem nach Übertragung mit Log4j Netzwerkprogrammierung 5
DeviAn Über ein Linux Server ein Windows Server nach einer File fragen Netzwerkprogrammierung 6
Q Datein von Windows nach Mac senden Netzwerkprogrammierung 4
L RMI Programm beendet ohne Fehler sofort nach Start (Windows 2000) Netzwerkprogrammierung 7
T Zugriffsverweigerung nach Dateitransfer Netzwerkprogrammierung 7
T Nach Servern suchen Netzwerkprogrammierung 2
K Bad Request nach Form Login in Jakarta HttpClient Netzwerkprogrammierung 4
L nach Servern suchen Netzwerkprogrammierung 2
M ordner nach socket-übertragung defekt Netzwerkprogrammierung 5
B Im eingelesenen Text nach einem Wort suchen Netzwerkprogrammierung 46
M serialisierung funktioniert nur nach neuer instanzierung Netzwerkprogrammierung 3
W fehlerhafte Datei nach Dateitransfer per ServletOutputStream Netzwerkprogrammierung 2
A Client stürzt nach versand ab Netzwerkprogrammierung 13
M Verbindung nach Serverabsturz wieder aufbauen Netzwerkprogrammierung 9
S Unix Datei vom Server nach Windows übertragen Netzwerkprogrammierung 8
G Port belegt nach Server restart Netzwerkprogrammierung 5
G Socket wird nach Portscann geschlossen Netzwerkprogrammierung 2
N Verarbeitung nach Weiterleitung in Sockets Netzwerkprogrammierung 2
L Frage nach Socket Netzwerkprogrammierung 4

Ähnliche Java Themen


Oben