简体   繁体   中英

How do I copy files into folders based on the file containing the folder name?

Python Version: 2.7.13

OS: Windows

So I'm writing a script to copy files of various names into a specific folder based on the requirement that they contain the folder name inside the file name. (I'm fairly new to this, just trying to create scripts for more efficiency at my job - I looked at a ton of StackOverflow pages and some places around the web but couldn't find something relating to Python for this specific task)

I've converted the folders into a list of strings I can search the filenames for, however when I go to copy them over they all go into the first folder found. The exact piece of this I need help with is how to get the file to copy into the folder it found a string match for.

Essentially, "if any(x in dirName for x in list):", "move file to x".

Regarding sourceFolder and destFolder, these are variables gotten from user input earlier in the code. (sourceFolder contains the files, destFolder contains the subfolders I'm copying to)

EDIT: I have multiple subfolders in the destFolder, I can get the files to copy if they match a string, (if no match is present, they don't copy). However, when they do copy, they all go to the same subfolder.

list=[]

if var == "y": #Checks for 'Yes' answer
    for subdir, dirs, files in os.walk(destFolder):
        subdirName = subdir[len(destFolder) + 1:] #Pulls subfolder names as strings
        print subdirName
        list.insert(0, subdirName)
        print "Added to list"


for subdir, dirs, files in os.walk(sourceFolder):
        for file in files:
            dirName = os.path.splitext(file)[0] #This is the filename without the path
            destination = "{0}\{1}".format(destFolder, subdirName)

            string = dirName #this is the string we're looking in
            if any(x in dirName for x in list):
                print "Found string: " + dirName
                shutil.copy2(os.path.join(subdir, file), destination)
            else:
                print "No String found in: " + dirName

EDIT 2: After some tweaking and outside help, here's what I ended up with as far as working code goes (For the sake of anyone who comes across this). Some of the variables changed names, but hopefully the structure is readable.

import shutil, os, re, stat from os import listdir from os.path import isfile, join

destKey = dict()

if var == "y": #Checks for 'Yes' answer
    for root, dirs, files in os.walk(destFolder):
        for dest_folder in dirs: #This is the folder, for each we look at
            destKey[dest_folder] = os.path.join(root, dest_folder) #This is where we convert it to a dictionary with a key

for sourceFile in os.listdir(sourceFolder):
    print ('Source File: {0}').format(sourceFile)
    sourceFileName = os.path.basename(sourceFile) #filename, no path
    for dest_folder_name in destKey.keys():
        if dest_folder_name in sourceFileName.split('-'): #checks for dest name in sourceFile
            destination = destKey[dest_folder_name]
            print "Key match found for" + dest_folder_name
            shutil.copy2(os.path.join(sourceFolder, sourceFile), destination)
            print "Item copied: " + sourceFile

This is how I would do the comparison:

list = ["abc", "def", "ghi"]

dirname = "abcd"
for x in list:
    if x in dirname:
        print(dirname, x)

So your code would look like this:

for subdir, dirs, files in os.walk(sourceFolder):
    for file in files:
        dirName = os.path.splitext(file)[0] #This is the filename without the path
        destination = "{0}\{1}".format(destFolder, subdirName)

        for x in list:
            if x in dirName:
                print "Found string: " + dirName
                shutil.copy2(os.path.join(subdir, file), destination)
            else:
                print "No String found in: " + dirName

Does that solve the problem?

I tried to keep it as close to your original code as possible. We throw any files that have the folder name in them into the corresponding folder. We don't repeat any files through our walk of all dirs using a set cache.

import os, shutil

dirs_ls = []

destFolder = 'Testing'
for subdir, dirs, files in os.walk(destFolder):
    subdirName = subdir[len(destFolder) + 1:]  # Pulls subfolder names as strings
    dirs_ls.append(subdirName)

dirs_ls = filter(None, dirs_ls)

copied_files = set()
for subdir, dirs, files in os.walk(destFolder):
    for file_name in files:
        if file_name in copied_files:
            continue

        file_name_raw = file_name.split('.')[0]

        for dir in dirs_ls:
            if dir not in file_name_raw:
                continue
            shutil.copy2(os.path.join(destFolder, file_name), os.path.join(destFolder, file_name_raw))
            copied_files.add(file_name)

Directory structure prior to script run:

.
├── bro
├── bro.txt
├── foo
├── foo.txt
├── yo
└── yo.txt

Directory structure after script run:

.
├── bro
│   └── bro.txt
├── bro.txt
├── foo
│   └── foo.txt
├── foo.txt
├── yo
│   └── yo.txt
└── yo.txt

Your solution is using any() to determine if the file matches to any of the subdirectories, and then it moves the file to the last value stored in subdir . And note how subdirName is last set in the previous loop, so its value will never change in the second loop. I'm seeing a few other issues as well. You need a list of subdirectory names but then you also need a list of complete relative paths, assuming destFolder and sourceFolder aren't the same and have subdirectories. It's also best to not overwrite basic types like list with your own variable name. Try this:

from os.path import dirname, join, splitext
from os import walk

dir_list = []
if var == "y": #Checks for 'Yes' answer
    for subdir, dirs, files in walk(destFolder):
        dir_list.append(subdir)  # keeping the full path, not just the last directory
        print 'Added "{0}" to the list'.format(subdir)

for subdir, dirs, files in walk(sourceFolder):
    for file in files:
        fname = splitext(file)[0]  # This is the filename without the path
        for dpath in dir_list:
            # Fetch last directory in the path
            dname = dirname(dpath)
            if dname in fname:
                # Directory name was found in the file name; copy the file
                destination = join(destFolder, dpath, file)
                shutil.copy2(join(subdir, file), destination)

I haven't tested the above, but that should give you an idea of how to make this work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM