web-dev-qa-db-fra.com

Différence entre l'analyse d'un fichier texte en mode r et rb

Qu'est-ce qui rend l'analyse d'un fichier texte en mode "r" plus pratique que l'analyse en mode "rb"? Surtout lorsque le fichier texte en question peut contenir des caractères non ASCII.

52
That Umbrella Guy

Cela dépend un peu de la version de Python que vous utilisez. Dans Python 2, réponse de Chris Drappier s'applique).

En Python 3, c'est une histoire différente (et plus cohérente): en mode texte ('r'), Python analysera le fichier selon au codage de texte que vous lui donnez (ou, si vous n'en donnez pas, une valeur par défaut dépendante de la plate-forme), et read() vous donnera un str. En binaire ('rb'), Python ne suppose pas que le fichier contient des éléments qui peuvent raisonnablement être analysés en tant que caractères, et read() vous donne un objet bytes .

De plus, dans Python 3, les sauts de ligne universels (la traduction entre '\n' Et les conventions de saut de ligne spécifiques à la plate-forme pour que vous n'ayez pas à vous en soucier) sont disponibles pour le texte- fichiers de mode sur n'importe quelle plate-forme , pas seulement Windows.

60
lvc

à partir de documentation :

Sous Windows, "b" ajouté au mode ouvre le fichier en mode binaire, il existe donc également des modes comme "rb", "wb" et "r + b". Python sous Windows fait une distinction entre les fichiers texte et binaires; les caractères de fin de ligne dans les fichiers texte sont automatiquement légèrement modifiés lorsque les données sont lues ou écrites. Cette modification en arrière-plan de les données de fichier sont correctes pour les fichiers texte ASCII, mais cela corrompra les données binaires comme celles des fichiers JPEG ou EXE. Soyez très prudent lorsque vous lisez et écrivez de tels fichiers en mode binaire. Sous Unix, cela ne fait pas de mal d'ajouter un "b" au mode, vous pouvez donc l'utiliser indépendamment de la plate-forme pour tous les fichiers binaires.

22
Chris Drappier

La différence réside dans la gestion de la fin de ligne (EOL). Différents systèmes d'exploitation utilisent différents caractères pour marquer EOL - \n sous Unix, \r dans les versions Mac antérieures à OS X, \r\n sous Windows. Lorsqu'un fichier est ouvert en mode texte, lorsque le fichier est lu, Python remplace le caractère de fin de ligne spécifique au système d'exploitation lu dans le fichier par juste \n. Et vice versa, c'est-à-dire lorsque vous essayez d'écrire \n dans un fichier ouvert en mode texte, il va écrire le caractère EOL spécifique au système d'exploitation. Vous pouvez trouver la fin de votre système d'exploitation par défaut en cochant os.linesep.

Lorsqu'un fichier est ouvert en mode binaire, aucun mappage n'a lieu. Ce que vous lisez est ce que vous obtenez. N'oubliez pas que le mode texte est le mode par défaut. Donc, si vous manipulez des fichiers non textuels (images, vidéo, etc.), assurez-vous d'ouvrir le fichier en mode binaire, sinon vous finirez par gâcher le fichier en introduisant (ou supprimant) quelques octets.

Python dispose également d'un mode de saut de ligne universel. Lorsqu'un fichier est ouvert dans ce mode, Python mappe tous les caractères \r, \n et \r\n à \n.

12
shining

Pour des éclaircissements et pour répondre Commentaire/question d'Agostino (Je n'ai pas une réputation suffisante pour commenter, alors soyez indulgent avec moi en disant cela comme une réponse ...):

En Python 2 aucune modification de fin de ligne ne se produit, ni en mode texte ni en mode binaire - comme cela a été dit précédemment, en Python 2 réponse de Chris Drappier s'applique (veuillez noter que son lien pointe aujourd'hui vers les documents 3.x Python mais le texte cité par Chris provient bien sûr du tutoriel d'entrée et de sortie Python 2 =)

Donc non, il est pas vrai que l'ouverture d'un fichier en mode texte avec Python 2 sous non-Windows effectue toute modification de fin de ligne:

0 $ cat data.txt 
line1
line2
line3
0 $ file data.txt 
data.txt: ASCII text, with CRLF line terminators
0 $ python2.7 -c 'f = open("data.txt"); print f.readlines()'
['line1\r\n', 'line2\r\n', 'line3\r\n']
0 $ python2.7 -c 'f = open("data.txt", "r"); print f.readlines()'
['line1\r\n', 'line2\r\n', 'line3\r\n']
0 $ python2.7 -c 'f = open("data.txt", "rb"); print f.readlines()'

Il est cependant possible d'ouvrir le fichier en mode saut de ligne universel en Python 2, qui effectue exactement ledit mod de fin de ligne:

0 $ python2.7 -c 'f = open("data.txt", "rU"); print f.readlines()'
['line1\n', 'line2\n', 'line3\n']

(le spécificateur de mode de nouvelle ligne universel est obsolète à partir de Python 3.x)

Sur Python 3, d'autre part, les fins de ligne spécifiques à la plate-forme sont normalisées à "\ n" lors de la lecture d'un fichier en mode texte, et "\ n" est converti en la plate-forme actuelle fin de ligne par défaut lors de l'écriture en mode texte (en plus des octets <-> unicode <-> octets décodage/encodage en cours en mode texte). Par exemple, la lecture d'un fichier à la fin de la ligne Dos/Win CRLF sur Linux normalisera la ligne se termine par '\ n'.

2
Holger Joukl