python file python-3.3

python - Buscando desde el final del archivo lanzando una excepción no soportada



file python-3.3 (3)

Tengo este fragmento de código y estoy intentando buscar hacia atrás desde el final del archivo usando python:

f=open(''D:/SGStat.txt'',''a''); f.seek(0,2) f.seek(-3,2)

Esto lanza la siguiente excepción mientras se ejecuta:

f.seek(-3,2) io.UnsupportedOperation: can''t do nonzero end-relative seeks

¿Me estoy perdiendo de algo?


De la documentation de Python 3.2 y superior:

En los archivos de texto (los que se abren sin una b en la cadena de modo), solo se permiten búsquedas relativas al principio del archivo (la excepción es buscar el final del archivo con la seek(0, 2) ).

Por lo tanto, puedes cambiar tu programa para leer:

f = open(''D:/SGStat.txt'', ''ab'') f.seek(0, 2) f.seek(-3, 2)

Sin embargo, debe tener en cuenta que agregar el indicador b cuando está leyendo o escribiendo texto puede tener consecuencias no deseadas (por ejemplo, con codificación multibyte) y, de hecho, cambia el tipo de datos leídos o escritos . Para una discusión más detallada de la causa del problema y una solución que no requiera agregar la marca b , vea otra respuesta a esta pregunta .


Las respuestas existentes responden a la pregunta, pero no proporcionan ninguna solución.

De readthedocs :

Si el archivo se abre en modo de texto (sin b ), solo las compensaciones devueltas por tell() son legales. El uso de otras compensaciones provoca un comportamiento indefinido.

Esto está respaldado por documentation , que dice que:

En los archivos de texto (los que se abren sin una b en la cadena de modo), solo se permiten búsquedas relativas al principio del archivo [ os.SEEK_SET ] ...

Esto significa que si tienes este código del antiguo Python:

f.seek(-1, 1) # seek -1 from current position

Se vería así en Python 3:

f.seek(f.tell() - 1, os.SEEK_SET) # os.SEEK_SET == 0

Solución

Al juntar esta información podemos lograr el objetivo del OP:

f.seek(0, os.SEEK_END) # seek to end of file; f.seek(0, 2) is legal f.seek(f.tell() - 3, os.SEEK_SET) # go backwards 3 bytes


Para utilizar la búsqueda desde la posición actual y el final, debe abrir el archivo de texto en modo binario. Vea este ejemplo donde he creado un archivo "nums.txt" y puse "ABCDEFGHIJKLMNOPQRSTUVWXYZ" en el archivo. Leí las letras de la cadena "PYTHON" del archivo y las muestro. Vea el código que he ejecutado en las ventanas de Python 3.6 en anaconda 4.2

>>> file=open(''nums.txt'',''rb'') >>> file.seek(15,0) 15 >>> file.read(1).decode(''utf-8'') ''P'' >>> file.seek(8,1) 24 >>> file.read(1).decode(''utf-8'') ''Y'' >>> file.seek(-7,2) 19 >>> file.read(1).decode(''utf-8'') ''T'' >>> file.seek(7,0) 7 >>> file.read(1).decode(''utf-8'') ''H'' >>> file.seek(6,1) 14 >>> file.read(1).decode(''utf-8'') ''O'' >>> file.seek(-2,1) 13 >>> file.read(1).decode(''utf-8'') ''N''