Wie kann man mehrere Dateien gleichzeitig umbenennen?

Die Klasse File stellt Methoden für den Zugriff auf Dateien bereit. Durch Rekursion können mehrere Dateien gleichzeitig umbenannt oder auch gelöscht werden.

Es wird ausdrücklich darauf hingewiesen, dass bei unsachgemäßer oder unbedachter Anwendung des hier dargestellten Verfahrens zum Umbenennen und/oder Löschen von Dateien Datenverlust drohen kann. Der Autor lehnt jegliche Verantwortung ab.

Das Beispiel weist neben main() zwei weitere Methoden auf: renameFile() enthält die wesentlichen Aktionen um innerhalb eines Dateibaumes alle Dateien nach einem festgelegten Schema umzubenennen und die Methode copyFile(), die als Hilfsmethode Dateien kopieren kann. Letzte entstammt dem Artikel zum Kopieren von Datein Ihre Funktion kann dort nachgeschlagen werden.

In renameFile() kann durch den Parameter deepness festgelegt werden, in welcher Rekursionstiefe die Umbenennung stattfinden soll. Wird hier ein Wert kleiner 1 angegeben, so werden alle Dateinamen unverändert belassen. 1 ändert nur die Dateinamen innerhalb des Verzeichnisses pfad, 2 benennt zusätzlich Dateien eine Ebene tiefer um, 3 noch eine zweite Ebene tiefer, etc.

Der Parameter pfad muss den absoluten Pfad zur umzubenennenden Datei enthalten oder zu einem Verzeichnis, dessen Inhalt umbenannt werden soll. Hierbei muss beachtet werden, dass die Umbenennung wesentlich auf die Trennung von Dateibezeichner und Dateierweiterung durch einen Punkt zurückgreift (s.u.). Dateien ohne Extension können auf die hier gezeigte Weise nicht umbenannt werden.
Durch den String-Parameter postfix kann ein Namensanteil eingegeben werden, der bei der Umbenennung vor dem letzten Punkt im Dateinamen eingefügt werden soll. Bsp.: Wird eine Datei mit dem Bezeichner xxx.yyy durch das Postfix _new erweitert, so resultiert der Dateiname xxx_new.yyy.

Der Parameter extension übergibt eine neue Dateinamenserweiterung, die bei der Umbenennung statt der alten verwendet werden kann. Wird er mit null belegt, so wird die bisherige Dateiendung beibehalten. Der Parameter delete wird dann selbstständig auf false gesetzt, um ein eventuelles Löschen der Dateien zu verhindern, falls gleichzeitig kein Postfix angegeben wurde. Durch Übergabe von true an den Parameter delete können ansonsten die alten Dateien gelöscht werden.

ACHTUNG DATENVERLUST! Hier muss große Sorgfalt geleistet werden! Eine Löschung ist unwiederbringlich und kann nicht rückgängig gemacht werden!

Der boolsche Parameter ask bestimmt, ob vor der Umbenennung jeder Datei eine Sicherheitsabfrage erfolgen soll. Wird hier false übergeben, so wird diese übersprungen.

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;

import javax.swing.JOptionPane;

public class MehrereDateienUmbenennen {

    private void renameFile(String pfad, String postfix, String extension,
    boolean ask, boolean delete, int deepness) {
        if (postfix == null) {
            postfix = "";
        }
        File file = new File(pfad);
        if (file.isDirectory()) {
            if (--deepness > -1) {
                File[] files = file.listFiles();
                for (File f : files) {
                    renameFile(f.getAbsolutePath(), postfix, extension, ask,
                        delete, deepness);
                }
            }
        } else if (file.canWrite()) {
            String extOld = pfad.substring(pfad.lastIndexOf(".") + 1,
                pfad.length());
            if (extension == null) {
                extension = extOld;
                delete = false;
            }
            pfad = pfad.substring(0, pfad.lastIndexOf(".")) + postfix + "."
                + extension;
            int conf = -1;
            if (ask) {
                conf = JOptionPane.showConfirmDialog(null, "Soll die Datei "
                    + file.getName() + " umbenannt werden?",
                        "Best\u00E4tigung", JOptionPane.YES_NO_OPTION);
            }
            if (conf == JOptionPane.YES_OPTION || !ask) {
                copyFile(file, new File(pfad));
                if (delete) {
                    file.delete();
                }
            }
        } else {
            if (file.setWritable(true)) {
                renameFile(file.getAbsolutePath(), postfix, extension, ask,
                    delete, deepness);
            } else {
                System.err.println("Anpassung der Schreibberechtigungen von "
                    + file.getName() + "nicht m\u00F6glich!");
                return;
            }
        }
    }

    public static void copyFile(File in, File out) {
        FileChannel inChannel = null;
        FileChannel outChannel = null;
        try {
            inChannel = new FileInputStream(in).getChannel();
            outChannel = new FileOutputStream(out).getChannel();
            inChannel.transferTo(0, inChannel.size(), outChannel);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (inChannel != null)
                    inChannel.close();
                if (outChannel != null)
                    outChannel.close();
            } catch (IOException e) {
            }
        }
    }

    public static void main(String[] args) {
        String pfad = "/Users/joecze/test/";
        MehrereDateienUmbenennen mdu = new MehrereDateienUmbenennen();
        mdu.renameFile(pfad, null, "html", false, false, 2);
    }
}

Zu Beginn der Methode renameFile werden zunächst ein mit null übergebener Parameter postfix in einen Leerstring gewandelt und anschließend ein File-Objekt mit dem übergebenen Pfad neu gebildet.

Es wird geprüft, ob hierbei ein Verzeichnis vorliegt. Ist dies der Fall, wird es ausgelesen und sein Inhalt in ein File-Array geladen, sowie der Parameter deepness dekrementiert. Er bestimmt die Rekursionstiefe und darf minimal bei 0 liegen (s.o.). Für jedes im Array enthaltene File-Objekt wird dann renameFile() mit den ansonsten gleichen Parametern rekursiv erneut aufgerufen.

Liegt kein Verzeichnis, sondern eine Datei vor, so werden zwei Fälle unterschieden: Kann die Datei nicht beschrieben werden, so wird versucht, deren Rechte entsprechend zu ändern und anschließend renameFile() erneut aufzurufen. Gelingt dies nicht, so terminiert die Methode mit einer Fehlermeldung.

Sind Schreibrechte gegeben, so wird zunächst die Dateiendung ermittelt. Sie wird verwendet, wenn der Parameter extension mit null belegt ist, sodass die ursprüngliche Erweiterung in diesem Fall an diesen Parameter übergeben werden kann, sodass beim folgenden Vorgang des Extensions-Tauschs somit die ursprüngliche Erweiterung wiederverwendet wird. Aus Sicherheitsgründen wird in diesem Fall zudem das Löschen der alten Datei verhindert, indem der Parameter delete auf false gesetzt wird.
Der Pfad des neuen File-Objektes wird dann aus dem Dateinamen bis zum letzten Punkt, dem übergebenen Postfix, dem Punkt und der evtl. neuen Dateiendung zusammengesetzt.
Wurde der Parameter ask auf true gesetzt, um bei der Umbenennung nachzufragen, so wird ein entsprechender Dialog erzeugt, der, abhängig von der angeklickten Option, einen int-Wert zurückgibt. Wurde hier OK gewählt oder wurde auf eine Nachfrage verzichtet, wird für den vorliegenden Pfad die Methode File#copyFile() aufgerufen. Sie kopiert das 'alte' File-Objekt in das 'neue'. Abhängig vom Parameter delete wird ggf. die alte Datei schließlich gelöscht.