0

I have 500 zip files in a folder called Data from which I need to randomly select 5 files and copy those files to the subfolders. I have the folder structure as follows:

    Root_Folder  
    |__Data (contains 500 zip files)  
    |__Assign_Folder  
        |__One (subfolder)
            |__a1 (sub-subfolder)
            |__a2 (and so on)
        |__Two (subfolder)
            |__a1 (sub-subfolder)
            |__a2 (and so on)
    |__script.py
        

The Python script is located in the Root_Folder. I want to randomly select 5 zip files from the Data folder and recursively copy them in each of the a1, a2, a3, ... subfolders inside the One, Two, ... parent folders. So, in the end I want to have 5 zip files each copied into the a1, a2, ... folders inside the One, Two, ... parent folders. There are enough subfolders that the files can be easily copied.

I have written the following code:

import os
import random
import shutil

data_path = 'Data'
root_folder = 'Assign_Folder'

for folder, subs, files in os.walk(root_folder): 
    # select 5 random files
    filenames = random.sample(os.listdir(data_path), 5)

    for fname in filenames:
        srcpath = os.path.join(data_path, fname)
        shutil.copyfile(srcpath, folder)

This code is giving me an error IsADirectoryError: [Errno 21] Is a directory: 'Assign_Folder'

Please help me in correcting and completing this task. Thank you.

User.5678
  • 3
  • 1
  • You didn't provide the full error trace, so I'm guessing that the exception was raised by the last line of your script. `shutil.copyfile` takes as input two file paths. Here it seems to may that your second parameter is the directory path in which you want to copy the file. This means that you have to append to that directory path the name of the file. Something like: `shutil.copyfile(srcpath, os.path.join(folder, fname))`. – qouify Mar 14 '22 at 06:14
  • Also note that `os.walk` traverses all the directories in `Assign_Folder` which means that files will also be copied in directories `Assign_Folder`, `One` and `Two` and as far as I understand it's not what you want. – qouify Mar 14 '22 at 06:17
  • The full trace is: Traceback (most recent call last): File "/home/user/Documents/Root_Folder/copy_random_files.py", line 22, in shutil.copyfile(srcpath, folder) File "/home/user/opt/anaconda3/lib/python3.8/shutil.py", line 264, in copyfile with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst: IsADirectoryError: [Errno 21] Is a directory: 'Assign_Folder' – User.5678 Mar 14 '22 at 06:25
  • Yes you are correct. I do not wish to have any files in the Assign_Folder. – User.5678 Mar 14 '22 at 06:27
  • thanks, so yes the problem comes from `copyfile` – qouify Mar 14 '22 at 06:27
  • Yes. I have tried your suggestion: shutil.copyfile(srcpath, os.path.join(folder, fname)) It works correctly but it copies files to the Assign_Folder. This is the only problem that remains. – User.5678 Mar 14 '22 at 06:31
  • Look at this [Printing final (leaf?) nodes in directory listing Python](https://stackoverflow.com/questions/28146974/printing-final-leaf-nodes-in-directory-listing-python). You'll find a solution for `os.walk` to ignore directories which have sub-directories. – qouify Mar 14 '22 at 06:35
  • Thank you so much for your help. How do I accept your solution in Stackoverflow? I am new to this platform. – User.5678 Mar 14 '22 at 06:38
  • you're welcome. I submitted an answer that summarises the comments. You can accept it by clicking on the checkmark left to it. – qouify Mar 14 '22 at 06:45

1 Answers1

0

shutil.copyfile fails if the second argument is the directory in which you want to copy the file. So you have to append the destination file name to it.

Also, since you want to copy files only in the leaf directories of Assign_Folder, you have to ignore directories generated by os.walk that do have sub-directories. You can do that by checking the second element of tuples generated by os.walk (see Printing final (leaf?) nodes in directory listing Python).

With these two patches the code becomes:

import os
import random
import shutil

data_path = 'Data'
root_folder = 'Assign_Folder'

for folder, subs, files in os.walk(root_folder):
    if not subs:  #  ignore the directory if it does have sub-directories

        # select 5 random files
        filenames = random.sample(os.listdir(data_path), 5)

        for fname in filenames:
            srcpath = os.path.join(data_path, fname)
            dstpath = os.path.join(folder, fname)
            shutil.copyfile(srcpath, dstpath)
qouify
  • 3,698
  • 2
  • 15
  • 26