【问题标题】:Creating Folders and Moving Files创建文件夹和移动文件
【发布时间】:2022-01-19 21:47:16
【问题描述】:

我想编写一个程序来读取给定目录中的文件,为文件的扩展名创建文件夹,然后将文件移动到新文件夹中。

我对 C++ 还很陌生,因为我之前所做的只是玩弄诸如方法和类之类的小东西,所以我真的不知道出了什么问题。

程序第一次在文件夹上运行时,它会正确创建所需的文件夹,但不会移动文件。

第二次运行时,没有任何变化,但它在当前文件夹的原始目录中创建了一组嵌套文件夹。我的意思是,如果文件夹目录是A:/b/c/d/,它开始创建b 的文件夹。我已经尝试在另一个文件夹上进行测试,它确实正确地制作了文件夹,但没有移动文件。

我添加了 cmets 以防代码难以阅读。我特意将制作文件夹和移动文件的逻辑设置为单独的方法,以便于编辑。我应该注意,即使文件没有被移动,rename 函数确实返回 0,表明它被移动了。

至于库,我计划在一切正常后清理它们。

/*
 main.cpp
 File Creator and Sorter
 
 Made in almost 24 hours
 First personal c++ project
 
 This program takes an input from the user in the form of /Users/.../.../.../... , ... being a folder location.
 It then goes through the files in the folder, finds any extensions, creates folders for those extensions, and moves the files there.
 There is a chance for a few files to be located in the folder that don't have a file type. For those files I plan to implement a
 miscallaneos folder and move them there. Do not use this program unless you confirmed you want to sort everything in the folder.
 The reason being this will not leave any file alone and can mess up and set ups.
 

 Created by yared yohannes on 12/15/21.
*/
// libraries idk what is needed and not so needs to be cleaned up

#include <dirent.h>
#include <cstdio>
#include <fstream>
#include <iostream>

// namespaces dont mess with cause filesystem was giving problems, im new.
using namespace std;
namespace fs = filesystem;

// turns the files in the string array into an extension section, and if it is
// not an extension(from noticing the .) removes it. the reason for the removing
// of unknown files is cause create_directory has an error on weird filenames.

void extension(string files[]) {
    int size = 0;

    while (files[size] != "") {
        size++;
    }

    for (int i = 0; i <= size; i++) {
        long position = files[i].find_last_of(".");
        files[i] = files[i].substr(position + 1);

        long position2 = files[i].find_last_of("/");
        if (position2 >= 44073709551615) {
            files[i] = "";
        }
    }
}

// Removes any repeated extensions(can be used on repeating string array, just
// called it extensions cause thats what I use it for). Also realigns the values
// in the string array so that all the values are at the front to save time
// later on.

void noRepeats(string file[]) {
    int size = 0;

    while (file[size] != "") {
        size++;
    }

    for (int i = 0; i <= size; i++) {
        for (int k = i + 1; k <= size + 1; k++) {
            if (file[i] == file[k]) {
                file[k] = "";
            }
        }
    }

    for (int i = 0; i <= size; i++) {
        for (int k = i + 1; k <= size + 1; k++) {
            if (file[i] == "") {
                if (file[k] != "") {
                    file[i] = file[k];
                    file[k] = "";
                }
            }
        }
    }
}

// gets the path of the files location. Mainly did this so I can automate the
// process in a method for cleaner main code. returns path.

string getPath(string files[]) {
    string holder = files[0];
    string path = "";

    long position = holder.find_last_of("/");

    path += files[0].substr(0, position + 1);

    return path;
}

// creates folders from string array of extensions from the first 2 methods and
// uses the path method to properly create the folders;

void makeFolders(string path, string extensions[]) {
    int size = 0;

    while (extensions[size] != "") {
        size++;
    }

    for (int i = 0; i <= size; i++) {
        if (extensions[i] != "DS_Store") {
            string folderName = path;

            folderName += extensions[i];
            folderName += "/";

            fs::create_directories(folderName);
        }
    }
}

// needs to be fixed cause not all files are moved?

// moves the files in the files array of the main into the folders created using
// the extensions array.

void moveFiles(string file[], string extensions[], string path) {
    int size = 0;

    while (file[size] != "") {
        size++;
    }

    int size2 = 0;

    while (extensions[size] != "") {
        size2++;
    }

    for (int i = 0; i <= size; i++) {
        long position = file[i].find_last_of(".");
        string fileType = file[i].substr(position + 1);

        for (int k = 0; k <= size2; k++) {
            if (fileType == extensions[k]) {
                string folderName = path;
                folderName += extensions[k];
                folderName += "/";
                
                long position2 = file[i].find_last_of("/");
                folderName += file[i].substr(position2 + 1);

                const char *oldName = file[i].c_str();
                const char *newName = folderName.c_str();

                if (rename(oldName, newName) != 0) {
                    cout << file[i] << "Could not be moved." << endl;
                }
            }
        }
    }
}

// main method, requests folder location, scans files, creates extension array,
// fixes extensions, makes folders, then moves files.

int main() {
    string files[1000];
    int arSpot = 0;
    const size_t path_max = 256;
    char dirname[path_max];

    cout << "What is the name of the folder: ";

    cin >> dirname;

    DIR *d = opendir(dirname);

    if (!d) {
        cout << "ERROR: Please provide a valid directory path.\n";
    } else {
        string path = dirname;

        for (const auto &entry : fs::directory_iterator(path)) {
            files[arSpot] = entry.path();
            arSpot++;
        }
    }

    string path = getPath(files);

    string exten[1000];

    int y = 0;

    while (files[y] != "") {
        exten[y] = files[y];
        y++;
    }

    extension(exten);
    noRepeats(exten);
    makeFolders(path, exten);
    moveFiles(files, exten, path);
    cout << endl;

    return 0;
}

【问题讨论】:

  • 当你包含&lt;filesystem&gt;时,你从&lt;dirent.h&gt;使用什么?
  • @TedLyngmo 老实说 idk,我浏览了许多图书馆尝试新的方法,什么都没有。我正确地忘记了删除它或不知道它的用途。我害怕删除它以防万一需要它。
  • @TedLyngmo 哦,顺便说一句,我尝试将两者都删除。我使用的是dirent.h而不是文件系统。生病更新问题代码
  • 首选使用 C++ 标准 &lt;filesystem&gt; 来遍历目录树,这样就不需要特定于平台的 &lt;dirent.h&gt;。注意事项:您似乎在路径方面做了很多工作。看看std::filesystem::path 能做什么。它可以为您提供扩展名,甚至路径中的各个目录。您可以使用a_path / "some_dir" / ... 连接路径。真的很方便。
  • 我会检查它,一旦我理解它,我就会将直接代码切换到文件系统。感谢您的提示。

标签: c++ arrays file directory


【解决方案1】:

extension()noRepeats()makeFolders()moveFiles() 中的 for 循环都超出了各自输入数组的范围。数组是 0 索引的,它们的有效索引仅为 [0..size-1]。在遍历数组时,您需要使用 &lt; size 而不是 &lt;= size

就此而言,调用者应该传入必要的size 作为输入参数,函数不应该计算它。在main() 中,您知道files[] 数组(arSpot) 和exten[] 数组(y) 的确切大小,因此将这些值传递给extension()noRepeats()makeFolders()moveFiles().

更好的是,根本不要使用原始数组。请改用std::vector,这是一个知道自己大小的动态数组。当您使用它时,您可以将整个 noRepeats() 函数替换为 std::set,它维护一个唯一值的排序列表。

另外,不要将long 用于字符串索引,而应使用string::size_typestd::size_t(甚至auto,让编译器决定)。

另外,if (position2 &gt;= 44073709551615) 到底在寻找什么?您在调用 string::find_last_of() 后立即执行此操作,因此您应该将结果与 string::npos 进行比较。

关于其余的逻辑:

  • 您没有处理使用\ 而不是/ 作为路径分隔符的文件夹路径。

  • extension() 没有考虑到没有扩展名的文件位于路径中带有点的文件夹中的可能性。

  • main() 不考虑包含空格的文件夹路径。

话虽如此,既然您已经知道&lt;filesystem&gt; 库,您应该让它为您完成所有艰苦的工作,例如:

#include <iostream>
#include <filesystem>
#include <vector>
#include <string>
#include <set>

using namespace std;
namespace fs = filesystem;

string getFileType(const fs::path &file) {
    string ext = file.extension();
    if (ext.size() > 1)
        return ext.substr(1);
    return "miscellaneous";
}

void makeFolders(const fs::path &folder, const set<string> &fileTypes) {
    for (const auto &fileType : fileTypes) {
        if (fileType != "DS_Store") {
            fs::path newFolder = folder / fileType;
            error_code ec;
            fs::create_directories(newFolder, ec);
            if (ec) {
                cerr << newFolder << " Could not be created." << endl;
            }
        }
    }
}

void moveFiles(const vector<fs::path> &files, const fs::path &folder) {
    for (const auto &file : files) {
        error_code ec;
        fs::rename(file, folder / getFileType(file) / file.filename(), ec);
        if (ec) {
            cerr << file << " Could not be moved." << endl;
        }
    }
}

int main()
{
    cout << "What is the path of the folder: ";

    string dirPath;
    getline(cin, dirPath);

    error_code ec;
    fs::directory_iterator dir(dirPath, ec);        
    if (ec)
    {
        cerr << "ERROR: Invalid directory path." << endl;
    }
    else
    {
        vector<fs::path> files;
        set<string> fileTypes;

        for (const auto &entry : dir) {
            fs::path file = entry.path();
            files.push_back(file);
            fileTypes.insert(getFileType(file));
        }

        makeFolders(dirPath, fileTypes);
        moveFiles(files, dirPath);
    }

    return 0;
}

【讨论】:

  • 谢谢你,我的家伙,必须弄清楚如何有效地实现向量和路径类。至于 if(position2>44073709551615,它适用于任何没有扩展名的文件。我在得到它的位置后计算了它的值,这是一个令人难以置信的高数字,所以我只是确保不包含高价值的文件。它出人意料地奏效了。再次感谢兄弟。
  • @Yaredyy per string::find_last_of():“返回值:找到的字符的位置npos,如果没有找到这样的字符”而根据string::npos: "虽然定义使用-1,size_type 是一个无符号整数类型,并且npos 的值是它可以容纳的最大正值,由于有符号到无符号隐式转换。这是一种指定任何无符号类型的最大值的可移植方式。"
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-26
  • 1970-01-01
  • 1970-01-01
  • 2021-03-14
  • 1970-01-01
  • 1970-01-01
  • 2013-01-09
相关资源
最近更新 更多