Пишу микро прогу на плюсах и возникла проблема с выводом терминала
Пишу микро прогу на плюсах которая сортирует файлы по папкам и возникает проблема. После хоть 1 выполнения функции sort_files(std::string file) у меня в выводе терминала зацикленно появляется mv: cannot stat путь к файлу No such file or directory с чем это связано мне не ясно. Судя по всему проблема в функции check_files(). Если я задаю переменную std::string file глобальной(до функций) то в терминале ничего не появляется но при этом программа работает только 1 раз а не постоянно. (Все переменные написанные капсом это абсолютные пути к папкам, файлам либо команды терминалу перейти в папку)
void sort_file(std::string file)
{
if (file == ".pdf")
system(MOVE_BOOKS);
}
void check_files()
{
for (unsigned i = 0; i < files.size(); ++i)
for (unsigned j = 0; j < files[i].size(); ++j)
if(files[i][j] == '.')
{
std::string file;
for (unsigned l = j; l < files[i].size(); ++l)
file += files[i][l];
sort_file(file);
break;
}
}
void run()
{
std::string line;
system("ls " BASE "> .tmp");
std::ifstream tmp(".tmp");
if (tmp.is_open())
while(getline(tmp, line))
files.push_back(line);
tmp.close();
check_files();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
int main(int argc, char* argv[])
{
make_base_catalogs();
while(true)
{
run();
}
return 0;
}
Ответы (1 шт):
Без полного текста тяжело сказать что-то конкретно. Но пара замечаний есть - может поможет как-то.
- Вектор строк
filesзаполняется, но нигде не очищается. Вы добавляете в массив строк имена файлов из текущей директории. Либо вы работаете со всё время увеличивающимся массивом, в котором вероятно есть дубликаты. Либо возможно очищаете где-то в другом месте? Или не очищаете... И так делаете 1 раз в секунду. И тут может быть ошибка - в списке есть расширение.pdf, а файлов с таким расширением в папке нет. Вероятно поэтому у вас идет циклическиNo such file or directory, когда вызывается системная функция для перемещения файлов, которых в папке нет. Поэтому перед каждым заполнением массивfilesнужно очищать от старых значений.
void run()
{
std::string line;
// по идее вот здесь надо очистить массив files <-------------
// files.clear(); <-------------
system("ls " BASE "> .tmp"); // записали список файлов в файл
std::ifstream tmp(".tmp");
if (tmp.is_open())
while(getline(tmp, line))
files.push_back(line); // добавили имена файлов в массив
tmp.close();
check_files();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
Я так понимаю, вам этот список нужен только 1 раз, для проверки есть ли в папке определенные файлы.
Также происходит, если вы делаете глобальной переменную std::string file. Вы её не очищаете, и в ней появляется значение .pdf.pdf.pdf.pdf. А как раз с локальной переменной функция check_files() работает корректно, правда неоптимально.
2. Перебирая имена файлов в массиве files вы пытаетесь получить расширение файла. Но ищете первую точку в имени. А в имени файла может быть несколько точек. Вероятно нужно искать последнее вхождение точки в имя. Ну и проще делать это через функции поиска в строках.
void check_files()
{
for (unsigned i = 0; i < files.size(); ++i)
{
std::string::size_type n;
n = files[i].rfind('.');
if( n!= std::string::npos )
sort_file( files[i].substr(n) );
}
}
- Поскольку вам нужны расширения, лучше сразу при чтении строки из файла выделять расширение и записывать в
filesтолько его - место сэкономите. И скорость работы повысится, т.к. расширение влезает в "короткую" строку иstd::stringне выделяет память в куче. А если строка будет с путем (или имя файла длинное), то полное имя может и не влезть - тогдаstringвыделит память в куче, куда запишет строку. - Файлов с одинаковым расширением в папке может быть несколько. Вы несколько раз будете вызывать
sort_file(file)для одного и того же расширения. А если расширение".pdf", то несколько раз вызовете системную функциюsystem(MOVE_BOOKS);, хотя файлов там уже нет (после первого вызова вы их переместите). Т.е. вам нужен список расширений файлов без повторов. Для этого вместоstd::vector<>проще использоватьstd::set<>илиstd::unordered_set<>. И если вы реагируете только на 1 расширение, искать именно его поиском во множестве вместо перебора вектора в цикле. Да иsort_file()можно сразу вызывать.
std::set< std::string > files;
void run()
{
...
files.clear();
if (tmp.is_open())
while(getline(tmp, line))
{
std::string::size_type n;
n = line.rfind('.');
if( n!= std::string::npos )
files.insert(line.substr(n)); // добавили сразу расширение файлов в массив
}
auto search = files.find(".pdf");
if (search != files.end())
sort_file(*search);
...
}
Можно оптимизировать ещё сильнее - добавляете во множество расширения не всех файлов из списка, а только тех, с которыми будете дальше работать (".pdf"). А если оно одно такое - то вообще не делаете список, а сразу вызываете sort_file();