comment
IRC Chat
play_arrow
Este sitio utiliza cookies propias y de terceros. Si continúa navegando consideramos que acepta el uso de cookies. OK Más Información.

Moviendonos entre archivos con python

  • 6 Respuestas
  • 3959 Vistas

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Once

  • *
  • Underc0der
  • Mensajes: 391
  • Actividad:
    0%
  • Reputación 0
    • Ver Perfil
    • El blog de Once
  • Twitter: @don_once
« en: Enero 22, 2015, 04:14:47 am »
Fuente: elblogdeonce.blogspot.com


 A veces, cuando tratamos con archivos necesitamos algo más que sólo leer todo el archivo. Necesitamos poder movernos entre el archivo y leer partes que bien podrían resultar aleatorias. En esta entrada veremos esos métodos que nos brinda Python para conseguir ¡movernos entre los archivos!
 
Abriendo el archivo

Python nos da dos opciones para abrir un archivo:

Código: Python
  1. archivo = open(ruta_archivo, modo_apertura)  # Abrimos el archivo
  2. archivo.read()
  3. archivo.close()  # Cerramos el archivo


Código: Python
  1. with open(ruta_archivo, modo_apertura) as archivo:  # Abrimos el archivo
  2.     print archivo.read()


En la primer forma nos tenemos que preocupar por cerrar el archivo, en la segunda forma, cuando salimos del bloque with Python se encarga de cerrar el archivo por nosotros. Ambas formas retornan un objeto tipo file.

Modos de apertura


Modo apertura    Significado
r    Abre el archivo en modo sólo lectura.
w    Abre el archivo en modo sólo escritura. Si ya existe el archivo éste se sobrescribe; de lo contrario, se crea el archivo.
a    Abre el archivo en modo escritura. Si el archivo ya existe se escribe la información al final.
r+    Abre el archivo en los modos lectura y escritura.
rb    Abre el archivo en modo sólo lectura binaria.
rw    Abre el archivo en modo sólo escritura binaria.
r+b    Abre el archivo en los dos modos lectura y escritura binaria.

En Windows se distingue entre archivos de texto y archivos binarios. Así que debemos tener cuidado con el modo en el que abrimos los archivos.

   
Código: Python
  1. with open("data.txt", "w") as archivo:  # Abrimos el archivo en modo escritura
  2.     print archivo.write("Hola mundo")  # Escribimos en el archivo

En el script anterior abrimos el archivo data.txt y escribimos en el "Hola mundo"

Métodos del objeto file

Leyendo el archivo

Código: Python
  1. archivo.read([tamaño])

El argumento tamaño es opcional y determina la cantidad de bytes que van a ser leídos. Si no se especifica, se leerá todo el archivo.
   
Código: Python
  1. archivo.readline()

El método readline() nos permite leer sólo una línea del archivo.

   
Código: Python
  1. arhivo.readlines()

El método readlines() lee todo el archivo y regresa una lista donde cada elemento es una línea del archivo.

Cada que leemos en el archivo también nos movemos en él, así, la próxima vez que leamos lo haremos un byte a la derecha desde la última posición.
Cuando llegamos al final del archivo, la lectura nos devolverá una cadena vacía.

Leyendo la versión de un PDF

La cabecera de los archivos PDF tienen el formato: %PDF-1.N(EOL)
Donde N es un número que puede ir desde uno hasta siete y representa la especificación y (EOL) representa un final del línea que puede ser un retorno de carro, una línea nueva o ambas.


Así pues,  tenemos dos opciones para leer la versión de un archivo PDF.
   
Código: Python
  1. with open("pdf.pdf", "r") as archivo:  # Abrimos el archivo
  2.     print archivo.readline()  # Leemos la primer línea

Leemos la primer línea completa del archivo.
Citar
%PDF-1.4\n

   
Código: Python
  1. with open("pdf.pdf", "r") as archivo:  # Abrimos el archivo
  2.     print archivo.read(8)  # Leemos los primeros ocho bytes del archivo

Sólo leemos los primeros ocho bytes del archivo.
Citar
%PDF-1.4

Otros métodos del objeto file

Conocer la posición en el archivo

Como ya se explicó antes, cada que leemos el archivo, también nos movemos en el, con el método tell() Python nos permite conocer la posición (el byte) donde estamos en el archivo.
   
Código: Python
  1. with open("pdf.pdf", "r") as archivo:  # Abrimos el archivo
  2.     print "Posición inicial:", archivo.tell()
  3.     print "Cabecera:", archivo.read(8)
  4.     print "Posición final:", archivo.tell()

Citar
Posición inicial: 0
Cabecera: %PDF-1.4
Posición final: 8

Moviéndonos entre el archivo
   
Código: Python
  1. archivo.seek(bytes, [desde_donde])

El argumento bytes indica la cantidad de bytes que nos vamos a mover dentro del archivo.

El argumento desde_donde es opcional, puede tomar tres valores 0, 1 y 2 e indica desde donde nos vamos a mover. 0 (valor por defecto) indica que nos vamos a mover desde el principio del archivo. 1 indica que nos vamos a mover desde donde se encuentra actualmente el puntero. 2 indica que nos vamos a mover desde el final del archivo.

Si el argumento desde_donde es especificado y es distinto que 0, entonces el argumento bytes puede tomar valores negativos y positivos. Un valor positivo indica que nos vamos a mover hacía la derecha y un valor negativo indica que nos vamos a mover hacía la izquierda.

Leyendo un archivo desde atrás
A veces necesitamos leer los archivos desde atrás ya sea porque las especificaciones así lo requieren (como en el formato PDF) o porque lo que nos interesa está ahí ej. los típicos casos de esteganografía por EOF (End Of File) donde la información que queremos ocultar la guardamos al final de una imagen. Si no pudiéramos movernos entre el archivo, tendríamos que leer todo el archivo y luego sí leer la parte que necesitamos.

Para este ejemplo vamos a usar la imagen principal de la entrada que guardaremos como "moviendonos.png". He guardado un pequeño mensaje ahí que ocupa los últimos 26 bytes.

   
Código: Python
  1. with open("moviendonos.png", "r") as archivo:  # Abrimos el archivo
  2.     archivo.seek(1, 2)  # Nos movemos al final del archivo
  3.     buffer = ""
  4.     for _ in xrange(26):  # Recorremos los 26 bytes
  5.         archivo.seek(-2, 1)  #  Nos movemos dos bytes a la izquierda
  6.         buffer += archivo.read(1)  # Leemos un byte
  7.  
  8. print buffer

En el ejemplo anterior estamos abriendo un archivo binario en modo texto (lo ideal es hacerlo en modo binario) "rb" Gracias a Azav por la observación

Recordemos que cuando leemos el archivo sin importar el método que usemos, Python comenzará a leer desde el byte a la derecha de donde se encuentra el puntero. Por eso en la quinta línea nos movemos dos bytes a la izquierda y cuando leemos en la sexta línea nos movemos un byte a la derecha.

El resultado es:


Citar
elblogdeonce.blogspot.com

Por lo general se usa un "separador" para delimitar donde acaba el archivo original y comienza nuestro mensaje; así que si no conocemos la cantidad de bytes que tiene el mensaje escondido, podemos seguir leyendo hasta que encontremos el separador. Teniendo en cuenta que como estamos leyendo desde atrás, el mensaje también lo estaremos leyendo desde atrás.

Si abrimos la imagen con un editor hexadecimal podemos ver que el mensaje está escrito al revés. Por eso cuando lo leemos es legible.


Con esto terminamos la entrada de hoy, cualquier comentario es bienvenido.

Fuente: No tienes permisos para ver links. Registrate o Entra con tu cuenta

Saludos!
Once
« Última modificación: Enero 23, 2015, 04:04:52 pm por Once »






No tienes permisos para ver links. Registrate o Entra con tu cuenta

Conectado blackdrake

  • *
  • Co Admin
  • Mensajes: 1914
  • Actividad:
    1.67%
  • Reputación 15
    • Ver Perfil
« Respuesta #1 en: Enero 22, 2015, 07:38:23 am »
Muy buen tutorial Once, la verdad es que estoy empezando con python y me viene muy bien!

Gracias ^^



Desconectado Once

  • *
  • Underc0der
  • Mensajes: 391
  • Actividad:
    0%
  • Reputación 0
    • Ver Perfil
    • El blog de Once
  • Twitter: @don_once
« Respuesta #2 en: Enero 22, 2015, 01:10:39 pm »
Gracias brother, espero que te sirva.

Saludos!






No tienes permisos para ver links. Registrate o Entra con tu cuenta

Desconectado Azav

  • *
  • Underc0der
  • Mensajes: 23
  • Actividad:
    0%
  • Reputación 0
    • Ver Perfil
« Respuesta #3 en: Enero 22, 2015, 05:12:15 pm »
Vaya coincidencia que publiques esto porque justo la semana pasada estuve explorando esto en python. Me parece bueno el artículo, bien explicado, sencillo y fácil de entender.

Aprovecho de hacer algunos comentarios. Notar que a diferencia de Once yo uso Python 3.x y él usa 2.x y eso significa que podrían haber varias diferencias.

Primero, en los modos de apertura, cuando uno no escribe la letra b, que significa abrir como binario, automáticamente el archivo se abre como texto (sería lo mismo que escribir una t) y a mi juicio uno no debería abrir nunca un archivo binario en modo texto. Hago este comentario porque en el apartado Leyendo un archivo desde atrás tu abres una imagen .png como texto (ya que no especificaste la letra b) y existen muchos bytes que no pueden leerse como strings, lo que traería como resultado una excepción del tipo UnicodeError. Para ser más claro, si abres el archivo moviendonos.png con un editor hexadecimal y agregas un byte 81 al final del archivo, entonces va a surgir un UnicodeError al intentar leer los últimos bytes en modo texto.

Esto se debe a que existen ciertos bytes (81, 8D, 8F, 90, y 9D) que no tienen un carácter asociado y arrojan un UnicodeDecodeError al intentar transformarlos a string. También hay otro grupo de bytes que si bien tienen caracteres asociados, esos caracteres no son imprimibles (ocurre con casi todos entre el byte 80 y el FF y entre el 00 y el 20) y al intentar imprimirlos van a lanzar un UnicodeEncodeError aunque estos últimos van a depender dónde se quieran imprimir.

La solución es abrir el archivo como binario, leer todos sus bytes y luego intentar pasarlos a string usando el método decode(), publico una parte del código que hice en mi investigación la semana pasada, aplicado al caso:

Código: Python
  1. targetfile = open('moviendonos.png', 'rb')
  2. targetfile_data = targetfile.read() #Data como bytes
  3. targetfile.close()
  4. string = targetfile_data.decode('cp1252', 'replace')[-27:] #Data como string.
  5. """
  6. Me llevo mucho tiempo descubrir que encriptación debia usar para decodificar los bytes. Después de muchas pruebas descubri que era 'cp1252'. Incluso tuve que crear otro programa para descubrirla, en la documentación de python no la encontré.
  7. El modo 'replace' reemplaza los bytes que no tienen caracteres asociados sin embargo quedan los bytes que tienen caracteres asociados no imprimibles.
  8. """
  9. #Reemplazamos los caracteres no imprimibles por espacios en blanco.
  10. pos_no_imprimibles = []
  11. while True:
  12.         try:
  13.                 print(string)
  14.                 break
  15.         except UnicodeEncodeError as EncError:
  16.                 PosErr = EncError.args[2] #El error nos dice la posicion del caracter no imprimible
  17.                 """
  18.                 La posicion que nos entrega el UnicodeEncodeError tiene el problema de que en un string considera el '\n' como dos caracteres.
  19.                 De modo que si el caracter no imprimible es \CNI y tenemos el string "\n\CNI", segun UnicodeEncodeError la posicion de \CNI es 2, mientras que la posicion real es 1.
  20.                 Este es un error que demoré mucho en descubrir y para repararlo es necesario este codigo.
  21.                 """
  22.                 contador = 0
  23.                 result = -1
  24.                 while True:
  25.                         result = string[:PosErr - contador].find("\n", result + 1)
  26.                         if result != -1:
  27.                                 contador += 1
  28.                         else:
  29.                                 break
  30.                 PosErr = PosErr - contador
  31.                 """Fin del codigo reparador"""
  32.                 string = string[:PosErr] + " " + string[PosErr + 1:] #Reemplazamos el caracter no imprimible por un espacio
  33.  

Tal vez me excedí en longitud del comentario pero quería aprovechar de compartir mis investigaciones. Fuera de esas sutilizas esta todo perfecto. ¡Gracias Once!
« Última modificación: Enero 22, 2015, 05:17:56 pm por Azav »

Desconectado WhiZ

  • *
  • Underc0der
  • Mensajes: 395
  • Actividad:
    0%
  • Reputación 0
    • Ver Perfil
« Respuesta #4 en: Enero 22, 2015, 05:42:04 pm »
Excelente aporte Once! Y muchas gracias Azav por complementarlo con tu información!

Así es como crecemos entre todos.

Un saludo y gracias por compartir!
WhiZ


Desconectado Once

  • *
  • Underc0der
  • Mensajes: 391
  • Actividad:
    0%
  • Reputación 0
    • Ver Perfil
    • El blog de Once
  • Twitter: @don_once
« Respuesta #5 en: Enero 22, 2015, 09:43:11 pm »
@Azav

Tienes toda la razón brother, como fui yo quien agregó la información al final del archivo no contemplé la posibilidad de que hubieran bytes no imprimibles. Ahí hago la aclaración. Muchas gracias por la observación!

En cuando al código que publicaste, no estoy muy familiarizado con Python 3.* pero la idea de la entrada era justo mostrar que se puede leer partes del archivo sin la necesidad de tener que leer todo el archivo. Piensa que tienes un archivo algo grande y lo único que necesitas es sacarle los metadatos, leer todo el archivo sería un gasto innecesario de memoria y tiempo. Mira que tienes que leer todo el archivo para usar sólo los últimos 27 bytes.

Por cierto, me parece que te complicaste mucho para sacar los caracteres imprimibles. Así lo haría yo, usando una lista blanca:

Código: Python
  1. # -*- coding: utf-8 -*-
  2.  
  3. import string
  4.  
  5. permitidos = string.ascii_letters + string.digits  # Lista blanca
  6.  
  7. with open("moviendonos.png", "rb") as archivo:
  8.     archivo.seek(1, 2)
  9.     buffer = ""
  10.     for _ in xrange(27):
  11.         archivo.seek(-2, 1)
  12.         byte = archivo.read(1)
  13.         if byte in permitidos:  # Verificamos si el byte leído está en la lista
  14.             buffer += byte
  15.  
  16. print buffer
  17.  

Así todos los caracteres deberían ser imprimibles. (Aunque no estoy muy seguro si es a lo que ter refieres)

Saludos y gracias de nuevo!






No tienes permisos para ver links. Registrate o Entra con tu cuenta

Desconectado Azav

  • *
  • Underc0der
  • Mensajes: 23
  • Actividad:
    0%
  • Reputación 0
    • Ver Perfil
« Respuesta #6 en: Enero 23, 2015, 12:30:11 am »
¡Vaya! No tenía idea de la libreria string. De haberla conocido me hubiera ahorrado bastante tiempo, aunque la verdad nunca se me hubiera ocurrido hacer una lista blanca. Definitivamente era muchísimo más simple así.

Algunos comentarios del código. Los caracteres imprimibles no son sólo letras y dígitos, también son los símbolos, los saltos de linea, etc. Para eso tu librería string cuenta con un atributo más específico aún: string.printable. Lo otro que veo es que en la linea 13 tu buscas un byte en una cadena de strings (osea nunca vas a encontrar un byte en la lista). Usando los métodos .encode() para strings y .decode() para bytes se puede solucionar el asunto. El código modificado y funcional para mí sería:

Código: Python
  1. import string
  2.  
  3. permitidos = string.printable.encode('cp1252')  # Lista blanca DE BYTES
  4.  
  5. with open("moviendonos.png", "rb") as archivo:
  6.     archivo.seek(1, 2)
  7.     buffer = ""
  8.     for _ in range(27):
  9.         archivo.seek(-2, 1)
  10.         byte = archivo.read(1)
  11.         if byte in permitidos:  # Verificamos si el byte leído está en la lista blanca de bytes.
  12.             buffer += byte.decode('cp1252') #De estarlo, lo transformamos nuevamente a string y lo unimos a buffer.
  13.  
  14. print(buffer)
  15.  

Nunca se me hubiera ocurrido hacerlo así, pero claramente era una excelente idea, nos evitamos usar try-except y manejar excepciones que puede ser muy tedioso. ¡Gracias Once!
« Última modificación: Enero 23, 2015, 12:36:12 am por Azav »

 

¿Te gustó el post? COMPARTILO!



[Código] Yardas a metros - Metros a yardas [Python]

Iniciado por LucaSthefano

Respuestas: 0
Vistas: 1419
Último mensaje Mayo 29, 2011, 01:27:34 am
por LucaSthefano
Python Trojan - By "bLiNdFiR3"

Iniciado por d33k40

Respuestas: 1
Vistas: 2111
Último mensaje Abril 03, 2010, 11:01:59 pm
por Dharok
Python phpmyadmin "BruteForce"

Iniciado por linkgl

Respuestas: 2
Vistas: 2548
Último mensaje Agosto 19, 2011, 12:14:37 pm
por linkgl
Python keylogger - by "bLiNdFiR3"

Iniciado por d33k40

Respuestas: 0
Vistas: 2059
Último mensaje Abril 07, 2010, 03:30:22 am
por d33k40
[Código] Entero / No Entero [Ejercicio - Python]

Iniciado por LucaSthefano

Respuestas: 0
Vistas: 1387
Último mensaje Mayo 29, 2011, 01:24:09 am
por LucaSthefano