web-dev-qa-db-fra.com

Existe-il une méthode Java?

Je crée une application multiplateforme qui renomme des fichiers en fonction des données récupérées en ligne. Je souhaite supprimer les chaînes que j'ai extraites d'une API Web pour la plate-forme actuelle.

Je sais que différentes plateformes ont des exigences de nom de fichier différentes, alors je me demandais s'il y avait un moyen multiplateforme de le faire?

Edit: Sur les plates-formes Windows, vous ne pouvez pas avoir de point d'interrogation "?" dans un nom de fichier, alors que sous Linux, vous pouvez. Les noms de fichiers peuvent contenir de tels caractères et j'aimerais que les plates-formes qui les prennent en charge les conservent, mais sinon, supprimez les.

De plus, je préférerais une solution Java standard qui n'exige pas de bibliothèques tierces.

52
Ben S

Comme suggéré ailleurs, ce n'est généralement pas ce que vous voulez faire. Il est généralement préférable de créer un fichier temporaire en utilisant une méthode sécurisée telle que File.createTempFile ().

Vous ne devriez pas faire cela avec une liste blanche et ne conserver que les «bons» caractères. Si le fichier est composé uniquement de caractères chinois, vous en supprimerez tout le contenu. Nous ne pouvons pas utiliser de liste blanche pour cette raison, nous devons utiliser une liste noire.

Linux permet à peu près tout ce qui peut être une vraie douleur. Je limiterais simplement Linux à la même liste que vous limitiez Windows afin de vous éviter des maux de tête à l'avenir.

À l'aide de cet extrait de code C # sous Windows, j'ai généré une liste de caractères non valides sous Windows. Il y a beaucoup plus de caractères dans cette liste que vous ne le pensez (41), donc je ne recommanderais pas d'essayer de créer votre propre liste.

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

Voici une classe Java simple qui "nettoie" un nom de fichier.

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: Comme Stephen l’a suggéré, vous devriez probablement également vérifier que ces accès aux fichiers ne se produisent que dans le répertoire que vous autorisez.

La réponse suivante contient un exemple de code permettant d'établir un contexte de sécurité personnalisé en Java, puis d'exécuter du code dans ce "bac à sable".

Comment créez-vous un sandbox JEXL sécurisé (script)?

24
Sarel Botha

ou juste faire ceci:

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

Résultat: A20_B22b_A_BC_ld_ma.la.xps

Explication:

[a-zA-Z0-9\\._] correspond à une lettre de a-z inférieure ou majuscule, à des nombres, des points et des traits de soulignement

[^a-zA-Z0-9\\._] est l'inverse. c'est-à-dire tous les caractères qui ne correspondent pas à la première expression

[^a-zA-Z0-9\\._]+ est une séquence de caractères qui ne correspond pas à la première expression

Donc, chaque séquence de caractères qui ne consiste pas en caractères de a-z, 0-9 ou. _ sera remplacé.

19
Dirk

Ceci est basé sur la réponse acceptée de Sarel Botha qui fonctionne correctement tant que vous ne rencontrez aucun caractère en dehors du Plan multilingue de base . Si vous avez besoin d'un support complet Unicode (et qui ne l'a pas?), Utilisez plutôt ce code qui est sans danger pour Unicode:

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();
  }
}

Principaux changements ici:

  • Utilisez codePointCount i.c.w. length au lieu de length
  • utilisez codePointAt au lieu de charAt
  • utilisez appendCodePoint au lieu de append
  • Pas besoin de transtyper chars en ints. En fait, vous ne devriez jamais vous occuper de chars car ils sont fondamentalement cassés pour tout ce qui est en dehors du BMP.
10
Stijn de Witt

Il existe une très bonne solution Java intégrée - Character.isXxx () .

Essayez Character.isJavaIdentifierPart(c):

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

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

Le résultat est "name.é $ _".

6
David Carboni

Voici le code que j'utilise:

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 est de Apache commons-lang3

6
Aaron Digulla

Cela ne ressort pas clairement de votre question, mais puisque vous envisagez d’accepter des noms de chemin à partir d’un formulaire Web (?), Vous devez probablement bloquer les tentatives de changement de nom de certaines choses; par exemple. "C:\Program Files". Cela implique que vous devez canoniser les noms de chemin pour éliminer "." et ".." avant de faire vos vérifications d'accès.

Compte tenu de cela, je ne tenterais pas de supprimer les caractères illégaux. Au lieu de cela, j'utiliserais "new File (str) .getCanonicalFile ()" pour générer les chemins canoniques, vérifierais ensuite qu'ils respectent vos restrictions en sandbox, et enfin utiliser "File.exists ()", "File.isFile ()" , etc pour vérifier que la source et la destination sont cachères et qu’elles ne sont pas le même objet système de fichiers. Je m'occuperais des caractères illégaux en essayant de faire les opérations et en attrapant les exceptions.

5
Stephen C

Si vous souhaitez utiliser davantage que [A-Za-z0-9], alors vérifiez Conventions de dénomination MS , et n'oubliez pas de filtrer "... Caractères dont les représentations entières vont de 1 à 31 , ... ", comme le fait l'exemple d'Aaron Digulla. Le code par exemple de David Carboni ne serait pas suffisant pour ces personnages.

0
wandlang

Paths.get(...) lève une exception détaillée avec la position du caractère illégal.

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