81 Copyright 1996-1997 by Axel T. Schreiner. All Rights Reserved. Information über Dateien — main/Ls Ls informiert über den aktuellen Katalog oder über die Pfade, die als Argumente angegeben sind. Mit der Flagge -l wird möglichst viel Information ausgegeben. Mit der Flagge -d wird Information über einen Katalog statt über seinen Inhalt ausgegeben. Nachrangig dazu wird mit der Flagge -R ein Katalog rekursiv traversiert. Ls ist eine einfache Version des UNIX-Kommandos ls und illustriert einige der Möglichkeiten, die die Klasse File zur Umgang mit Dateien bietet. ist deutlich so konzipiert, daß nur portable Informationen verfügbar sind. Leider hat die Klasse unter Windows leichte Probleme mit Platten. Unter UNIX kann man symbolische Links nicht erkennen, was Ls gefährlich macht. File Für Ls gibt es keine Randbedingungen, folglich kann die Klasse von MainClient abstammen. Wie üblich werden die Flaggen notiert — da es nur ein Klienten-Objekt gibt, genügen Instanzvariablen. {programs/main/Ls.java} import java.io.*; import lib.main.*; /** A client class to implement a simple ’ls’ command */ public class Ls extends MainClient { public static void main (String args []) { Main main = new Main(new Ls()); try { System.exit(main.run(args)); } catch (IllegalArgumentException e) { System.err.println("usage: "+main.name+" [-dlR] path..."); } catch (Exception e) { main.error(e); } System.exit(1); } /** record flags */ public boolean dflag, lflag, Rflag; public boolean flag (char ch, Main m) throws IOException { switch (ch) { case ’d’: dflag = true; return true; case ’l’: lflag = true; return true; case ’R’: Rflag = true; return true; default: return super.flag(ch, m); } } {} 82 Die Argumente kann man an eine zentrale Funktion ls(dirname, path) weiterleiten: {programs/main/Ls.java} /** no argument -- process current directory */ public int arg (Main m) throws IOException { ls("", System.getProperties().getProperty("user.dir", ".")); return 0; } /** argument -- process a path */ public int arg (String arg, Main m) throws IOException { ls(arg == null || arg.equals(".") ? "" : arg+File.separator, arg); return 0; } {} Man kann eigentlich nicht davon ausgehen, daß der Name . überall auf den aktuellen Katalog verweist. Mit der System-Property user.dir kann man den aktuellen Katalog feststellen. Zur Verschönerung der Ausgabe übergibt man den Katalog-Präfix separat vom kompletten Pfad. liefert bei toString() nur einen Pfad . Zum Ersatz unter Kontrolle einer Flagge dient eine Komponentenklasse. Da sie in Blöcken verwendet wird, kann sie nicht lokal in ls() sein: File {programs/main/Ls.java} /** A class to produce information about a path */ protected class File extends java.io.File { /** constructs, even if path does not exist */ public File (String path) { super(path); } /** provides a directory listing */ public String toString () { StringBuffer s = new StringBuffer(); if (lflag) { if (isDirectory()) s.append("d"); else if (isFile()) s.append("-"); else s.append("?"); s.append(canRead() ? "r" : "-") .append(canWrite() ? "w" : "-") .append("\t" + length() + "\t"); } return s.append(getPath()).toString(); } } {} 83 File hilft dadurch bei der Traverse eines Katalogs, daß die einfachen Dateinamen (ohne . und ..) mit der Methode list() als Vektor geliefert werden: {programs/main/Ls.java} /** take care of one file */ protected void ls (String dirname, String path) { File f = new File(path); if (! f.exists()) System.err.println(path + ": does not exist"); else if (! dflag && f.isDirectory()) { String names [] = f.list(); if (names == null) // can still happen: Windows 95 names = new File(path + ".").list(); // kludge... File files [] = new File [names.length]; for (int n = 0; n < names.length; ++ n) files[n] = new File(dirname + names[n]); for (int n = 0; n < files.length; ++ n) System.out.println(files[n]); if (Rflag) for (int n = 0; n < files.length; ++ n) if (files[n].isDirectory()) ls(dirname+names[n]+File.separator, files[n].getPath()); } else System.out.println(f); } } {} File.separator ist eine Klassenvariable , mit der der lokale Komponententrenner portabel gehalten wird. Es gibt ihn auch als System-Property. Die Lösung geht von homogenen Pfaden aus, die zum Beispiel bei Windows nicht vorliegen. Leider ist die Windows-Implementierung von File reichlich defekt in bezug auf die Wurzel eines Laufwerks. Ohne die obige ‘‘Korrektur’’ erhält man folgendes: c> java Ls c: c: c> java Ls c:\ Ls: java.lang.NullPointerException c> java Ls \ Ls: java.lang.NullPointerException C> java Ls c:\. Nur der letzte Versuch funktioniert. Man kann zwar das vorliegende Beispiel reparieren, aber eigentlich sollte man auf Korrektur der Klasse drängen. Die Reparatur korrigiert nicht das Problem, daß man für unlesbare Kataloge unter UNIX offenbar auch null erhält.