Python move files to sub-folders of single name

Asked

Viewed 118 times

0

good night!

on the study level, I am trying to create a script with the following rule:

what I’m trying to do is:

-inside the 'source' folder will have dozens of files.

-i need python to move the files that start with 'A', from 8 in 8 files to a single name subfolder within the destination.

-ie, take 8 files and put in a single sub-folder, then take 8 more and put in another sub-folder, so on,

-when the source folder has a quantity below 8, the process is finished.

I have been 2 days trying to do according to the code below.

I believe you’re missing something simple, but I can’t identify.

I’m grateful if someone can help me.

thank you!

import shutil, os, datetime

# para criar uma pasta de nome único, usei datetime.now
data = datetime.datetime.now()
folder_dist = data.strftime("%d""%H""%M""%S")

# pasta origem
origem = r'D:\origem'

# pasta destino
destino = r'D:\destino' + '\\' + folder_dist  # cria uma pasta de nome único

# muda para a pasta origem
os.chdir(origem)

# cria uma lista dos arquivos dentro da pasta origem
files = os.listdir(origem)

# cria uma lista filtrando os arquivos que começam com 'A'
files_a = [f for f in files if f.startswith('A')]

# quantidade de arquivos que quero mover da pasta origem
files_move = 8

# neste ponto preciso que o python mova de 8 em 8 arquivos para dentro de uma pasta única dentro do destino.
# se não houver ao menos 8 arquivos na pasta, o python termina o processo.
while len(files_a) >= 8:
    for file in files_a:
        os.makedirs(destino, exist_ok=True)
        shutil.move(file, destino)
        files_move -= 1
        if files_move == 0:  # sair do loop
            break
  • What mistake are you making? Well, you say that to make life easier for those who try to help.

  • hi Erick, good morning, yes I’m sorry :) the error is the following: the script makes the first break, all right, when will make the second break...gives an error speaking q file already exists.

2 answers

0

There are some problems with your code:

  • you create the variable files_a, a string list, once. Since the list size never changes during your code, the condition while len(files_a) >= 8: will either always be false (your loop never runs) or always true (your loop never ends). Note that the fact that you move files with shutil.move(file, ... does not cause the string file automatically exit from within the list.
  • similarly, you create the folder destino once, out of the loop. This means that shutil.move(..., destino) will always put the files in that same folder. This will not cause an error as the first remark, but it is a different behavior than you described.

To fix the first point, consider passing the filenames to shutil.move using the method pop lists, which "extracts" an element from the list at each call.

For the second point, just construct the variable destino inside the loop, just as you do now.

Following an example that does what you want:

import shutil, os, datetime

# pasta origem
origem = r'D:\origem'
# muda para a pasta origem
os.chdir(origem)
# cria uma lista dos arquivos dentro da pasta origem
files = os.listdir(origem)
# cria uma lista filtrando os arquivos que começam com 'A'
files_a = [f for f in files if f.startswith('A')]
# quantidade de arquivos que quero mover da pasta origem
files_move = 8

# a cada iteração, checa se há o número mínimo 
#  de arquivos começando por 'A' na pasta origem
while len(files_a) >= files_move:
    # nome único para pasta destino dos próximos arquivos
    data = datetime.datetime.now()
    folder_dist = data.strftime("%d""%H""%M""%S")
    destino = r'D:\destino' + '\\' + folder_dist
    # cria a pasta de destino
    os.makedirs(destino, exist_ok=True)
    # move N arquivos (N = variável files_move), 
    # removendo os nomes de dentro da lista files_a
    for _ in range(files_move): 
        file = files_a.pop() 
        shutil.move(file, destino)
  • good afternoon jfaccioni! you are the guy, you know a lot!! only one detail that didn’t work, it moves all the files to the new folder... what I would like is it to be moved only 8 at a time.. moves 8 and creates a sub-folder...moves 8 more to another sub-folder...so on. I will study your code. much fought!

  • Hi @hanspereira, I guess I didn’t understand your initial question correctly. Do you want to move 8 files every run of the program (runs once, moves 8, runs once again, moves 8 more, ...)? If that’s it, I believe that by changing the while by a if should work.

  • Hi @jfaccioni, thanks man! I was able to make it work, I don’t know if I used the right shape or if I did gambiara :)... but it worked, the only change I made in your code was to add "%f" within the date.strftime...was like this: data.strftime("%d""%H""%M""%S""%f")...adding the milliseconds works perfectly...I believe that before, without the milliseconds, since the python does everything very fast....

  • Ah understood, makes sense yes your amendment, and had not realized that this could be a problem heheh!

0

You need to "assemble" a different directory name for each group of files you want to copy. Using date and time as a single directory name can cause all files to be copied to the same destination in the same second.

Here’s a commented solution to your problem with a approach similar to your:

import shutil
import os

qtd = 8         # Quantidade de arquivos no bloco
origem = '/tmp' # Diretorio de origem

# Recupera lista de todos os arquivos iniciados
# por 'A' Contidos no diretorio de origem
arquivos = [f for f in os.listdir(origem) if f.startswith('A')]

# Divide lista de arquivos em sublistas (blocos)
# com o tamanho definido
blocos = [arquivos[i: i + qtd] for i in range(0, len(arquivos), qtd)]

# Para cada bloco de arquivos...
for i, bloco in enumerate(blocos, 1):

    # Monta caminho de destino dos arquivos contidos no bloco
    destino = os.path.join(origem, 'Destino' + str(i).zfill(4))

    # Cria diretorio de destino se ele nao existir
    os.makedirs(destino, exist_ok=True)

    # Para cada arqivo no bloco...
    for arquivo in bloco:

        # Exibe mensagem de status
        print(f"Movendo arquivo: {arquivo}' => '{destino}'")

        # Move o arquivo para o destino
        shutil.move(arquivo, destino)
  • Thanks @Lacobus, I’ll put your code into practice, thanks!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.