2012-03-10 16 views
38

¿Qué hace que el análisis de un archivo de texto en el modo 'r' sea más conveniente que el análisis en el modo 'rb'? Especialmente cuando el archivo de texto en cuestión puede contener caracteres que no sean ASCII.Diferencia entre el análisis de un archivo de texto en el modo r y rb

+0

¿Estás leyendo un archivo de texto o un archivo binario? –

+0

Un archivo de texto. Pero por alguna razón, me dieron el archivo como un byte-stream. – MxyL

Respuesta

44

Esto depende un poco de la versión de Python que esté utilizando. En Python 2, se aplica Chris Drappier's answer.

En Python 3, es una historia diferente (y más coherente): en modo texto ('r'), Python analizará el archivo de acuerdo con la codificación de texto que le proporcione (o, si no lo proporciona, depende de la plataforma por defecto) y read() le dará un str. En el modo binario ('rb'), Python no supone que el archivo contenga elementos que puedan analizarse razonablemente como caracteres, y read() le ofrece un objeto bytes.

Además, en Python 3, los saltos de línea universales (la traducción entre '\n' y específico de la plataforma de nueva línea convenciones por lo que no tiene que preocuparse por ellos) está disponible para los archivos en modo texto en cualquier plataforma , no sólo Windows.

+0

para py3, ¿la lectura en modo texto intentará automáticamente detectar qué tipo de codificación es? Me imagino que tener que detectar la codificación es todo un desafío con un objeto de bytes. – MxyL

+1

@Keikoku La detección de codificación basada únicamente en una secuencia, sin ningún metadato, es imposible: piense en las diversas codificaciones que son ASCII +, utilice el octavo bit para obtener información en lugar de paridad; todos comparten 255 secuencias de un byte válidas, pero solo la mitad (la mitad ASCII) representan el mismo carácter en cada una. El valor predeterminado de Python no es adivinarlo, es una codificación predeterminada para toda la sesión, deletreado 'sys.getdefaultencoding()'. En mi instalación de Py3, es su UTF-8, pero no puede confiar en que ese sea siempre el caso. – lvc

19

del documentation:

En Windows, 'b' adjunta al modo se abre el archivo en modo binario, por lo que también son modos como 'rb', 'wb', y 'r + b '. Python en Windows hace una distinción entre archivos de texto y binarios; los caracteres de fin de línea en los archivos de texto se modifican automáticamente cuando se leen o escriben los datos. Esta modificación entre bastidores de los datos de archivos está bien para los archivos de texto ASCII, pero dañará los datos binarios de esa manera en los archivos JPEG o EXE. Tenga mucho cuidado de usar el modo binario al leer y escribir dichos archivos. En Unix, no está de más agregar una 'b' al modo, por lo que puedes usarla independientemente de la plataforma para todos los archivos binarios.

+0

Entonces, básicamente, tratar de leer líneas en modo binario es mucho más difícil porque no estoy seguro de que el carácter EOL sea \ n o \ r \ n u otra cosa. – MxyL

8

La diferencia radica en cómo se maneja el fin de línea (EOL). Los diferentes sistemas operativos utilizan caracteres diferentes para marcar EOL - \n en Unix, \r en las versiones de Mac anteriores a OS X, \r\n en Windows. Cuando se abre un archivo en modo texto, cuando se lee el archivo, Python reemplaza el carácter de final de línea específico del sistema operativo leído del archivo con solo \n. Y viceversa, es decir, cuando intenta escribir \n en un archivo abierto en modo texto, va a escribir el carácter EOL específico del sistema operativo. Puede encontrar la EOL predeterminada de su sistema operativo marcando os.linesep.

Cuando se abre un archivo en modo binario, no se realiza ninguna asignación. Lo que lees es lo que obtienes. Recuerde, el modo de texto es el modo predeterminado. Entonces, si está manejando archivos que no son de texto (imágenes, video, etc.), asegúrese de abrir el archivo en modo binario, de lo contrario terminará descomponiendo el archivo al introducir (o eliminar) algunos bytes.

Python también tiene un modo de nueva línea universal. Cuando se abre un archivo en este modo, Python mapea todos los caracteres \r, \n y \r\n en \n.

+0

¿Esto es cierto tanto para Python 2 como para Python 3? – Agostino

2

Para mayor claridad y para responder a Agostino's comment/question (no tengo suficiente reputación para comentar de manera que tengan paciencia conmigo indicando esto como una respuesta ...):

En Python 2 sin modificación del extremo de la línea que pasa, ni en el texto ni el modo binario - como se ha indicado anteriormente, en Python 2 aplica Chris Drappier's answer (tenga en cuenta que su enlace hoy en día apunta al 3.x documentación de Python, pero Chris texto citado es, por supuesto, de la Python 2 input and output tutorial)

Así que no, es no cierto que abrir un archivo en modo texto con Python 2 en que no sea Windows hace cualquier extremo de la línea modificación:

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()' 

Sin embargo, es posible abrir el archivo en modo de nueva línea universal en Python 2, que hace exactamente realizar dicha final de línea mod:

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

(el especificador modo de salto de línea universal está obsoleta desde Python 3.x)

En Python 3, por el contrario, la línea específica de la plataforma termina hacen llegar normalizado a la lectura de un archivo de texto en '\ n' modo, y '\ n' se convierte al final de línea predeterminado de la plataforma actual cuando se escribe en modo texto (además de los bytes < -> unicode < -> bytes de decodificación/codificación en modo texto). P.ej. leer un archivo Dos/Win CRLF finalizado en Linux normalizará la línea termina en '\ n'.

+0

La función abierta de Python3 tiene un parámetro de nueva línea para controlar eso si es necesario https://docs.python.org/3/library/functions.html#open "newline controla cómo funciona el modo de nuevas líneas universales (solo se aplica al texto modo). Puede ser Ninguno, '', '\ n', '\ r', y '\ r \ n'. Funciona de la siguiente manera: Al leer la entrada de la secuencia, si newline es None, el modo universal de nuevas líneas es habilitado – Davos

Cuestiones relacionadas