web-dev-qa-db-fra.com

Python ajoute plusieurs fichiers dans un ordre donné à un gros fichier

J'ai jusqu'à 8 processus séparés Python processus créant des fichiers temporaires dans un dossier partagé. Ensuite, j'aimerais que le processus de contrôle ajoute tous les fichiers temporaires dans un certain ordre dans un seul gros fichier. moyen le plus rapide de le faire à un niveau Shell indépendant du système d'exploitation?

16
Martlark

En utilisant simplement un fichier IO:

# tempfiles is a list of file handles to your temp files. Order them however you like
f = open("bigfile.txt", "w")
for tempfile in tempfiles:
    f.write(tempfile.read())

C'est à peu près aussi indépendant du système d'exploitation que possible. C'est aussi assez simple, et les performances devraient être à peu près aussi bonnes que d'utiliser n'importe quoi d'autre.

29
Rafe Kettler

Je ne connais aucune commande au niveau du shell pour ajouter un fichier à un autre. Mais l'ajout au "niveau python" est suffisamment facile pour que je devine python n'ont pas jugé nécessaire de l'ajouter à la bibliothèque.

La solution dépend de la taille et de la structure des fichiers temporaires que vous ajoutez. S'ils sont tous suffisamment petits pour que cela ne vous dérange pas de les lire en mémoire, alors la réponse de Rafe Kettler (copiée de sa réponse et répétée ci-dessous) fait le travail avec le moins de code.

# tempfiles is an ordered list of temp files (open for reading)
f = open("bigfile.txt", "w")
for tempfile in tempfiles:
    f.write(tempfile.read())

Si la lecture complète des fichiers en mémoire n'est pas possible ou n'est pas une solution appropriée, vous voudrez parcourir chaque fichier et les lire par morceaux. Si votre fichier temporaire contient des lignes terminées par une nouvelle ligne qui peuvent être lues individuellement en mémoire, vous pouvez faire quelque chose comme ceci

# tempfiles is an ordered list of temp files (open for reading)
f = open("bigfile.txt", "w")
for tempfile in tempfiles:
    for line in tempfile
        f.write(line)

Alternativement - quelque chose qui fonctionnera toujours - vous pouvez choisir une taille de tampon et simplement lire le fichier par morceaux, par exemple.

# tempfiles is an ordered list of temp files (open for reading)
f = open("bigfile.txt", "w")
for tempfile in tempfiles:
    while True:
        data = tempfile.read(65536)
        if data:
            f.write(data)
        else:
            break

L'entrée/sortie tutoriel a beaucoup de bonnes informations.

8
CptJeanLuc

La réponse de Rafe manquait de déclarations d'ouverture/fermeture appropriées, par ex.

# tempfiles is a list of file handles to your temp files. Order them however you like
with open("bigfile.txt", "w") as fo:
     for tempfile in tempfiles:
          with open(tempfile,'r') as fi: fo.write(fi.read())

Cependant, sachez que si vous souhaitez trier le contenu du bigfile, cette méthode n'attrape pas les instances où la dernière ligne d'un ou plusieurs de vos fichiers temporaires a un format EOL différent, ce qui entraînera des résultats de tri étranges. Dans ce cas, vous voudrez supprimer les lignes du fichier temporaire au fur et à mesure que vous les lisez, puis écrire des lignes EOL cohérentes dans le bigfile (c'est-à-dire impliquant une ligne de code supplémentaire).

6
ksed
import os
str = os.listdir("./")

for i in str:
    f = open(i)
    f2 = open("temp.txt", "a")
    for line in f.readlines():
        f2.write(line)

Nous pouvons utiliser le code ci-dessus pour lire tout le contenu de tout le fichier présent dans le répertoire courant et stocker dans le fichier temp.txt.

3
Sumit Naik

Utilisez fileinput :

with open("bigfile.txt", "w") as big_file:
    with fileinput.input(files=tempfiles) as inputs:
        for line in inputs:
            big_file.write(line)

C'est plus efficace en mémoire que la réponse de @ RafeKettler car il n'a pas besoin de lire le fichier entier en mémoire avant d'écrire dans big_file.

1
Peter Wood

Essaye ça. C'est très rapide (beaucoup plus rapide que ligne par ligne, et ne devrait pas provoquer de VM thrash pour les gros fichiers), et devrait fonctionner sur n'importe quoi, y compris CPython 2.x, CPython 3 .x, Pypy, Pypy3 et Jython. De plus, il doit être très indépendant du système d'exploitation. De plus, il ne fait aucune hypothèse sur les encodages de fichiers.

#!/usr/local/cpython-3.4/bin/python3

'''Cat 3 files to one: example code'''

import os

def main():
    '''Main function'''
    input_filenames = ['a', 'b', 'c']

    block_size = 1024 * 1024

    if hasattr(os, 'O_BINARY'):
        o_binary = getattr(os, 'O_BINARY')
    else:
        o_binary = 0
    output_file = os.open('output-file', os.O_WRONLY | o_binary)
    for input_filename in input_filenames:
        input_file = os.open(input_filename, os.O_RDONLY | o_binary)
        while True:
            input_block = os.read(input_file, block_size)
            if not input_block:
                break
            os.write(output_file, input_block)
        os.close(input_file)
    os.close(output_file)

main()

Il y a une optimisation (non triviale) que j'ai laissée de côté: il vaut mieux ne rien supposer d'une bonne taille de bloc, en utilisant plutôt un tas de tailles aléatoires, et en reculant lentement la randomisation pour se concentrer sur les bonnes (parfois appelées "recuit simulé "). Mais c'est beaucoup plus de complexité pour peu de performances réelles.

Vous pouvez également faire en sorte que os.write garde une trace de sa valeur de retour et redémarre les écritures partielles, mais ce n'est vraiment nécessaire que si vous vous attendez à recevoir des signaux (non terminaux) * ix.

1
user1277476

Un moyen simple et efficace de copier des données de plusieurs fichiers vers un seul gros fichier, avant cela, vous devez renommer vos fichiers en (int), par exemple. 1,2,3,4 ... etc, Code:

#Rename Files First

import os

path = 'directory_name'
files = os.listdir(path)
i = 1
for file in files:
    os.rename(os.path.join(path, file), os.path.join(path, str(i)+'.txt'))

    i = i+1
# Code For Copying Data from Multiple files

import os

i = 1
while i<50:

    filename = i
    for filename in os.listdir("directory_name"):

        # %s is your filename # .txt is file extension 
        f = open("%s.txt" % i,'r') 
        fout = open("output_filename", "a")

    for line in f:
        fout.write(line)
    i += 1
0
Injamul Islam

Il y a aussi la classe fileinput dans Python 3, qui est parfaite pour ce genre de situation

0
MikeTheTall

Je me sens un peu stupide d'ajouter une autre réponse après 8 ans et tant de réponses, mais je suis arrivé ici par le titre "ajouter au fichier", et je n'ai pas vu la bonne solution pour ajouter à un fichier binaire existant avec une mémoire tampon en lecture/écriture .

Voici donc la manière de base de le faire:

def append_file_to_file(_from, _to):
    block_size = 1024*1024
    with open(_to, "ab") as outfile, open(_from, "rb") as infile:
        while True:
            input_block = infile.read(block_size)
            if not input_block:
                break
            outfile.write(input_block)

Compte tenu de ce bloc de construction, vous pouvez utiliser:

for filename in ['a.bin','b.bin','c.bin']:
    append_file_to_file(filename, 'outfile.bin')
0
ishahak

Dans ce code, vous pouvez indiquer le chemin et le nom des fichiers d'entrée/sortie, et il créera le gros fichier final dans ce chemin:

import os

dir_name = "Your_Desired_Folder/Goes_Here"    #path
input_files_names = ["File1.txt", "File2.txt", "File3.txt"]     #input files
file_name_out = "Big_File.txt"     #choose a name for the output file
file_output = os.path.join(dir_name, file_name_out)
fout = open(file_output, "w")

for tempfile in input_files_names:
    inputfile = os.path.join(dir_name, tempfile)
    fin = open(inputfile, 'r')
    for line in fin:
        fout.write(line)

fin.close()    
fout.close()
0
mah65