Dateinamen mit Zahl um eins erhöhen

osix

Bekanntes Mitglied
Moin Leute,

Ich hab hier ein Verzeichnis, da liegen eine unbekannte Zahl von Dateien drin z.B.

Seite1.jpg
Seite2.jpg
Seite3.jpg
Seite4.jpg

Wie kann ich mit Java alle Dateinamen umbennen, dass es nachher so aussieht
Seite2.jpg
Seite3.pg
Seite4.jpg
Seite5.jpg

Also alle Zahlen sind um eins nach oben verändert. Es ist nicht bekannt wieviel Dateien vorhanden sind !

Besten Dank für eure Hilfe
 

philanthrop

Bekanntes Mitglied
Moin, das ist nicht "trivial", aber es ginge so:

Java:
import java.io.File;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class NFiles {
    record Filename(File file, String prefix, int number, String ending) {
    }

    public static void shiftFilenamesOffset(final File dir, final int offset) {
        Comparator<Filename> filenameComparator = offset <= 0 ? Comparator.comparingInt(Filename::number) : Comparator.comparingInt(Filename::number).reversed();
        String re = "(.*?)(\\d+)\\.(.*+)";
        Pattern pat = Pattern.compile(re);
        Arrays.stream(Objects.requireNonNull(dir.listFiles())).filter(f -> pat.matcher(f.getName()).find()).map(f -> {
            Matcher mat = pat.matcher(f.getName());
            mat.find();
            return new Filename(f, mat.group(1), Integer.parseInt(mat.group(2)), mat.group(3));
        }).sorted(filenameComparator).forEach(fn -> {
            File nf = new File(fn.file().getParent(), fn.prefix() + (fn.number() + offset) + "." + fn.ending());
            System.out.println(fn + " -> " + nf + " -> " + fn.file().renameTo(nf));
        });
    }

    public static void main(final String[] args) {
        shiftFilenamesOffset(new File("test1"), 3);
    }
}
 

philanthrop

Bekanntes Mitglied
Ich sehe gerade, der Regex re muss noch leicht anders sein:

String re = "(.*)(\\d+)\\.([^.]*)"; (ohne zögerlich)

... sonst gäbe es zum Beispiel hierbei Probleme:

1695603899964.png

Erkannt würde: 0 2 2 3

... aber richtig wäre ja: 0 1 2 3. ;)

So nun Heia
 

KonradN

Super-Moderator
Mitarbeiter
Wieso schreibt man so komplexen Code und macht nicht einfach ein paar Methoden mehr, damit es leserlich wird?

Also machen wir nur beim gegebenen Code einmal ein Refactoring:
a) Erster Schritt: Mal etwas vernünftiger Einrücken:
Java:
import java.io.File;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class NFiles {
    record Filename(File file, String prefix, int number, String ending) {
    }

    public static void shiftFilenamesOffset(final File dir, final int offset) {
        Comparator<Filename> filenameComparator = offset <= 0 ? Comparator.comparingInt(Filename::number) : Comparator.comparingInt(Filename::number).reversed();

        String re = "(.*?)(\\d+)\\.(.*+)";
        Pattern pat = Pattern.compile(re);

        Arrays.stream(Objects.requireNonNull(dir.listFiles()))
                .filter(f -> pat.matcher(f.getName()).find())
                .map(f -> {
                    Matcher mat = pat.matcher(f.getName());
                    mat.find();
                    return new Filename(f, mat.group(1), Integer.parseInt(mat.group(2)), mat.group(3));
                })
                .sorted(filenameComparator)
                .forEach(fn -> {
                    File nf = new File(fn.file().getParent(), fn.prefix() + (fn.number() + offset) + "." + fn.ending());
                    System.out.println(fn + " -> " + nf + " -> " + fn.file().renameTo(nf));
        });
    }

    public static void main(final String[] args) {
        shiftFilenamesOffset(new File("test1"), 3);
    }
}

b) Objects.requireNonNull - Was soll das erreichen? Wenn es null ist (das Verzeichnis nicht existiert, dann wird eine NPE geworfen. Arrays.stream würde das aber auch schon für uns machen. Wieso nicht eine vernünftige Validierung des Parameters?

Sprich einfach ein
Java:
        if (!dir.exists() || !dir.isDirectory()) {
            throw new RuntimeException("File does not exist or is not a directory!");
        }
und schon braucht man dies nicht mehr.

c) Dann packen wir die Lambdas in separate Methoden (zusammen mit der Umbenennung erster Variablen) und erhalten dann etwas wie:
Java:
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.Arrays;
import java.util.Comparator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class NFiles {
    record Filename(File file, String prefix, int number, String ending) {
    }

    static Pattern filenamePattern = Pattern.compile("(.*?)(\\d+)\\.(.*+)");

    public static void shiftFilenamesOffset(final File dir, final int offset) {

        if (!dir.exists() || !dir.isDirectory()) {
            throw new RuntimeException("File does not exist or is not a directory!");
        }

        Comparator<Filename> filenameComparator = offset <= 0 ? Comparator.comparingInt(Filename::number) : Comparator.comparingInt(Filename::number).reversed();

        Arrays.stream(dir.listFiles())
                .filter(f -> filenamePattern.matcher(f.getName()).find())
                .map(NFiles::createFilename)
                .sorted(filenameComparator)
                .forEach(fn -> renameFile(fn, offset);
    }

    private static Filename createFilename(File file) {
            Matcher mat = filenamePattern.matcher(file.getName());
            mat.find();
            return new Filename(file, mat.group(1), Integer.parseInt(mat.group(2)), mat.group(3));
    }

    private static void renameFile(Filename filename, int offset) {
        File nf = new File(filename.file().getParent(), filename.prefix() + (filename.number() + offset) + "." + filename.ending());
        System.out.println(filename + " -> " + nf + " -> " + filename.file().renameTo(nf));
    }

    public static void main(final String[] args) {
        shiftFilenamesOffset(new File("test1"), 3);
    }
}

Damit hat man dann direkt einen etwas lesbareren Stand. Hier würde ich aber noch etwas weiter vorgehen:
  • statt dem .filter ein Parameter bei listFiles()
  • Dann die Zeile Array.steam(...) durch eine Methode ersetzen, die den Stream zurück gibt.
  • Natürlich noch paar weitere Variablen umbenennen
  • Die Methoden sind jetzt private static - das ist natürlich auch noch anzupassen. Wozu ist man in einer objektorientierten Sprache, wenn man dies komplett ignoriert?

Aber das nur als kleine Anregung für eigene Optimierungen.
 

KonradN

Super-Moderator
Mitarbeiter
Hier ist nach meiner Meinung ein Kommentar notwendig, dass und warum man reversed vergleicht.
Ansonsten aber sehr gut.
Ja, guter Hinweis. Das Refactoring ist nicht komplett. Bezüglich Kommentar: Das wäre also bei mir hier eine (Factory-)Methode und man hätte dann den Methodennamen und JavaDoc um es deutlicher zu machen.
 

Barista

Top Contributor
Bezüglich Kommentar: Das wäre also bei mir hier eine (Factory-)Methode und man hätte dann den Methodennamen und JavaDoc um es deutlicher zu machen.
Ich hatte mal bei einem anderen Programmierer im Codereview angemeckert, dass eine private Methode keinen JavaDoc hatte.

Derjenige konterte, dass an einer private Methode kein JavaDoc erforderlich ist.

Insofern korrekt, weil JavaDoc eigentlich eine API-Doc ist, keine Implementierungs-Doc.

Leider ist für Implementierungs-Doc in Java nichts vorgesehen.

Man kann aber trotzdem JavaDoc als Implementierungs-Doc verwenden.

Ich frage mich außerdem, wie ein Methodenname ausdrücken soll, dass man beim Erhöhen des Index im Dateinamen am Ende beginnen muss, damit sich die Änderungen sich nicht gegenseitig in die Quere kommen. Ein Problem das nach meiner Meinung nicht unmittelbar ersichtlich ist. Nun ja, Andere sind eventuell schlauer, ich könnte mir vorstellen über dieses Problem zu stolpern. bei Dateien ist es wahrscheinlich nicht so schlimm, weil das Umbenennen einfach scheitert, aber im Speicher würde dies zu Datenhack führen.
 

philanthrop

Bekanntes Mitglied
Ich frage mich außerdem, wie ein Methodenname ausdrücken soll, dass man beim Erhöhen des Index im Dateinamen am Ende beginnen muss, damit sich die Änderungen sich nicht gegenseitig in die Quere kommen. Ein Problem das nach meiner Meinung nicht unmittelbar ersichtlich ist. Nun ja, Andere sind eventuell schlauer, ich könnte mir vorstellen über dieses Problem zu stolpern. bei Dateien ist es wahrscheinlich nicht so schlimm, weil das Umbenennen einfach scheitert, aber im Speicher würde dies zu Datenhack führen.

Beispiel:

5
6
7
8

versuche das mal, um +2 zu verschieben, dabei aber nicht rückwärtszulaufen ... viel Spaß
 

KonradN

Super-Moderator
Mitarbeiter
Wie meinst du das? Arrays.stream( ) liefert bereits einen Stream zurück.
Du hast einen Ausdruck wie:
Arrays.stream(dir.listFiles(f -> filenamePattern.matcher(f.getName()).find()))
Der ist relativ unleserlich. Ein typisches Refactoring ist bei sowas, den Ausdruck, der nicht ganz verständlich ist, in eine Methode zu verlagern. Also etwas wie
Array.stream(dir.listFiles(this::isMatchingFile))
Arrays.stream(getMatchingFiles())
oder gar einfach
getMatchingFileStream()

Das ist halt das, was direkt lesbar wäre:
Java:
getMatchingFiles()
    .map(this::getFileName)
    .sort(this::getComparatorForFilename)
    .foreach(this::doMove);
Was macht der Code?
Er holt die passenden Dateien,
holt sich dazu die Filename Instanzen (Der Name gefällt mir noch nicht, aber das ist erst einmal egal)
um diese dann zu sortieren
und dann zu verschieben.

Daher kann eine Methode getMatchingFiles, welche einen Stream<File> zurück gibt, zumindest einen Gedanken wert sein.

Insofern korrekt, weil JavaDoc eigentlich eine API-Doc ist, keine Implementierungs-Doc.

Leider ist für Implementierungs-Doc in Java nichts vorgesehen.

Man kann aber trotzdem JavaDoc als Implementierungs-Doc verwenden.
Ja, aber die Idee ist aus meiner Sicht ja nicht nur die Bereitstellung einer Dokumentation der API sondern eine generelle Unterstützung des Entwicklers. Die Dokumentation sollte die Entwicklungsumgebung ja mit einblenden können. Damit sieht man die, wenn man die Methode aufrufen will und hat daher direkt eine Kontrolle, ob man wirklich nichts vergessen hat. Aber das kenne ich vor allem von Visual Studio / C#, und da war das Ergebnis immer ein .xml File das wir generiert haben für Visual Studio. Daraus haben wir eigentlich nie HTML erzeugt (in dem damaligen Projekt. Ich schon paar Jährchen her.)

Und wichtig ist, dass man sich halt auf klare Coding Guidelines einigt. So sollte klar sein, wie man alles benennt. Und wenn es für etwas noch keine Vorgabe gibt (weil es bei einer Library nicht von außen erkannbar ist), dann legt man dennoch etwas fest, damit es einheitlich ist. So gesehen bin ich ganz bei Dir.

Ich bin aber auch der Meinung, dass man private Methoden durchaus vermeiden sollte. Das ist oft ein Zeichen, dass da in einer Klasse etwas drin ist, das zu komplex ist und daher in eine eigene Klasse verlagert werden sollte. Sprich: Ein angepasstes Design sollte geprüft werden. (Ich sage nicht, dass es immer so sein sollte. Oder dass dies die große Masse sein muss. Aber es sollte aus meiner Sicht bei einem Code Review geprüft werden. Das vereinfacht dann nach meiner Erfahrung dann auch die Unit Tests deutlich.
 

KonradN

Super-Moderator
Mitarbeiter
Bezüglich JavaDoc - wenn man bei privaten Methoden kein JavaDoc wünscht, ist das natürlich ok. Dann passen so wichtige Informationen in das JavaDoc der Klasse. Wobei dann natürlich der Vorteil mit der Entwicklungsumgebung entfällt, weil das ja nicht mehr eingeblendet werden kann oder es einfach zu viel wäre.

Das ist ja etwas, das man im Java Framework öfters findet - die Klasse hat wichtige Hinweise zur Nutzung und solche Besonderheiten immer in der Klassenbeschreibung. In der Methode selbst finden sich meist nur minimal gehaltene Hinweise.
 

philanthrop

Bekanntes Mitglied
es tut mir leid, aber ich kann mit deinem code review nix anfangen ... die Stream-Methoden sind ja bereits einzelne Methoden ... und wenn dir die einzelnen Aufrufe zu kompliziert sind, liegt das an dir (oder an Java).

aber vielleicht ist es für andere noch hilfreich.
 

KonradN

Super-Moderator
Mitarbeiter
es tut mir leid, aber ich kann mit deinem code review nix anfangen ... die Stream-Methoden sind ja bereits einzelne Methoden ... und wenn dir die einzelnen Aufrufe zu kompliziert sind, liegt das an dir (oder an Java).
Damit kann ich erst einmal gut leben. Auch Du wirst evtl. irgendwann einmal einsehen, dass es gut ist, lesbaren und testbaren Code zu schreiben. Aber das ist natürlich keine Verpflichtung. Du kannst weiter Code so schreiben, dass er nicht wirklich lesbar ist. Nur eben solltest Du Dir dann überlegen, sowas niemandem hier im Forum als Antwort zu geben. Das ist eine Zumutung.

Und bei Deiner Einrückung wirst Du auch kaum ernsthaft behaupten wollen, dass Du da einen schnellen Überblick hast. Wenn Du da nach 2 Wochen drauf schaust, wirst Du auch erst einmal anfangen, nach den Klammern zu schauen um zu sehen, wo was anfängt oder aufhört. Alleine schon da ist das erste Refactoring mit Zeilenumbrüchen / Einrückungen ein wichtiger, guter Schritt. Und Tests hast Du ja eh keine geschrieben. Manueller Test mit einem Verzeichnis und das war es, oder?

Daher ja: Keine Grundlage für eine Diskussion. Deine Meinung akzeptiere ich aber sie zeigt ein deutliches Bild von Deinem Stand.
 

philanthrop

Bekanntes Mitglied
1695634855928.png

Das nervt ein bisschen ...

Das ist eine Zumutung.
Das stimmt, denn deine "Reviews", die etwas, was ja bereits richtig ist, verbessern sollen, sind für alle eine Zumutung, ja.

Aber, falls eine Persönlichkeitsstörung oder Ähnliches vorliegt, dann kannst du dafür nichts - und ich will mich deshalb auch nicht streiten.

🤷‍♂️

Wie wäre es damit, wenn ich mich aus diesem Thema in Zukunft heraushalten würde, und du darfst dann alles schreiben, was du möchtest? Nur haltlose Unterstellungen sind halt nicht so schön ...
 

KonradN

Super-Moderator
Mitarbeiter
Das stimmt, denn deine "Reviews", die etwas, was ja bereits richtig ist, verbessern sollen, sind für alle eine Zumutung, ja.
Und da gehen halt die Meinungen stark auseinander wie Du selbst ganz deutlich merkst. Die Reaktion von @Apple’s Jünger, die Dich so massiv stört, drückt ja auch seine Meinung recht deutlich aus.

Nur haltlose Unterstellungen sind halt nicht so schön ...
Wo habe ich haltlose Unterstellungen geschrieben?

Aber, falls eine Persönlichkeitsstörung oder Ähnliches vorliegt, dann kannst du dafür nichts - und ich will mich deshalb auch nicht streiten.
Was sollen diese Angriffe jetzt? Du hast Dich jetzt 2 Wochen so zivilisiert verhalten und dann jetzt doch wieder diese Entgleisung?

Du kannst gerne meinen, was immer du willst. Ich will Dich zu nichts bekehren. Daher ist mir das auch alles egal. Aber zu dem Thema gibt es nun wirklich mehr wie genug Literatur und Videos und so. Uncle Bob ist da wohl immer noch mit der beste Einstieg. Und wenn Textverständnis so Probleme bereitet, dann gibt es das als Videos:

Ansonsten ist das Thema hoffentlich erledigt, oder gibt es wirklich diskussionsbedarf? Wir sind ja von dem Thema selbst weg.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
lewbue Eclipse Eclipse Dateinamen in Hieroglyphen Allgemeine Java-Themen 4
B Stringmanipulationen beim Dateinamen Allgemeine Java-Themen 8
G Datei aus Ordner wählen, ohne den Dateinamen im Pfad angeben zu müssen Allgemeine Java-Themen 4
S Alle Dateinamen ermitteln Allgemeine Java-Themen 22
Elyt Compiler-Fehler Datei kann nicht erstellt werden. Die Syntax für den Dateinamen etc. ist falsch. Allgemeine Java-Themen 2
MiMa Illegal char im Dateinamen Allgemeine Java-Themen 14
MiMa Umlaute beim Einlesen von Dateinamen Allgemeine Java-Themen 12
R Besondere Zeichen in Dateinamen Allgemeine Java-Themen 4
I FTP Probleme mit Umlauten in Dateinamen Allgemeine Java-Themen 5
W Dateinamen dynamisch Parsen Allgemeine Java-Themen 12
9 Dateinamen erfassen und vergleichen Allgemeine Java-Themen 6
M Charset Encoding für Dateinamen Allgemeine Java-Themen 4
J Dateinamen beim Start auslesen Allgemeine Java-Themen 10
S Problem mit / im Dateinamen Allgemeine Java-Themen 3
G Syntax für den Dateinamen Allgemeine Java-Themen 1
M Dateinamen ändern Allgemeine Java-Themen 3
T Konvertieren zu gültigen Dateinamen Allgemeine Java-Themen 10
G Linux Dateinamen Charset Probleme Allgemeine Java-Themen 8
C Dateinamen auslesen? Allgemeine Java-Themen 23
F Alle Files im Ordner nach Dateinamen durchsuchen Allgemeine Java-Themen 28
P Dateinamen mit regulärem Ausdruck testen Allgemeine Java-Themen 9
P Dateinamen testen? Schreibrechte auf Verzeichnis testen? Allgemeine Java-Themen 8
B Millionen bit lange zahl bauen? Allgemeine Java-Themen 7
J Zerlegen einer Zahl Allgemeine Java-Themen 6
J Die Letzte Zahl aus einer Text datei lesen Allgemeine Java-Themen 8
Tronert Alphabetische Aufzählung aus Zahl? Allgemeine Java-Themen 5
E String in Zahl umwandeln, ohne Befehl Integer.parseInt Allgemeine Java-Themen 3
E Swing andere schreibart für jButtoni (i = Zahl des Buttons) Allgemeine Java-Themen 6
J Eine bestimmte Zahl im Integer ändern Allgemeine Java-Themen 9
J While Schleife ausführen bis Zahl = X Allgemeine Java-Themen 19
J Repräsentation in Java - 32bit Zahl Allgemeine Java-Themen 8
T Quadrieren einer Zahl nur durch Addition Allgemeine Java-Themen 5
Z Zahl raten Allgemeine Java-Themen 2
Chr1s ergebnis = Zahl? Allgemeine Java-Themen 3
A Zahl abgerundet obwohl Double Allgemeine Java-Themen 9
K Interpreter-Fehler Java Zahl Raten Spiel- Fehlermeldung mir unbekannt Allgemeine Java-Themen 12
J Die Menge einer Zahl im Binärbaum zählen Allgemeine Java-Themen 7
P Input/Output java.util.Scanner in einer Schleife und Exception-Behandlung: Einlesen einer Zahl Allgemeine Java-Themen 4
A Zahl zu lang für Long Allgemeine Java-Themen 3
L Leerzeichen zu string hinzufügen, um eine gerade zahl zu erhalten Allgemeine Java-Themen 9
O Prüfen ob String eine Zahl mit maximal 2 Nachkommastellen ist Allgemeine Java-Themen 4
N Zahl mit bestimmter Länge und nur bestimmten Zahlen generieren lassen Allgemeine Java-Themen 7
J Bestimmter Buchstabe = bestimmte Zahl Allgemeine Java-Themen 10
H Eclipse x Stellen einer Zahl in array speichern Allgemeine Java-Themen 3
S Antlr Grammatik übersetzt ohne Fehler, dennoch wird Zahl nicht als Eingabe erkannt Allgemeine Java-Themen 4
C Zahl im Textarea anzeigen lassen Allgemeine Java-Themen 8
C Regex: Zahl ohne führende Null Allgemeine Java-Themen 13
cedi int Zahl in ein ASCII zeichen umwandeln und dieses in ein externes Textfenster schreiben Allgemeine Java-Themen 6
Rudolf Aus Collection<Integer> eine Zahl machen Allgemeine Java-Themen 2
M Zahl aktiver Threads einer Gruppe verlässlich abfragen Allgemeine Java-Themen 3
C Prüfen auf Zahl und 6 stellig fehlerhaft? warum? Allgemeine Java-Themen 7
S Zahl konvertieren [Internationalisierung l10n, l18n] Allgemeine Java-Themen 4
T Zufallszahlen generieren und dabei eine Zahl weglassen Allgemeine Java-Themen 4
Z Zahl einer spanne zuordnen Allgemeine Java-Themen 2
FoolMoon Elegante Möglichkeit die kleinste Zahl zu ermitteln. Allgemeine Java-Themen 7
E Konstante Zahl Threads parallel rechnen lassen Allgemeine Java-Themen 6
L Berechnung mit Module bis bes.timme Zahl erreicht. Allgemeine Java-Themen 4
Ark O-Notation und Zahl versus String-Repräsentation Allgemeine Java-Themen 7
N int[] eindeutig durch eine Zahl repräsentieren Allgemeine Java-Themen 12
D Regular Expression Mit Punkt und Zahl Allgemeine Java-Themen 4
X Substring aus Zahl Allgemeine Java-Themen 8
G Auf eine ganze Zahl aufrunden Allgemeine Java-Themen 30
G Zahl aus dem String Allgemeine Java-Themen 6
K Double-Zahl runden Allgemeine Java-Themen 4
L Partitionen der Länge x einer natürlichen Zahl n Allgemeine Java-Themen 21
G Prüfen ob Ziffern einer Zahl pandigital sind? Allgemeine Java-Themen 15
J Große Zahl (double) as text ausgeben? Allgemeine Java-Themen 2
0 Alle Teiler einer Zahl performant berechnen? Allgemeine Java-Themen 9
G Double Zahl quadrieren Allgemeine Java-Themen 8
G String in Zahl umwandeln Allgemeine Java-Themen 9
C Server-Zahl von google.com Allgemeine Java-Themen 11
B Umwandeln von Bytes in float Zahl (DataInputStream) Allgemeine Java-Themen 3
H ganze zahl true / false Allgemeine Java-Themen 3
M Umwandeln String (mit Zahl zur Basis 36) in Dezimalzahl Allgemeine Java-Themen 2
N Float zahl auf eine Stelle nach dem Komma runden Allgemeine Java-Themen 3
G Double Zahl auf 4 Stellen hinter Komma kuerzen Allgemeine Java-Themen 4
S addAtPosition - Zahl an einer bestimmten Position einfügen Allgemeine Java-Themen 8
G String als Zahl erkennen Allgemeine Java-Themen 19
N Zahl mit DecimalFormat formattieren Allgemeine Java-Themen 2
R Zahl eingeben! Allgemeine Java-Themen 9
B Fehler beim Auslesen von Einstellungen. Zwei ähnliche Blöcke, nur eins geht. Allgemeine Java-Themen 5
V Mac: Paketinhalt eins Files öffnen, wie? Allgemeine Java-Themen 3
B Aus mehreren Fenstern(Dialogen) eins machen! Allgemeine Java-Themen 2

Ähnliche Java Themen

Neue Themen


Oben