2012-09-06 18 views
12

Possible Duplicate:
Get last n lines of a file with Python, similar to tail
Read a file in reverse order using pythonlectura pitón sólo el final del texto enorme presentar

Tengo un archivo que está alrededor de 15 GB de tamaño, se trata de un archivo de registro que se supone que debo analizar la salida de. Ya hice un análisis básico de un archivo similar pero GRANDEMENTE más pequeño, con solo algunas líneas de registro. El análisis de cadenas es no el problema. El problema es el gran archivo y la cantidad de datos redundantes que contiene.

Básicamente estoy intentando hacer un script de python que pueda decir; por ejemplo, dame 5000 últimas líneas del archivo. Eso es una vez más el manejo básico de los argumentos y todo eso, nada especial allí, puedo hacer eso.

Pero, ¿cómo puedo definir o decirle al lector de archivos que SÓLO lea la cantidad de líneas que especifiqué desde el final del archivo? Estoy tratando de omitir la cantidad de líneas huuuuuuge al principio de un archivo ya que no estoy interesado en eso y para ser honesto, leer alrededor de 15GB de líneas de un archivo txt lleva demasiado tiempo. ¿Hay alguna manera de equivocarse ... empezar a leer desde ... el final del archivo? ¿Eso tiene sentido?

Todo se reduce a la cuestión de leer un archivo de 15 GB, línea por línea lleva demasiado tiempo. Así que quiero omitir los datos ya redundantes (redundantes para mí al menos) al principio y solo leer la cantidad de líneas del final del archivo que quiero leer.

La respuesta obvia es copiar manualmente N cantidad de líneas del archivo a otro archivo, pero ¿hay alguna manera de hacerlo semi-auto-mágicamente solo para leer la cantidad N de líneas desde el final del archivo con python ?

+0

¿Qué sistema operativo está utilizando? –

+2

No es una respuesta directa, pero si está usando nix, puede aceptar la entrada de stdin y simplemente enviar los datos usando 'tail hugefile.txt -n1000 | python myprog.py' – moopet

+1

Ver las respuestas en la pregunta duplicada. El primero es relativamente independiente de la plataforma, el segundo funciona bien en los sistemas basados ​​en UNIX (utilizando el comando 'tail' como se sugiere @moopet). –

Respuesta

-1

El método preferido en este punto era simplemente usar la cola de Unix para el trabajo y modificar el pitón para aceptar la entrada a través de la entrada estándar.

tail hugefile.txt -n1000 | python magic.py 

No es nada sexy, pero al menos se ocupa del trabajo. El gran archivo es una carga demasiado grande de manejar, me enteré. Al menos para mis habilidades de pitón. Así que fue mucho más fácil solo agregarle una pizca de magia nix para reducir el tamaño del archivo. Tail era nuevo para mí, entonces. Aprendí algo y descubrí otra forma de utilizar la terminal a mi favor otra vez. Gracias a todos.

4

Granja esto a UNIX:

import os 
os.popen('tail -n 1000 filepath').read() 

uso subprocess.Popen en lugar de os.popen si tiene que ser capaz de acceder a stderr (y algunas otras características)

+0

Muchas respuestas útiles en este hilo, pero para fines prácticos, su respuesta parece ser la más relevante, ¡merece una clasificación más alta! – isosceleswheel

0

Aunque yo preferiría la solución 'cola': si conoce la cantidad máxima de caracteres por línea puede implementar otra solución posible obteniendo el tamaño del archivo, abra un manejador de archivos y use el método 'buscar' con una cantidad estimada de caracteres que esté buscando para.

Este código final debería tener el siguiente aspecto: solo para explicar por qué también prefiero la solución de cola :) ¡buena suerte!

MAX_CHARS_PER_LINE = 80 
size_of_file = os.path.getsize('15gbfile.txt') 
file_handler = file.open('15gbfile.txt', "rb") 
seek_index = size_of_file - (number_of_requested_lines * MAX_CHARS_PER_LINE) 
file_handler.seek(seek_index) 
buffer = file_handler.read() 

puede mejorar este código analizando las nuevas líneas del búfer que lee. Buena suerte (y se debe utilizar la solución de cola ;-) Estoy seguro de que usted puede conseguir la cola para cada sistema operativo)

11

es necesario buscar a la final del archivo, a continuación, leer algunos trozos en bloques de al final, líneas de conteo, hasta que haya encontrado suficientes líneas nuevas para leer sus líneas n.

Básicamente, está implementando una forma simple de cola.

Aquí hay algo de código probado la ligera que hace precisamente eso:

import os, errno 

def lastlines(hugefile, n, bsize=2048): 
    # get newlines type, open in universal mode to find it 
    with open(hugefile, 'rU') as hfile: 
     if not hfile.readline(): 
      return # empty, no point 
     sep = hfile.newlines # After reading a line, python gives us this 
    assert isinstance(sep, str), 'multiple newline types found, aborting' 

    # find a suitable seek position in binary mode 
    with open(hugefile, 'rb') as hfile: 
     hfile.seek(0, os.SEEK_END) 
     linecount = 0 
     pos = 0 

     while linecount <= n + 1: 
      # read at least n lines + 1 more; we need to skip a partial line later on 
      try: 
       hfile.seek(-bsize, os.SEEK_CUR)   # go backwards 
       linecount += hfile.read(bsize).count(sep) # count newlines 
       hfile.seek(-bsize, os.SEEK_CUR)   # go back again 
      except IOError, e: 
       if e.errno == errno.EINVAL: 
        # Attempted to seek past the start, can't go further 
        bsize = hfile.tell() 
        hfile.seek(0, os.SEEK_SET) 
        linecount += hfile.read(bsize).count(sep) 
        break 
       raise # Some other I/O exception, re-raise 
      pos = hfile.tell() 

    # Re-open in text mode 
    with open(hugefile, 'r') as hfile: 
     hfile.seek(pos, os.SEEK_SET) # our file position from above 

     for line in hfile: 
      # We've located n lines *or more*, so skip if needed 
      if linecount > n: 
       linecount -= 1 
       continue 
      # The rest we yield 
      yield line 
+0

¿Cómo se imprimen las líneas producidas? – Superdooperhero

+0

Me da: Trazaback (última llamada más reciente): Archivo "tail3.py", línea 45, en últimas líneas (r "E: \ D_Backup \ Descargas \ googlebooks-eng-all-2gram-20120701-_NOUN_", 1000, bsize = 2048) Archivo "tail3.py", línea 21, en las últimas líneas linecount + = hfile.read (bsize) .count (sep) # count newlines TypeError: se requiere un objeto de tipo byte, no ' str ' – Superdooperhero

+1

@Superdooperhero: el código fue escrito para Python 2, no Python 3. Tendría que usar 'sep.encode()' para obtener un objeto 'bytes' en su lugar. –

Cuestiones relacionadas