it-swarm.com.de

Gibt es eine plattformübergreifende Java-Methode zum Entfernen von Dateinamen-Sonderzeichen?

Ich mache eine plattformübergreifende Anwendung, die Dateien basierend auf online abgerufenen Daten umbenennt. Ich möchte die Strings, die ich von einer Web-API für die aktuelle Plattform genommen habe, bereinigen.

Ich weiß, dass unterschiedliche Plattformen unterschiedliche Anforderungen an die Dateinamen haben. Ich habe mich gefragt, ob es einen plattformübergreifenden Weg gibt, dies zu tun?

Bearbeiten: Auf Windows-Plattformen können Sie kein Fragezeichen "?" in einem Dateinamen, während Sie in Linux können. Die Dateinamen enthalten möglicherweise solche Zeichen, und ich möchte, dass die Plattformen, auf denen diese Zeichen unterstützt werden, diese beibehalten, sie aber ansonsten entfernen.

Ich würde auch eine Java-Standardlösung vorziehen, die keine Bibliotheken von Drittanbietern erfordert.

52
Ben S

Wie an anderer Stelle vorgeschlagen, ist dies normalerweise nicht das, was Sie tun möchten. Normalerweise ist es am besten, eine temporäre Datei mit einer sicheren Methode wie File.createTempFile () zu erstellen.

Sie sollten dies nicht mit einer Whitelist machen und nur "gute" Zeichen behalten. Wenn die Datei nur aus chinesischen Zeichen besteht, entfernen Sie alles. Wir können aus diesem Grund keine Whitelist verwenden, wir müssen eine Blacklist verwenden.

Linux lässt fast alles zu, was wirklich schmerzhaft sein kann. Ich würde Linux nur auf dieselbe Liste beschränken, auf die Sie Windows beschränken, damit Sie sich in Zukunft Kopfschmerzen ersparen.

Mit diesem C # -Schnipsel unter Windows habe ich eine Liste von Zeichen erstellt, die unter Windows nicht gültig sind. Diese Liste enthält einige mehr Zeichen, als Sie vielleicht denken (41). Ich würde daher nicht empfehlen, eine eigene Liste zu erstellen.

        foreach (char c in new string(Path.GetInvalidFileNameChars()))
        {
            Console.Write((int)c);
            Console.Write(",");
        }

Hier ist eine einfache Java-Klasse, die einen Dateinamen "reinigt".

public class FileNameCleaner {
final static int[] illegalChars = {34, 60, 62, 124, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47};
static {
    Arrays.sort(illegalChars);
}
public static String cleanFileName(String badFileName) {
    StringBuilder cleanName = new StringBuilder();
    for (int i = 0; i < badFileName.length(); i++) {
        int c = (int)badFileName.charAt(i);
        if (Arrays.binarySearch(illegalChars, c) < 0) {
            cleanName.append((char)c);
        }
    }
    return cleanName.toString();
}
}

EDIT: Wie von Stephen vorgeschlagen, sollten Sie wahrscheinlich auch sicherstellen, dass diese Dateizugriffe nur innerhalb des von Ihnen zugelassenen Verzeichnisses erfolgen.

Die folgende Antwort enthält Beispielcode zum Erstellen eines benutzerdefinierten Sicherheitskontexts in Java und zum Ausführen von Code in dieser 'Sandbox'.

Wie erstellt man eine sichere JEXL-Sandbox (Scripting)?

24
Sarel Botha

oder einfach das tun:

String filename = "A20/B22b#öA\\BC#Ä$%ld_ma.la.xps";
String sane = filename.replaceAll("[^a-zA-Z0-9\\._]+", "_");

Ergebnis: A20_B22b_A_BC_ld_ma.la.xps

Erläuterung:

[a-zA-Z0-9\\._] entspricht einem Buchstaben aus a-z Klein- oder Großbuchstaben, Zahlen, Punkten und Unterstrichen

[^a-zA-Z0-9\\._] ist die Umkehrung. alle Zeichen, die nicht mit dem ersten Ausdruck übereinstimmen

[^a-zA-Z0-9\\._]+ ist eine Folge von Zeichen, die nicht mit dem ersten Ausdruck übereinstimmen

Also jede Zeichenfolge, die nicht aus Zeichen von a-z, 0-9 oder besteht. _ wird ersetzt werden.

19
Dirk

Dies basiert auf der akzeptierten Antwort von Sarel Botha , die gut funktioniert, solange Sie keine Zeichen außerhalb der Basic Multilingual Plane finden. Wenn Sie vollständige Unicode-Unterstützung benötigen (und wer nicht?), Verwenden Sie stattdessen diesen Code, der Unicode-sicher ist:

public class FileNameCleaner {
  final static int[] illegalChars = {34, 60, 62, 124, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47};

  static {
    Arrays.sort(illegalChars);
  }

  public static String cleanFileName(String badFileName) {
    StringBuilder cleanName = new StringBuilder();
    int len = badFileName.codePointCount(0, badFileName.length());
    for (int i=0; i<len; i++) {
      int c = badFileName.codePointAt(i);
      if (Arrays.binarySearch(illegalChars, c) < 0) {
        cleanName.appendCodePoint(c);
      }
    }
    return cleanName.toString();
  }
}

Wichtige Änderungen hier:

  • Verwenden Sie codePointCount i.c.w. length statt nur length
  • verwenden Sie codePointAt anstelle von charAt
  • benutze appendCodePoint anstelle von append
  • Es ist nicht nötig, chars in ints umzuwandeln. Tatsächlich sollten Sie sich niemals mit chars befassen, da diese außerhalb des BMP grundsätzlich defekt sind.
10
Stijn de Witt

Es gibt eine ziemlich gute integrierte Java-Lösung - Character.isXxx () .

Versuchen Sie Character.isJavaIdentifierPart(c):

String name = "name.é[email protected]#$%^&*(){}][/=?+-_\\|;:`~!'\",<>";
StringBuilder filename = new StringBuilder();

for (char c : name.toCharArray()) {
  if (c=='.' || Character.isJavaIdentifierPart(c)) {
    filename.append(c);
  }
}

Ergebnis ist "name.é $ _".

6
David Carboni

Hier ist der Code, den ich verwende:

public static String sanitizeName( String name ) {
    if( null == name ) {
        return "";
    }

    if( SystemUtils.IS_OS_LINUX ) {
        return name.replaceAll( "/+", "" ).trim();
    }

    return name.replaceAll( "[\u0001-\u001f<>:\"/\\\\|?*\u007f]+", "" ).trim();
}

SystemUtils stammt aus Apache commons-lang3

6
Aaron Digulla

Aus Ihrer Frage geht nicht klar hervor, aber da Sie planen, Pfadnamen aus einem Webformular (?) Zu akzeptieren, sollten Sie wahrscheinlich Versuche verhindern, bestimmte Dinge umzubenennen. z.B. "C:\Programme". Dies bedeutet, dass Sie die Pfadnamen kanonisieren müssen, um "." und "..", bevor Sie Ihre Zugriffsprüfungen durchführen.

In Anbetracht dessen würde ich nicht versuchen, illegale Zeichen zu entfernen. Stattdessen würde ich "new File (str) .getCanonicalFile ()" verwenden, um die kanonischen Pfade zu erstellen. Als Nächstes prüfen Sie, ob sie die Sandboxing-Einschränkungen erfüllen, und verwenden schließlich "File.exists ()", "File.isFile ()". usw., um zu überprüfen, ob Quelle und Ziel koscher sind und nicht dasselbe Dateisystemobjekt sind. Ich beschäftige mich mit illegalen Charakteren, indem ich versuchte, die Operationen auszuführen und die Ausnahmen zu erfassen.

5
Stephen C

Wenn Sie mehr als [A-Za-z0-9] verwenden möchten, überprüfen Sie MS Naming Conventions und vergessen Sie nicht, "... Zeichen herauszufiltern, deren Ganzzahldarstellungen zwischen 1 und 31 liegen , ... ", wie es das Beispiel von Aaron Digulla tut. Der Code, z.B. von David Carboni würde für diese Zeichen nicht ausreichen.

0
wandlang

Paths.get(...) löst eine detaillierte Ausnahme mit der Position des illegalen Charakters aus.

public static String removeInvalidChars(final String fileName)
{
  try
  {
    Paths.get(fileName);
    return fileName;
  }
  catch (final InvalidPathException e)
  {
    if (e.getInput() != null && e.getInput().length() > 0 && e.getIndex() >= 0)
    {
      final StringBuilder stringBuilder = new StringBuilder(e.getInput());
      stringBuilder.deleteCharAt(e.getIndex());
      return removeInvalidChars(stringBuilder.toString());
    }
    throw e;
  }
}
0
l.poellabauer