cómo leer una lista de archivos txt en una carpeta en python

Soy nuevo en Python, escribí un algoritmo para leer 10 archivos txt en una carpeta y luego escribo la primera línea de cada uno de ellos en un archivo outxt de txt. pero no funciona Quiero decir, después de ejecutarlo, no enfrentaré ningún error ni obtendré el archivo.

def MergePerFolder(path): path1=listdir_fullpath(path) for i in path1: infile=open(i) outfile=open('F:// merge1.txt', 'w') a=infile.readline().split('.') for k in range (len(a)): print(a[0], file=outfile, end='') infile.close() outfile.close print("done") 

NOTA: Escribo la (s) función (es) al final de mi respuesta, así que siéntase libre de saltar a eso, pero todavía quería leer el código parte por parte para una mejor comprensión.


Escenario de ejemplo que se utilizará para la explicación

Digamos que tiene 12 archivos en esta carpeta llamada test , 10 de los cuales son archivos .txt :

 .../ test/ 01.txt 02.txt 03.txt 04.txt 05.txt 06.txt 07.txt 08.txt 09.txt 10.txt random_file.py this_shouldnt_be_here.sh 

Con cada archivo .txt con su primera línea como su número correspondiente, como

  • 01.txt contiene la primera línea 01 ,
  • 02.txt contiene la primera línea 02 ,
  • etc …

Listar todos los archivos de texto en el directorio designado

Puede hacer esto de dos maneras:

Método 1: módulo os

Puede importar el módulo os y usar el método listdir para enumerar todos los archivos en ese directorio. Es importante tener en cuenta que todos los archivos de la lista serán nombres de archivo relativos:

 >>> import os >>> all_files = os.listdir("test/") # imagine you're one directory above test dir >>> print(all_files) # won't necessarily be sorted ['08.txt', '02.txt', '09.txt', '04.txt', '05.txt', '06.txt', '07.txt', '03.txt', '06.txt', '01.txt', 'this_shouldnt_be_here.sh', '10.txt', 'random_file.py'] 

Ahora, solo desea los archivos .txt , así que con un poco de progtwigción funcional utilizando la función de filter y las funciones anónimas, puede filtrarlos fácilmente sin usar el estándar for bucles:

 >>> txt_files = filter(lambda x: x[-4:] == '.txt', all_files) >>> print(txt_files) # only text files ['08.txt', '02.txt', '09.txt', '04.txt', '05.txt', '06.txt', '07.txt', '03.txt', '06.txt', '01.txt', '10.txt'] 

Método 2: módulo glob

De manera similar, puede usar el módulo glob y la función glob.glob para enumerar todos los archivos de texto en el directorio sin usar ninguna progtwigción funcional arriba. La única diferencia es que glob generará una lista con rutas de prefijo, sin embargo, la ingresó.

 >>> import glob >>> txt_files = glob.glob("test/*.txt") ['test/08.txt', 'test/02.txt', 'test/09.txt', 'test/04.txt', 'test/05.txt', 'test/06.txt', 'test/07.txt', 'test/03.txt', 'test/06.txt', 'test/01.txt', 'test/10.txt'] 

Lo que quiero decir con glob salida de la lista, sin embargo, usted ingresa la ruta relativa o completa; por ejemplo, si estuviera en el directorio de test y llamara glob.glob('./*.txt') , obtendría una lista como :

 >>> glob.glob('./*.txt') ['./08.txt', './02.txt', './09.txt', ... ] 

Por cierto, ./ significa en el mismo directorio. Alternativamente, simplemente no puede anteponer el ./ , pero las representaciones de cadena cambiarán en consecuencia:

 >>> glob.glob("*.txt") # already in directory containing the text files ['08.txt', '02.txt', '09.txt', ... ] 

Hacer algo con un archivo usando administradores de contexto de archivos.

Bien, ahora el problema con tu código es que estás abriendo estas conexiones a todos estos archivos sin cerrarlos. Generalmente, el procedimiento para hacer algo con un archivo en python es este:

 fd = open(filename, mode) fd.method # could be write(), read(), readline(), etc... fd.close() 

Ahora, el problema con esto es que si algo sale mal en la segunda línea en la que llama a un método en el archivo, el archivo nunca se cerrará y tendrá un gran problema.

Para evitar esto, usamos lo que llamamos administrador de contexto de archivos en Python usando la palabra clave with . Esto asegura que el archivo se cerrará con o sin fallos.

 with open(filename, mode) as fd: fd.method 

Leyendo la primera línea de un archivo con readline()

Como probablemente ya sepa, para extraer la primera línea de un archivo, simplemente tiene que abrirlo y llamar al método readline() . Queremos hacer esto con todos los archivos de texto listados en txt_files , pero sí, puede hacerlo con la función de map progtwigción funcional, excepto que esta vez no escribiremos una función anónima (para facilitar la lectura):

 >>> def read_first_line(file): ... with open(file, 'rt') as fd: ... first_line = fd.readline() ... return first_line ... >>> output_strings = map(read_first_line, txt_files) # apply read first line function all text files >>> print(output_strings) ['08\n', '02\n', '09\n', '04\n', '05\n', '06\n', '07\n', '03\n', '06\n', '01\n', '10\n'] 

Si desea ordenar la txt_files salida, ordene los txt_files antemano o ordene la lista de output_list sí. Ambas obras:

  • output_strings = map(read_first_line, sorted(txt_files))
  • output_strings = sorted(map(read_first_line, txt_files))

Concatene las cadenas de salida y escríbalas en un archivo de salida

Así que ahora tienes una lista de cadenas de salida, y lo último que quieres hacer es combinarlas:

 >>> output_content = "".join(sorted(output_strings)) # sort join the output strings without separators >>> output_content # as a string '01\n02\n03\n04\n05\n06\n07\n08\n09\n10\n' >>> print(output_content) # print as formatted 01 02 03 04 05 06 07 08 09 10 

¡Ahora solo es cuestión de escribir esta cadena gigante en un archivo de salida! Llamémoslo outfile.txt :

 >>> with open('outfile.txt', 'wt') as fd: ... fd.write(output_content) ... 

¡Entonces ya está! Estás todo listo! Vamos a confirmarlo:

 >>> with open('outfile.txt', 'rt') as fd: ... print fd.readlines() ... ['01\n', '02\n', '03\n', '04\n', '05\n', '06\n', '07\n', '08\n', '09\n', '10\n'] 

Todo lo anterior en una función.

glob módulo glob para que siempre sepa de qué directorio accederé a mis rutas sin la molestia de usar rutas absolutas con el módulo os y otras cosas.

 import glob def read_first_line(file): """Gets the first line from a file. Returns ------- str the first line text of the input file """ with open(file, 'rt') as fd: first_line = fd.readline() return first_line def merge_per_folder(folder_path, output_filename): """Merges first lines of text files in one folder, and writes combined lines into new output file Parameters ---------- folder_path : str String representation of the folder path containing the text files. output_filename : str Name of the output file the merged lines will be written to. """ # make sure there's a slash to the folder path folder_path += "" if folder_path[-1] == "/" else "/" # get all text files txt_files = glob.glob(folder_path + "*.txt") # get first lines; map to each text file (sorted) output_strings = map(read_first_line, sorted(txt_files)) output_content = "".join(output_strings) # write to file with open(folder_path + output_filename, 'wt') as outfile: outfile.write(output_content) 

Supongamos que tiene archivos en la ruta de la carpeta path = /home/username/foldername/

así que tiene todos los archivos en la carpeta de ruta, para leer todos los archivos en la carpeta debe usar os o `glob ‘para hacer eso.

 import os path = "/home/username/foldername/" savepath = "/home/username/newfolder/" for dir,subdir,files in os.walk(path): infile = open(path+files) outfile = open(savepath,'w') a = infile.readline().split('.') for k in range (0,len(a)): print(a[0], file=outfile, end='') infile.close() outfile.close print "done" 

O usando glob puedes hacerlo mucho menos líneas de código.

 import glob path = "/home/username/foldername/" savepath = "/home/username/newfolder/" for files in glob.glob(path +"*.txt"): infile = open(files) outfile = open(savepath,'w') a = infile.readline().split('.') for k in range (0,len(a)): print(a[0], file=outfile, end='') infile.close() outfile.close print "done" 

Espero que pueda funcionar para usted.

en este ejemplo, puede ser que deba cerrar el archivo en bucle porque está intentando abrir muchas veces sin cerrar el anterior