Cómo usar os.walk para listar solo archivos de texto

Esta pregunta fue similar al abordar los tipos de archivos ocultos. Estoy teniendo problemas con un problema similar porque necesito procesar solo el texto que contiene archivos en carpetas que tienen muchos tipos diferentes de archivos: imágenes, texto, música. Estoy utilizando os.walk, que enumera TODO, incluidos los archivos sin archivos de icono similares a una extensión. Estoy usando linux y me conformaría con filtrar solo los archivos txt. Una forma es también revisar la extensión del nombre del archivo y esta publicación explica muy bien cómo se hace.

Pero esto todavía deja archivos mal etiquetados o archivos sin una extensión. Hay valores hexadecimales que identifican de forma única los tipos de archivo conocidos como números mágicos o firmas de archivos. aquí y aquí Desafortunadamente, no existen números mágicos para los archivos de texto ( consulte aquí ).

Una de las estrategias que he encontrado es analizar el primer grupo de caracteres para asegurarse de que son palabras haciendo una búsqueda en el diccionario (solo estoy tratando con textos en inglés). El enfoque parece bastante pesado y costoso (hacer un montón de búsquedas de diccionario para cada archivo). Otro enfoque consiste simplemente en buscar la palabra “the” que es poco probable que sea frecuente en un archivo de datos, pero que se encuentra comúnmente en los archivos de texto. Pero los falsos negativos me harían perder archivos de texto para procesarlos. Intenté pedirle a google el texto más largo sin la palabra ‘the’ pero no tuve suerte con eso.

No sé si este es el foro adecuado para este tipo de pregunta, es casi una cuestión de IA en lugar de informática / encoding. No es tan difícil como la detección de galimatías. Es posible que los textos no sean correctos de manera semántica o sintáctica; pueden ser palabras como el inventario de un almacén, pero también pueden ser prosa y poesía. Es solo que no quiero procesar archivos que puedan ser código de bytes, código fuente o colecciones de caracteres alfanuméricos que no sean palabras en inglés.

    Puede usar la biblioteca de mimetypes de Python para verificar si un archivo es un archivo de texto plano.

     import os import mimetypes for dirpath, dirnames, filenames in os.walk('/path/to/directory'): for filename in filenames: if mimetypes.guess_type(filename)[0] == 'text/plain': print(os.path.join(dirpath, filename)) 

    ACTUALIZACIÓN : dado que la biblioteca de tipos mimetypes utiliza la extensión de archivo para determinar el tipo de archivo, no es muy confiable, especialmente porque mencionó que algunos archivos están mal etiquetados o sin extensiones.

    Para esos casos, puede usar la biblioteca magic (que desafortunadamente no está en la biblioteca estándar).

     import os import magic mime = magic.Magic(mime=True) for dirpath, dirnames, filenames in os.walk('/path/to/directory'): for filename in filenames: fullpath = os.path.join(dirpath, filename) if mime.from_file(fullpath) == 'text/plain': print(fullpath) 

    ACTUALIZACIÓN 2 : La solución anterior no detectaría archivos que de lo contrario consideraría “texto sin formato” (por ejemplo, archivos XML, archivos de origen, etc.). La siguiente solución debería funcionar en esos casos:

     import os import magic for dirpath, dirnames, filenames in os.walk('/path/to/directory'): for filename in filenames: fullpath = os.path.join(dirpath, filename) if 'text' in magic.from_file(fullpath): print(fullpath) 

    Déjame saber si alguno de estos te funciona.

    Una buena heurística es buscar bytes nulos al principio del archivo. Los archivos de texto no suelen tenerlos y los archivos binarios suelen tener muchos de ellos. A continuación se comprueba que los primeros 1K bytes no contienen nulos. Por supuesto, puede ajustar cuánto o poco del archivo para leer:

     #!python3 import os def textfiles(root): for path,dirs,files in os.walk(root): for file in files: fullname = os.path.join(path,file) with open(fullname,'rb') as f: data = f.read(1024) if not 0 in data: yield fullname for file in textfiles('.'): print(file)