# Netzlaufwerke erkennen



## palador (13. Okt 2010)

*Hallo Javamenschen,*

hier mein kleines Problem mit java.io.File:

Situation:
Ziel ist ein TreeModel für Swing, welches den Dateibaum vom Arbeitsplatz an darstellt. Eine Ebene unter dem Arbeitsplatz befinden sich die anderen Laufwerke, die ich via _File.listRoots()_ ermittle.
Das ganze funktioniert auch wunderbar.
Nur ist der Zugriff auf Netzlaufwerke recht langsam. Weil wenn man auf untergeordnete Files Operationen durchführt wie _.isFile()_ oder _.length()_ wird jedesmal eine Abfrage losgeschickt.
Wireshark sagt: bei _.listFiles()_ werden via SMB alle benötigten Informationen (ob Datei, Dateigröße...) für jede Datei mitgeliefert. Sie nochmal zu besorgen ist nicht sinnvoll.
Klar: die Implementateure wollten sicherstellen, das man die aktuellste Information erhällt, Dateien ändern sich ja auch mal.
Nun habe ich JCifs getestet und da funktioniert alles so wie ich möchte, d.h. nur eine Abfrage aus der alle Informationen verwertet werden.

Problem:
File.listRoots() gibt mir alle Laufwerke, die das System kennt. Wie erkenne ich ein Netzlaufwerk? Und wie bekomme ich die SMB-URL raus?

Beispiel:
Netzlaufwerk _z:\_ verweist auf _\\blubHost\irgenteinordner\_
_File rootLocal = new File("c:\\");
File rootNet = new File("z:\\");_
wie bekomme ich raus, das _rootLocal _ein Netzlaufwerk ist und _rootNet _nicht?
wie komme ich von _rootNet _auf _\\blubHost\irgenteinordner\_?


```
public static void main(String[] args) throws Exception {
		// z: ist ein Netzlaufwerk, beide zeigen auf den Gleichen Ordner im
		// Netzwerk
		File netDrive = new File("z:\\");
		SmbFile smbNetDrive = new SmbFile("smb://blubHost/irgenteinordner/");
		
		// unterdateien listen
		File[] files = netDrive.listFiles(); // diese Abfrage würde reichen
		for(File file : files) {
			String name = file.getName();
			long length = file.length(); // !!! extra abfrage !!!
			
			// ... do sth
		}
		
		// das gleiche mit jcifs
		SmbFile[] smbFiles = smbNetDrive.listFiles(); // einzigste abfrage
		for(SmbFile smbFile : smbFiles) {
			String name = smbFile.getName();
			long length = smbFile.length(); // !!! keine extra abfrage !!!
			
			// ... do sth
		}

	}
```

Sorry, dass es soviel geworden ist, hab ein Problem micht kurzzufassen.
Danke im vorraus.

Palador


----------



## Empire Phoenix (13. Okt 2010)

Hm normalerweise sit ja der sinn von entzwerklaufwerken, dass diese sich vollkomen tranzparent verhalten.
Ich weiß das es über c/c++ möglich ist darauf zugriff zu erhalten bo es sich um netzlaufwerke handelt, aber rein mit java ist das denke ich nciht möglich.


----------



## Gast2 (14. Okt 2010)

Kannst über "net share" und "net use" und Runtime.exec() arbeiten. Aber so wirklich schön ist das auch nicht


----------



## palador (14. Okt 2010)

Ok, erstmal besser als nichts. Da das Programm sowieso meistens unter Windows läuft, kann ich net use ja verwenden. Wenns nicht klappt (z.B. auf anderer Plattform) , ist es ja auch nicht so wild, es funktioniert ja auch mit den klassischen java.io.File, halt blos recht lahm.
Hier meine (temporäre) Lösung:

```
package org.javaforum.bsp;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.filechooser.FileSystemView;

public class NetDriveTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		for (File root : File.listRoots()) {
			System.out.println(root + ": " + getNetworkPath(root));
		}
	}

	private static Pattern NETWORK_PATH_PATTERN = Pattern.compile("\\\\\\\\[^\\\\]+\\\\.+"); // :)

	/**
	 * Converts a root-{@link File} to a network path.
	 * 
	 * @param rootFile
	 * @return the networkpath or <code>null</code> if <code>rootFile</code> is
	 *         not a netdrive, a filesystemroot or if it is not possible to find
	 *         out the networkpath
	 * @throws IllegalArgumentException
	 *             when <code>rootFile</code> is <code>null</code>
	 */
	public static String getNetworkPath(File rootFile) throws IllegalArgumentException {
		if (rootFile == null) {
			throw new IllegalArgumentException("rootFile must not be null");
		}

		String result = null;

		// test if is rootfile
		if (FileSystemView.getFileSystemView().isFileSystemRoot(rootFile)) {

			// test if platform is windows
			if (System.getProperty("os.name").toLowerCase().contains("win")) {

				// try via net use (works on windows only)
				String drive = rootFile.getAbsolutePath();
				int index = drive.indexOf(':');
				if (index != -1) {
					drive = drive.substring(0, index + 1);
				}
				InputStream procIS = null;
				try {
					Process proc = Runtime.getRuntime().exec(new String[] {
							"cmd", "/C", "net use " + drive
					});
					procIS = proc.getInputStream();
					ByteArrayOutputStream bArrOS = new ByteArrayOutputStream(1024);

					// stream procIS to bArrOS
					int size;
					byte[] buf = new byte[32];
					while ((size = procIS.read(buf)) >= 0) {
						bArrOS.write(buf, 0, size);
					}

					// byteArray to String
					// TODO: find out consolecharset
					String procOutput = bArrOS.toString("US-ASCII");

					// extract netpath if any
					Matcher matcher = NETWORK_PATH_PATTERN.matcher(procOutput);
					result = (matcher.find()) ? matcher.group() : null;

				} catch (IOException e) {

					// TODO: log exception
				} finally {
					// close procstream
					if (procIS != null) {
						try {
							procIS.close();
						} catch (IOException e) {
							// TODO: log exception
						}
					}
				}

			}
		}

		return result;

	}
}
```

Aber vieleicht kennt ja jemand noch eine elegantere Lösung?


----------

