Есть вот такая задачка:
Написать программу на С++ выполняющую следующую задачу: допустим в текущей директории есть файлы a.txt (10 байт), 3.jpg(1000 байт), а также папка 1 с содержимым KISH.mp3 (4000 байт) то есть присутствуют вложенные папки с файлами
Программа должна создать директорию renamedFiles с содержимым:
// файлы упорядочены по размеру
Есть такое решение: проверяем есть ли папка с именем renamedFiles, удаляем ее со вложенными файлами и создаем новую, копируем туда файлы попутно сохраняя их путь и размеры, в общем все просто.
Вот далее проблемка. Есть два массива с размерами файлов, один отсортированный, другой исходный. Сравнивая отсортированный массив i с исходным, находим по j-тому элементу файл и переименовываем. Но данный метод не подходит для файлов одинаковых размеров. Быть может есть другой способ упорядочить файлы в папке? Может как-то по другому идентифицировать файлы (а не по размеру)? Исходный код прилагаю ниже. С библиотекой filesystem работаю впервые, поэтому готов выслушать замечания в целом по коду.
#include <algorithm>
#include <vector>
#include <iostream>
#include <filesystem>
#include <iomanip>
constexpr char NEWFOLDER[] = "renamedFiles";
constexpr int TAB = 60;
using namespace std;
namespace fs = std::experimental::filesystem;
string getFileName(const string& s)
{
char sep = '\\';
size_t i = s.rfind(sep, s.length());
if (i != string::npos)
{
return(s.substr(i + 1, s.length() - i));
}
return("");
}
int main()
{
setlocale(LC_ALL, "Rus");
error_code err;
vector<uintmax_t> fsize;
vector<uintmax_t> sort_fsize;
vector<fs::path> path_list;
fs::path currPath = fs::current_path();
fs::path newPath = currPath / NEWFOLDER;
cout << "\nCurrent directory: " << endl;
cout << currPath << endl << endl;
if (fs::exists(newPath))
{
fs::remove_all(newPath, err);
if (err)
{
cout << "Error: can't remove folder: " << NEWFOLDER;
return -1;
}
}
if (!fs::create_directory(newPath, err))
{
cout << "Error: can't create new folder: " << NEWFOLDER;
return -1;
}
cout << "Created new folder: " << NEWFOLDER << endl << endl;
cout << "Coping files..." << endl;
for (auto& entry : fs::recursive_directory_iterator(currPath))
{
if (!fs::is_directory(entry) && entry.path().parent_path() != newPath)
{
fs::path pathFile = newPath / entry.path().filename();
if (fs::copy_file(entry, pathFile, fs::copy_options::skip_existing))
{
cout << entry << endl;
path_list.push_back(pathFile);
fsize.push_back(fs::file_size(pathFile));
}
}
}
sort_fsize = fsize;
sort(sort_fsize.begin(), sort_fsize.end(), less<uintmax_t>());
cout << "\nSorted files in folder: " << NEWFOLDER << endl;
cout << setiosflags(ios::left) << setw(TAB) << "File:" << "Size:" << endl;
for (uintmax_t i = 0, count = 0; i < sort_fsize.size(); ++i)
{
for (uintmax_t j = 0; j < fsize.size(); ++j)
{
if (sort_fsize[i] == fsize[j])
{
string newFileName = to_string(++count) + '.' + getFileName(path_list[j].string());
fs::rename(newPath / path_list[j].filename(), newPath / newFileName, err);
cout << setw(TAB) << newFileName << sort_fsize[i] << " bytes" << endl;
}
}
}
return 0;
}
Для начала поясню, что по заданию нужно было скопировать все файлы из текущего каталога в новый с именем "renamedFiles" и приписать в именах файлов порядок, то есть пронумеровать их в порядке возрастания размера. Вот так новый каталог должен выглядеть:
В общем, решил проблему так. Как подсказали в комментариях, нужно было просто напросто хранить имена и размеры файлов в одном массиве (массив структур). Для удобства сделал конструктор.
struct file_struct {
fs::path fpath;
uintmax_t fsize;
file_struct(fs::path _fpath, uintmax_t _fsize) :
fpath(_fpath), fsize(_fsize) {}
};
Объявление в main:
vector<file_struct> list;
Чтобы заполнять вектор со структурой, необходимо каждый раз создавать эту структуру:
for (auto& entry : fs::recursive_directory_iterator(currPath))
{
if (!fs::is_directory(entry) && entry.path().parent_path() != newPath)
{
fs::path pathFile = newPath / entry.path().filename();
if (fs::copy_file(entry, pathFile, fs::copy_options::skip_existing))
{
file_struct currFile(pathFile, fs::file_size(pathFile)); //заполняются поля структуры
list.push_back(currFile); //заносится в массив
cout << entry.path() << endl;
}
}
}
Раз мы находимся в стандарте C++17, то для сортировки по некоторому полю структуры (размеру файла) грех не воспользоваться нововведением стандарта C++11, то есть лямбда-функцией в функции sort:
sort(list.begin(), list.end(),
[](const file_struct& l1, const file_struct& l2) -> bool
{
return l1.fsize < l2.fsize;
});
Осталось пронумеровать имена файлов:
for (size_t i = 0; i < list.size(); ++i)
{
string newFileName = to_string(i + 1) + '.' + getFileName(list[i].fpath.string());
fs::rename(newPath / list[i].fpath.filename(), newPath / newFileName, err);
cout << setw(TAB) << newFileName << list[i].fsize << " bytes" << endl;
}
Результат работы программы был приведён на изображении выше. По поводу комментариев об одинаковых файлов или файлов с одинаковыми именами, то такие файлы пропускаются если один из них уже окажется в новой директории на что указывает опция fs::copy_options::skip_existing, которая пропускает ошибки при копировании файла в строчке:
if (fs::copy_file(entry, pathFile, fs::copy_options::skip_existing))
Можно обработать данное исключение, но задание этого не требует.
Доработанный код привожу ниже. Всем спасибо за подсказки.
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <filesystem>
using namespace std;
namespace fs = std::filesystem;
constexpr char NEWFOLDER[] = "renamedFiles";
constexpr int TAB = 70;
struct file_struct {
fs::path fpath;
uintmax_t fsize;
file_struct(fs::path _fpath, uintmax_t _fsize) :
fpath(_fpath), fsize(_fsize) {}
};
string getFileName(const string& s)
{
char sep = '\\';
size_t i = s.rfind(sep, s.length());
if (i != string::npos) {
return(s.substr(i + 1, s.length() - i));
}
return("");
}
int main()
{
setlocale(LC_ALL, "Rus");
error_code err;
vector<file_struct> list;
fs::path currPath = fs::current_path();
fs::path newPath = currPath / NEWFOLDER;
cout << "\nCurrent directory: " << endl;
cout << currPath << endl << endl;
if (fs::exists(newPath))
{
cout << "Detected folder: " << NEWFOLDER << endl;
fs::remove_all(newPath, err);
if (err)
{
cout << "Error: can't remove folder: " << NEWFOLDER;
return -1;
}
else
{
cout << "Folder removed!" << endl;
}
}
if (!fs::create_directory(newPath, err))
{
cout << "Error: can't create new folder: " << NEWFOLDER;
return -1;
}
cout << "Created new folder: " << NEWFOLDER << endl << endl;
cout << "Coping files..." << endl;
for (auto& entry : fs::recursive_directory_iterator(currPath))
{
if (!fs::is_directory(entry) && entry.path().parent_path() != newPath)
{
fs::path pathFile = newPath / entry.path().filename();
if (fs::copy_file(entry, pathFile, fs::copy_options::skip_existing))
{
file_struct currFile(pathFile, fs::file_size(pathFile));
list.push_back(currFile);
cout << entry.path() << endl;
}
}
}
sort(list.begin(), list.end(),
[](const file_struct& l1, const file_struct& l2) -> bool
{
return l1.fsize < l2.fsize;
});
cout << "\nSorted files in folder: " << NEWFOLDER << endl;
cout << setiosflags(ios::left) << setw(TAB) << "File:" << "Size:" << endl;
for (size_t i = 0; i < list.size(); ++i)
{
string newFileName = to_string(i + 1) + '.' + getFileName(list[i].fpath.string());
fs::rename(newPath / list[i].fpath.filename(), newPath / newFileName, err);
cout << setw(TAB) << newFileName << list[i].fsize << " bytes" << endl;
}
return 0;
}
Виртуальный выделенный сервер (VDS) становится отличным выбором
Задача из универа: Для числа типа float при выводе на экран его битового представления указать знаковый бит, порядок и мантиссуЧисло вводят...
Пытаюсь открыть файл, который находится на диске С, но выдает ошибки
У меня есть два jar файла, один лежит в lib, соответственно все работаетЕсть ли способ засунуть все это добро в один exe файл ?!