Kaushik
En Python, dado el nombre de un archivo, ¿cómo puedo escribir un bucle que lea un carácter cada vez que pasa por el bucle?
jchl
with open(filename) as f:
while True:
c = f.read(1)
if not c:
print("End of file")
break
print("Read a character:", c)
-
Dado que esto está leyendo un byte a la vez, ¿no fallará para las codificaciones que no son ASCII?
–David Chouinard
15/01/2013 a las 18:30
-
Las preguntas y respuestas son conceptos confusos de caracteres y bytes. Si el archivo está en una codificación de un solo byte por carácter, como Ascii y muchos otros, entonces sí, está leyendo un solo carácter al leer un fragmento del tamaño de un solo byte; de lo contrario, si la codificación requiere más de un solo byte por carácter, entonces está simplemente leyendo un solo byte, no un solo carácter.
– Basilea Shishani
16 de octubre de 2013 a las 1:34
-
Así es. Por lo tanto, a menudo hago
result = open(filename).read()
y luego leerresult
personaje por personaje.– Shravan
30 de junio de 2015 a las 17:27
-
A la pregunta de David Chouinard: este fragmento funciona correctamente en Python 3 con un archivo en codificación UTF-8. Si tiene, por ejemplo, un archivo con codificación Windows-1250, simplemente cambie la primera línea a
with open(filename, encoding='Windows-1250') as f:
– SergO
21 de enero de 2016 a las 9:17
-
Y para agregar a SergO,
open(filename, "r")
contraopen(filename, "rb")
puede resultar en diferentes números de iteraciones (al menos hablando de Python 3). El modo “r” podría leer varios bytes para obtenerc
si golpea el carácter especial apropiado.– dc310
8 de diciembre de 2017 a las 23:06
Raj
Primero, abre un archivo:
with open("filename") as fileobj:
for line in fileobj:
for ch in line:
print(ch)
Esto pasa por cada línea del archivo y luego por cada carácter de esa línea.
-
De acuerdo, esta parece ser la forma más pitónica de hacerlo. ¿No se encargaría esto de manejar la codificación que no es ASCII también?
– Ron7
28 de noviembre de 2017 a las 9:19
-
Una de las razones por las que puede leer un archivo de un carácter a la vez es que el archivo es demasiado grande para caber en la memoria. Pero la respuesta anterior asume que cada línea puede caber en la memoria.
– CS
11 de febrero de 2018 a las 22:44
-
Editado para que coincida con Python 3.
– usuario11462042
8 de abril de 2020 a las 0:24
-
Dado que el OP nunca mencionó leer todo el archivo un carácter a la vez, este enfoque no es óptimo porque todo el archivo podría estar contenido en una sola línea; en cuyo caso se necesita un tiempo considerable para leer toda la línea antes de que se realice el procesamiento de caracteres. Es mejor usar f.read(1) en lecturas parciales en estos casos.
– búho7
7 de julio de 2021 a las 12:02
-
-1. Secundando el comentario de @CS. El OP preguntó cómo leer “un solo carácter a la vez”, por lo que esto no responde la pregunta. Esto no es más simple que la respuesta aceptada, y es mejor tener una función que a veces no bloquee innecesariamente su script/aplicación. ¿Qué sucede si se trata de un INSERTO SQL para una tabla completa? ¿O usa un carácter de nueva línea no nativo? El mejor de los casos es un almacenamiento en búfer ineficiente; el peor de los casos se está quedando sin memoria.
–Douglas Myers-Turnbull
13 de julio de 2021 a las 20:46
Me gusta la respuesta aceptada: es sencillo y hará el trabajo. También me gustaría ofrecer una implementación alternativa:
def chunks(filename, buffer_size=4096):
"""Reads `filename` in chunks of `buffer_size` bytes and yields each chunk
until no more characters can be read; the last chunk will most likely have
less than `buffer_size` bytes.
:param str filename: Path to the file
:param int buffer_size: Buffer size, in bytes (default is 4096)
:return: Yields chunks of `buffer_size` size until exhausting the file
:rtype: str
"""
with open(filename, "rb") as fp:
chunk = fp.read(buffer_size)
while chunk:
yield chunk
chunk = fp.read(buffer_size)
def chars(filename, buffersize=4096):
"""Yields the contents of file `filename` character-by-character. Warning:
will only work for encodings where one character is encoded as one byte.
:param str filename: Path to the file
:param int buffer_size: Buffer size for the underlying chunks,
in bytes (default is 4096)
:return: Yields the contents of `filename` character-by-character.
:rtype: char
"""
for chunk in chunks(filename, buffersize):
for char in chunk:
yield char
def main(buffersize, filenames):
"""Reads several files character by character and redirects their contents
to `/dev/null`.
"""
for filename in filenames:
with open("/dev/null", "wb") as fp:
for char in chars(filename, buffersize):
fp.write(char)
if __name__ == "__main__":
# Try reading several files varying the buffer size
import sys
buffersize = int(sys.argv[1])
filenames = sys.argv[2:]
sys.exit(main(buffersize, filenames))
El código que sugiero es esencialmente la misma idea que su respuesta aceptada: lea una cantidad determinada de bytes del archivo. La diferencia es que primero lee una buena parte de los datos (4006 es un buen valor predeterminado para X86, pero es posible que desee probar 1024 u 8192; cualquier múltiplo del tamaño de su página), y luego produce los caracteres en esa parte. por uno.
El código que presento puede ser más rápido para archivos más grandes. Tomar como ejemplo, el texto completo de Guerra y paz, de Tolstoi. Estos son mis resultados de sincronización (Mac Book Pro con OS X 10.7.4; so.py es el nombre que le di al código que pegué):
$ time python so.py 1 2600.txt.utf-8
python so.py 1 2600.txt.utf-8 3.79s user 0.01s system 99% cpu 3.808 total
$ time python so.py 4096 2600.txt.utf-8
python so.py 4096 2600.txt.utf-8 1.31s user 0.01s system 99% cpu 1.318 total
Ahora: no tome el tamaño del búfer en 4096
como una verdad universal; mire los resultados que obtengo para diferentes tamaños (tamaño de búfer (bytes) frente a tiempo de pared (seg)):
2 2.726
4 1.948
8 1.693
16 1.534
32 1.525
64 1.398
128 1.432
256 1.377
512 1.347
1024 1.442
2048 1.316
4096 1.318
Como puede ver, puede comenzar a ver ganancias antes (y es probable que mis tiempos sean muy inexactos); el tamaño del búfer es una compensación entre el rendimiento y la memoria. El valor predeterminado de 4096 es solo una opción razonable pero, como siempre, mida primero.
joaquín
Justo:
myfile = open(filename)
onecharacter = myfile.read(1)
matias nilsson
Python mismo puede ayudarte con esto, en modo interactivo:
>>> help(file.read)
Help on method_descriptor:
read(...)
read([size]) -> read at most size bytes, returned as a string.
If the size argument is negative or omitted, read until EOF is reached.
Notice that when in non-blocking mode, less data than what was requested
may be returned, even if no size parameter was given.
-
Estoy de acuerdo con el sentimiento, pero ¿quizás esto sea más adecuado como comentario para el OP?
– Mike Bóers
7 de junio de 2010 a las 12:56
-
Podría ser, pero creo que todo ese texto se vería desordenado en un comentario.
–Mattias Nilsson
7 de junio de 2010 a las 13:23
Michael Kropat
Hoy aprendí un nuevo modismo para esto mientras miraba la película de Raymond Hettinger. Transformando el código en Python hermoso e idiomático:
import functools
with open(filename) as f:
f_read_ch = functools.partial(f.read, 1)
for ch in iter(f_read_ch, ''):
print 'Read a character:', repr(ch)
-
Estoy de acuerdo con el sentimiento, pero ¿quizás esto sea más adecuado como comentario para el OP?
– Mike Bóers
7 de junio de 2010 a las 12:56
-
Podría ser, pero creo que todo ese texto se vería desordenado en un comentario.
–Mattias Nilsson
7 de junio de 2010 a las 13:23
david sikes
Solo lee un solo carácter
f.read(1)