2017-08-16 14 views
3

J'essaie d'utiliser le module pathlib qui fait partie de la bibliothèque standard dans Python 3.4+ pour trouver et manipuler les chemins de fichiers. Bien que ce soit une amélioration par rapport aux fonctions de style os.path pour pouvoir traiter les chemins de manière orientée objet, j'ai du mal à gérer certains noms de fichiers plus exotiques sur les systèmes de fichiers Posix; fichiers spécifiquement dont les noms contiennent octets qui ne peuvent être décodés en UTF-8:Traitement de noms de fichiers Posix non-UTF-8 en utilisant Python pathlib?

>>> pathlib.PosixPath(b'\xe9') 

Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/lib/python3.5/pathlib.py", line 969, in __new__ 
    self = cls._from_parts(args, init=False) 
    File "/usr/lib/python3.5/pathlib.py", line 651, in _from_parts 
    drv, root, parts = self._parse_args(args) 
    File "/usr/lib/python3.5/pathlib.py", line 643, in _parse_args 
    % type(a)) 
TypeError: argument should be a path or str object, not <class 'bytes'> 

>>> b'\xe9'.decode() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 0: unexpected end of data 

Le problème est que sur un système de fichiers Posix, ces fichiers peuvent exister, et je voudrais être en mesure de traiter tous les noms de fichiers valides pour le système de fichiers dans mon application plutôt que de provoquer des erreurs et/ou un comportement imprévisible.

Je peux obtenir un objet PosixPath pour de tels fichiers dans un répertoire en utilisant la méthode .iterdir() du répertoire parent. Mais je n'ai pas encore trouvé un moyen de l'obtenir à partir d'un chemin complet fourni comme variable de type 'bytes', ce qui est plutôt difficile à éviter lors du chargement de chemins d'une autre source supportant toutes les valeurs d'octets brutes valides comme une base de données ou un fichier contenant des chemins séparés par des bits).

Existe-t-il un moyen de le faire que je ne connais pas? Ou, si ce n'est vraiment pas possible: est-ce par conception, ou pourrait-il être considéré comme une déficience dans la bibliothèque standard qui pourrait justifier un rapport de bogue?

J'ai trouvé un related bug report, mais ce problème concernait la documentation mentionnant de manière incorrecte que les arguments de classe 'bytes' étaient autorisés.

Répondre

2

Je pense que vous pouvez obtenir ce que vous voulez comme ceci:

import os 
PosixPath(os.fsdecode(b'\xe9')) 

Démo:

>>> import os, pathlib 
>>> b = b'\xe9' 
>>> p = pathlib.Path(os.fsdecode(b)) 
>>> p.exists() 
False 
>>> with open(b, mode='w') as f: 
...  f.write('wacky filename') 
...  
>>> p.exists() 
True 
>>> p.read_bytes() 
b'wacky filename' 
>>> os.listdir(b'.') 
[b'\xe9'] 
+0

Merci. Bien que j'avais vu 'surrogateencoding' mentionné dans les discussions de Python 3 en passant, je ne savais pas qu'il permettait de représenter toute valeur d'octet brut comme des points de code Unicode, et que ce mécanisme fournissait une solution viable au problème rencontré. Je pense toujours qu'être capable d'utiliser de vrais 'bytes' serait une approche sémantiquement plus significative (les données brutes ne sont pas * vraiment * Unicode après tout). Sur le plan positif, la connaissance de cette astuce me permettra probablement de résoudre des situations problématiques similaires et de réduire le besoin de stockage persistant de type «octets bruts». –

+0

Dans ce cas, c'est en fait avec POSIX que je suis en désaccord. Nous pouvons avoir des noms de fichiers avec des encodages différents simplement assis dans le même répertoire, c'est un gâchis. Peut-être l'une des rares choses que Windows a fait mieux que Linux ces jours-ci. – wim

+0

Je suis d'accord, avoir des noms de fichiers comme octets bruts est une approche plutôt datée (expliquée par la longue histoire derrière Posix, je suppose) maintenant que tout le monde en ligne a pratiquement réglé Unicode/UTF-8. Il semble que l'approche de Python en utilisant des paires de substitution à cette fin pourrait en fait fournir une avenue aux systèmes Linux/UNIX pour permettre la migration vers Unicode tout en maintenant la rétrocompatibilité. Là encore, les gens travaillent probablement déjà là-dessus ... –