How to Dump Files in Individual Folders

How to Dump Files in Individual Folders

6 Comments on How to Dump Files in Individual Folders

Introduction
While installing the Boxee+ hack on my media center I found out that all my movies needed to be saved in individual folders of the same name. This needs to be done for Boxee+ and XBMC to display fanart. With thousands of files, this was going to be a huge manual task. After searching for a tool to complete this task I decided to make one.

Usage
folder_dump
-p : verify paths
-e : verify each file
-i : include hidden files
-d : don’t remove file extensions for folder names
-v : display each file name as completed
-h : help

Code

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <dirent.h>
#include <errno.h>
#include <vector>
#include <sys/stat.h>
#include <cstdio>

using namespace std;

int main(int argc, char *argv[])
{
    bool verify_path = false;
    bool verify_each = false;
    bool include_hidden = false;
    bool dont_remove_extension = false;
    bool verbose = false;
    string source_path = "";
    string destination_path = "";

    for(int i = 1; i <= argc-1; i++)
    {
        if(argv[i][0] == '-')
        {
            if(strcmp(argv[i], "-p") == 0) verify_path = true;
            if(strcmp(argv[i], "-e") == 0) verify_each = true;
            if(strcmp(argv[i], "-i") == 0) include_hidden = true;
            if(strcmp(argv[i], "-d") == 0) dont_remove_extension = true;
            if(strcmp(argv[i], "-v") == 0) verbose = true;
            if(strcmp(argv[i], "-h") == 0)
            {
                cout << "folder_dump <flags> <source path> <destination path>" << endl;
                cout << "-p : verify paths" << endl;
                cout << "-e : verify each file" << endl;
                cout << "-i : include hidden files" << endl;
                cout << "-d : don't remove file extensions for folder names" << endl;
                cout << "-v : display each file name as completed" << endl;
                cout << "-h : help" << endl;
                return 0;
            }
    }
    else
    {
        if(source_path.compare("") == 0)
            source_path = argv[i];
        else
            destination_path = argv[i];
        }
    }
    if(verify_path == true)
    {
        string cin_continue = "";
        cout << "source path : " << source_path << endl;
        cout << "destination path : " << destination_path << endl;
        cout << "continue [y/n] :";
        cin >> cin_continue;
        if(cin_continue.compare("y") !=0)
        {
            cout << "canceled" << endl;
            return 0;
        }
    }
    if(source_path.compare("") == 0)
    {
        cout << "error: source path was not provided : (try -h for help)" << endl;
        return -101;
    }
    if(destination_path.compare("") == 0)
    {
        cout << "error: destination path was not provided : (try -h for help)" << endl;
        return -102;
    }
    if(source_path[strlen(source_path.c_str()) - 1] != '/') source_path += "/";
    if(destination_path[strlen(destination_path.c_str()) - 1] != '/') destination_path += "/";

    // - - - - - - - - - - - -
    // DO THE WORK
    DIR *dp;
    struct dirent *dirp;
    if((dp = opendir(source_path.c_str())) == NULL)
    {
        cout << "error: (" << errno << ") opening " << source_path << endl;
        return errno;
    }
    while ((dirp = readdir(dp)) != NULL)
    {
        if(dirp->d_type == DT_REG)
        {
            if((dirp->d_name[0] == '.' && include_hidden == true) || dirp->d_name[0] != '.')
            {
                string folder_name = "";
                for(int i = 0; i <= strlen(dirp->d_name) - 1; i++)
                {
                    if(dirp->d_name[i] == '.' && i == 0) {} else folder_name += dirp->d_name[i];
                }
                if(dont_remove_extension == false)
                {
                    int pos = folder_name.find_last_of(".");
                    if(pos != string::npos) folder_name = folder_name.substr(0, pos);
                }
                string source_file = source_path + dirp->d_name;
                string new_folder = destination_path + folder_name;
                string destination_file = new_folder + "/" + dirp->d_name;

                bool skip = false;

                if(verify_each == true)
                {
                    string cin_process = "";
                    cout << "process: " << dirp->d_name << " [y/n]";
                    cin >> cin_process;
                    if(cin_process.compare("y") !=0) skip = true;
                }

                if(skip == false)
                {
                    try
                    {
                        mkdir(new_folder.c_str(), S_IRWXU | S_IROTH | S_IRGRP | S_IXOTH);
                    }
                    catch(...)
                    {
                        cout << "error: creating new folder. check the destination path is correct.";
                        cout << "source path : " << source_path << endl;
                        cout << "destination path : " << destination_path << endl;
                        cout << "current file : " << source_file << endl;
                        cout << "current destination : " << destination_file << endl;
                        return -103;
                    }
                    try
                    {
                        rename(source_file.c_str(), destination_file.c_str());
                    }
                    catch(...)
                    {
                        cout << "error: creating new folder. check the destination path is correct.";
                        cout << "source path : " << source_path << endl;
                        cout << "destination path : " << destination_path << endl;
                        cout << "current file : " << source_file << endl;
                        cout << "current destination : " << destination_file << endl;
                        return -104;
                    }
                    if(verbose == true)
                    {
                        cout << "moved : " << dirp->d_name << endl;
                    }
                }
            }
        }
    }
    closedir(dp);
    return 0;
}

Compiling the Code
Copy and save the code to a file with the name “main.cpp”. Open a terminal window and use cd to change to the directory of the file. Use the following command to compile the code to an executable.

g++ main.cpp -o folder_dump

About the author:

Bill Payne started working as a paid professional software developer at the young age of 12 years old developing simple games and other applications for pre-packaged computers. Bill has since developed software for many industries such as direct sales and the the stock market. Bill has now started sharing his many years of software development experience through a blog on the MPSHouse website and one on one lessons.

6 Comments

  1. daniel@mentalfossa.com  - 23 March , 2014 - 10:34 pm
    Reply /

    why not do something like…

    for i in *.* ; do mkdir “${i%.*}” ; mv “$i” “${i%.*}” ; done

    • bill  - 23 March , 2014 - 11:08 pm
      Reply /

      Binary vs Script?
      This binary processed over 4000 files over a CIFS mounted network drive in seconds. It is a tool that I will use more than once when friends drop media in my servers via VPN or locally. So spending 10 to 15 minutes writing some C++ code is no big deal. Also this has options for hidden, remove file extensions, verify path and each, etc.

      But thanks for the comment! :)

      • Liam  - 24 March , 2014 - 2:08 am
        Reply /

        Off the top of my head, without having tested, it seems to me that this operation, when performed against a network mounted file system, is more likely to be IO-bound than limited by the processing performance of the program itself regardless of whether the program is a script or a binary. Even were it found not to be so, it sounds like you only need to process those thousands (and “thousands” is only “many” if you are processing each one manually anyway) once and going forward will only process a few at a time.

        There are many ways to skin a cat. One’s personal preferences often overrule any practical consideration and rightly so. For me, the “human readability” of a script nearly always trumps the performance gain of a compiled program for this sort of task. For readability, I would have written the script with a little more verbosity, some error checking and perhaps some of the options included in the binary instead of writing a one-liner.

        I suspect Daniel meant for the one-liner to be typed at the command line rather than saved as a script (since re-usability was not mentioned in the initial spec), hence readability and additional features would be of lesser importance. The formidable capabilities offered by the GNU/linux utilities make it rare indeed that one “needs” to write a program like this in a compiled language rather than as a script. While the investment in learning the uses, features and options of the utilities will be no less than learning a “proper” programming language, the return on that investment, in my opinion, justifies it.

        • bill  - 24 March , 2014 - 11:32 am
          Reply /

          I really did not want to get into a binary vs script argument. This post was about sharing a proven and working binary that saves you the problem of the “human readability” issue so you get the performance gain as you put it.

          You are missing the point, it is not a script vs binary article. As you said there are many ways to skin a cat and I am a software developer, I find reading and writing code quite easy so spending a couple of extra minutes to create a C++ binary is not a problem.

          Thanks for taking to time to share your thoughts.

  2. Mark Ribbson  - 27 February , 2015 - 4:51 am
    Reply /

    you are amazing this is a perfect code

    thank you

    • Bill  - 1 July , 2015 - 11:05 am
      Reply /

      I am glad you found it useful, you are welcome.

Leave a comment

Back to Top