7 votes

Java ne peut pas voir le fichier sur le système de fichiers qui contient des caractères illégaux

J'expérimente avec un cas limite que nous voyons en production. Nous avons un modèle d'entreprise dans lequel les clients génèrent des fichiers texte et les transfèrent par FTP sur nos serveurs. Nous ingérons ces fichiers et les traitons sur notre backend Java (fonctionnant sur des machines CentOS). La plupart (95 % et plus) de nos clients savent générer ces fichiers en UTF-8, ce qui correspond à ce que nous voulons. Cependant, nous avons quelques clients têtus (mais de gros comptes) qui génèrent ces fichiers sur une machine Windows avec le jeu de caractères CP1252. Pas de problème, nous avons configuré nos librairies tierces (qui font la plus grande partie du travail de "traitement" pour nous) pour qu'elles gèrent les entrées dans n'importe quel jeu de caractères grâce à une sorte de magie.

De temps en temps, nous voyons arriver un fichier dont le nom contient des caractères UTF-8 illégaux (CP1252). Lorsque notre logiciel tente de lire ces fichiers à partir du serveur FTP, la méthode normale de lecture des fichiers s'arrête et génère un message d'erreur. FileNotFoundException :

File f = getFileFromFTPServer();
FileReader fReader = new FileReader(f);

String line = fReader.readLine();
// ...etc.

Les exceptions ressemblent à ceci :

java.io.FileNotFoundException: /path/to/file/some-text-blah?blah.xml (No such file or directory) at java.io.FileInputStream.open(Native Method) at 
java.io.FileInputStream.(FileInputStream.java:120) at java.io.FileReader.(FileReader.java:55) at com.myorg.backend.app.InputFileProcessor.run(InputFileProcessor.java:60) at 
java.lang.Thread.run(Thread.java:662)

Donc je pense que ce qui se passe c'est que parce que le fichier nom contient des caractères illégaux, nous ne pouvons même pas le lire en premier lieu. Si nous le pouvions, alors quel que soit le contenu du fichier, notre logiciel devrait être capable de le traiter correctement. Il s'agit donc d'un problème de lecture de noms de fichiers contenant des caractères UTF-8 illégaux.

À titre de test, j'ai créé une "application" Java très simple à déployer sur l'un de nos serveurs et à tester certaines choses (le code source est fourni ci-dessous). Je me suis ensuite connecté à une machine Windows et j'ai créé un fichier de test que j'ai nommé test£.txt . Remarquez le caractère après "test" dans le nom du fichier. C'est Alt-0163. Je l'ai transféré par FTP sur notre serveur, et quand j'ai exécuté ls -ltr sur son répertoire parent, j'ai été surpris de voir qu'il était listé comme test?.txt .

Avant d'aller plus loin, voici l'"application" Java que j'ai écrite pour tester/reproduire ce problème :

public Driver {
    public static void main(String[] args) {
        Driver d = new Driver();
        d.run(args[0]);     // I know this is bad, but its fine for our purposes here
    }

    private void run(String fileName) {
        InputStreamReader isr = null;
        BufferedReader buffReader = null;
        FileInputStream fis = null;
        String firstLineOfFile = "default";

        System.out.println("Processing " + fileName);

        try {
            System.out.println("Attempting UTF-8...");

            fis = new FileInputStream(fileName);
            isr = new InputStreamReader(fis, Charset.forName("UTF-8"));
            buffReader = new BufferedReader(isr);

            firstLineOfFile = buffReader.readLine();

            System.out.println("UTF-8 worked and first line of file is : " + firstLineOfFile);
        }
        catch(IOException io1) {
            // UTF-8 failed; try CP1252.
            try {
                System.out.println("UTF-8 failed. Attempting Windows-1252...(" + io1.getMessage() + ")");

                fis = new FileInputStream(fileName);
                // I've also tried variations "WINDOWS-1252", "Windows-1252", "CP1252", "Cp1252", "cp1252"
                isr = new InputStreamReader(fis, Charset.forName("windows-1252"));
                buffReader = new BufferedReader(isr);

                firstLineOfFile = buffReader.readLine();

                System.out.println("Windows-1252 worked and first line of file is : " + firstLineOfFile);
            }
            catch(IOException io2) {
                // Both UTF-8 and CP1252 failed...
                System.out.println("Both UTF-8 and Windows-1252 failed. Could not read file. (" + io2.getMessage() + ")");
            }
        }
    }
}

Lorsque j'exécute ceci à partir du terminal ( java -cp . com/Driver t* ), j'obtiens le résultat suivant :

Processing test.txt
Attempting UTF-8...
UTF-8 failed. Attempting Windows-1252...(test.txt (No such file or directory))
Both UTF-8 and Windows-1252 failed. Could not read file.(test.txt (No such file or directory))

test.txt ? !?! J'ai fait quelques recherches et j'ai découvert que le "" est le caractère de remplacement Unicode. \uFFFD . Alors je devinez ce qui se passe, c'est que le serveur FTP de CentOS ne sait pas comment traiter les Alt-0163 ( £ ) et le remplace donc par \uFFFD ( ). Mais je ne comprends pas pourquoi ls -ltr affiche un fichier appelé test?.txt ...

Quoi qu'il en soit, il semble que la solution consiste à ajouter une logique qui recherche l'existence de ce caractère dans le nom du fichier et, s'il est trouvé, renomme le fichier en quelque chose d'autre (par exemple, en faisant un "String-wise"). replaceAll("\uFFFD", "_") ou quelque chose comme ça) que le système peut lire et traiter.

Le problème est que Java n'a même pas voir ce fichier sur le système de fichiers. CentOS sait que le fichier est là ( test?.txt ), mais lorsque ce fichier est transmis à Java, ce dernier l'interprète en tant que test.txt et pour une raison quelconque No such file or directory ...

Comment puis-je faire en sorte que Java voit ce fichier pour que je puisse effectuer un File::renameTo(String) sur elle ? Désolé pour l'historique, mais je pense que c'est important car chaque détail compte dans ce scénario. Merci d'avance !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X