Comment afficher de mauvais noms de fichiers en Python

Comment afficher de mauvais noms de fichiers en Python
Comment afficher de mauvais noms de fichiers en Python

Imaginez que votre programme a reçu une liste de répertoire, mais lorsqu’il a essayé d’imprimer les noms de fichiers, il s’est crashé avec une exception UnicodeEncodeError et un message tel que “surrogates not allowed”.

Lorsque vous afficher des noms de fichiers d’origine inconnue, utilisez cette convention pour éviter les erreurs:

def bad_filename(nom_de_fichier) :
    return repr(nom_de_fichier)[1:-1].

try:
    print(nom_de_fichier)
except UnicodeEncodeError :
    print(bad_filename(nom_de_fichier))

 

Le code ci-dessus concerne un problème potentiellement rare mais très ennuyeux concernant les programmes qui doivent manipuler le système de fichiers. Par défaut, Python suppose que tous les noms de fichiers sont encodés selon le paramètre défini par sys.getfilesystemencoding().

Cependant, certains systèmes de fichiers n’appliquent pas nécessairement cette restriction d’encodage, ce qui permet de créer des fichiers sans codage approprié du nom de fichier. Ce n’est pas courant, mais il y a toujours le danger qu’un utilisateur fasse quelque chose de stupide et crée un tel fichier par accident (par exemple, en passant un mauvais nom de fichier pour la fonction open() dans un code bogué).

Lors de l’exécution d’une instruction telle que os.listdir(), les mauvais noms de fichiers laissent Python dans un état bloquant. D’un côté, il ne peut pas se débarrasser des mauvais noms. D’un autre côté, il ne peut toujours pas transformer le nom de fichier en une chaîne de texte correcte.

La solution de Python à ce problème est de prendre une valeur d’octet non décodable \xhh dans un nom de fichier et de la mapper dans un “encodage de substitution” représenté par le caractère Unicode \udchh. Voici un exemple de ce à quoi pourrait ressembler une mauvaise liste de répertoire si elle contenait un nom de fichier bäd.txt, encodé en Latin-1 au lieu de UTF-8:

>>> import os
>>> fichiers = os.listdir('.')
>>> fichiers 
['zbam.py', 'b\udce4d.txt', 'foto.txt']
>>>

Si vous avez du code qui manipule les noms de fichiers ou même les passe comme paramètres à des fonctions telle que open(), tout fonctionne normalement.

Ce n’est que dans les situations où vous souhaitez éditer le nom de fichier que vous rencontrez des problèmes (par exemple, en l’affichant à l’écran, en l’enregistrant, etc.). Plus précisément, si vous avez essayé d’afficher la liste précédente, votre programme plantera:

>>> for nom in fichiers:
...     print(nom)
...
spam.py
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
UnicodeEncodeError: 'utf-8' codec can't encode character '\udce4' in
position 1: surrogates not allowed
>>>

 

La raison pour laquelle il se bloque est que le caractère \udce4 est techniquement est un Unicode invalide. Il s’agit en fait de la deuxième moitié d’une combinaison de deux caractères connue sous le nom de paire de substitution.

Cependant, comme la première mi-temps est manquante, c’est un unicode invalide. Ainsi, la seule façon de produire une sortie valide est de prendre des mesures correctives lorsqu’un mauvais nom de fichier est rencontré.

Par exemple, vous pouvez utiliser le code suivant pour corriger le problème:

>>> for nom in fichiers:
...     try:
...             print(nom)
...     except UnicodeEncodeError:
...             print(bad_filename(nom))
...

Voici le résulta de l’éxécution du code ci-dessus:

spam.py
b\udce4d.txt
foo.txt

Le choix de ce qu’il faut faire pour la fonction bad_filename() dépend largement de vous. Une autre option est de réencoder la valeur d’une manière ou d’une autre, comme ceci:

def bad_filename(nom_de_fichier) :
    temp = nom_de_fichier.encode(sys.getfilesystemencoding(), errors='subsrogateescape')
    return temp.decode('latin-1')

L’utilisation de cette version produit la sortie suivante:

>>> for nom in fichiers:
...     try:
...             print(nom)
...     except UnicodeEncodeError:
...             print(bad_filename(nom))
...
spam.py
bäd.txt
foo.txt
>>>

Finalement, si vous écrivez des scripts critiques qui doivent fonctionner de manière fiable avec les noms de fichiers et le système de fichiers, c’est une chose à laquelle il faut réfléchir. Sinon, vous risquez de déboguer une erreur apparemment insondable.

LAISSER UN COMMENTAIRE

Please enter your comment!
Please enter your name here