Работа с файлами С++ (...)

Модератор: Модераторы разделов

Аватара пользователя
MUTOgen
Сообщения: 343
Статус: i like the way you move
ОС: OpenSuse 11.1

Работа с файлами С++

Сообщение MUTOgen »

Какими средствами можно выяснить расширение файла если я работаю с библиотекой dirent.h (читаю директорию и меняю мена файлов с расширением jpg)?
Спасибо сказали:
Аватара пользователя
nesk
Сообщения: 2268
Статус: Линукссаксовец
ОС: MS Windows XP Home SP3

Re: Работа с файлами С++

Сообщение nesk »

расширение - это просто часть имени файла
анализируйте d_name, если эта строка заканчивается на .jpg , то наверно это то, что Вам надо
Внимание: У меня под рукой нет машины с Linux. Я не использую эту ОС. Ответы я даю либо по памяти, либо мне помогает гугл. Тщательно читайте маны по тем командам и конфигурационным файлам, которые я упоминаю.

0xDEFEC8ED
Спасибо сказали:
Аватара пользователя
MUTOgen
Сообщения: 343
Статус: i like the way you move
ОС: OpenSuse 11.1

Re: Работа с файлами С++

Сообщение MUTOgen »

я немного неправильно задал вопрос... надо шире... какими средствами можно изменять имена файлов в директориях основываясь на возможностях С/С++ (библиотеки, функции и т.д.)
Спасибо сказали:
Аватара пользователя
MUTOgen
Сообщения: 343
Статус: i like the way you move
ОС: OpenSuse 11.1

Re: Работа с файлами С++

Сообщение MUTOgen »

все, проблему решил с помошью функции rename.
Спасибо сказали:
Аватара пользователя
MUTOgen
Сообщения: 343
Статус: i like the way you move
ОС: OpenSuse 11.1

Re: Работа с файлами С++

Сообщение MUTOgen »

возникла проблема с функцией rename. вот есть код на С:

Код:

#include <stdio.h> #include <dirent.h> #include <stdlib.h> void listF (const char* dir_name,int x,int y){ DIR* dir; char str[20],str_min[20];int i; i=x; struct dirent* dir_ent; if((dir = opendir(dir_name)) == NULL){printf("error");return;} dir_ent=readdir(dir); while(dir_ent!= NULL && i<=y ){ if(dir_ent->d_name[(dir_ent->d_namlen)-1]=='g'){ itoa(i,str_min,10); strcpy(str,str_min); strcat(str,".jpg"); //printf("%s %s\n",str,dir_ent->d_name); rename(dir_ent->d_name,str); i++; } dir_ent=readdir(dir); } closedir(dir); } int main(){ listF(".",1,14); return 0; }


нужно чтобы в текущей директории все файлы с расширением .jpg переименовались с x по y (т.е. например от 5.jpg до 10.jpg, в коде взято от 1 до 14). Так вот, если для одной директории эта прога выполнилась, то второй раз файлы не переименовываются в ней, например если добавляю еще файлов. Может я не правильно использую какие-то функции?
Спасибо сказали:
Аватара пользователя
MUTOgen
Сообщения: 343
Статус: i like the way you move
ОС: OpenSuse 11.1

Re: Работа с файлами С++

Сообщение MUTOgen »

Код:

#include <stdio.h> #include <dirent.h> #include <stdlib.h> #include <string.h> void listF (const char* dir_name,int x,int y){ DIR* dir; char str[20],str_min[20];int i; i=x; struct dirent* dir_ent; if((dir = opendir(dir_name)) == NULL){printf("error");return;} dir_ent=readdir(dir); while(dir_ent!= NULL && i<=y ){ if(dir_ent->d_name[(dir_ent->d_namlen)-1]=='g'){ itoa(i,str_min,10); strcpy(str,str_min); strcat(str,".jpg"); rename(dir_ent->d_name,str); i++; } dir_ent=readdir(dir); } closedir(dir); } int main(){ listF(".",1,14); return 0; }


Исправил опечатки. Поэксперементировал и обнаружил вот что. Проблема стала более конкретна. Работал с каталогом состоящим из 14-ти jpg файлов которые первоначально называются f1.jpg, f2.jpg, f3.fpg ... f14.jpg. Запускаю прогу поставив заместо строки listF(".",1,14) -- listF(".",2,15), т.е. сдвинул нумирацию на единицу. Все отлично переименовано. Далее возвращаю строку listF(".",1,14) и вновь запускаю прогу там же. Вот тут глюк.
Вместо того чтобы переделать на нумирацию от 1 до 14 получаю вот такой например ряд: 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15. Т.е. где-то в середине совершенно случайным образом (не обязательно пятерка) выпадает цифра. Код вроде бы железный и идет по счетчику... где там может теряться значение? :unsure:
Спасибо сказали:
Аватара пользователя
Rootlexx
Бывший модератор
Сообщения: 4471
Статус: GNU generation
ОС: Debian GNU/Linux

Re: Работа с файлами С++

Сообщение Rootlexx »

MUTOgen
В вашей программе readdir() читает не статичную папку. После каждого прочтения следующего элемента файл условно переименовывается, при этом, разумеется, содержимое папки меняется. Как будет себя вести readdir() в такой ситуации, чётко не определено. В зависимости от реализации, она может в конце концов прочесть элемент, соответствующий уже переименованному файлу, что приведёт к описанной коллизии (в вашем примере уже переименованный файл 5 снова переименовывается), причём неизвестно, когда это наступит. А может, readdir() в один прекрасный момент вернёт NULL, что приведёт к слишком раннему завершению программы.
Для выяснения причин я бы посоветовал включить в код вывод отладочной информации, такой как: значение errno, имя текущего файла, новое имя файла, значение счётчика.
Что касается правильного написания программы, лучше сначала прочитать все необходимые элементы, занести их в, скажем, список, а далее уже переименовывать.
Спасибо сказали:
Аватара пользователя
Atragor
Сообщения: 681
Статус: ...

Re: Работа с файлами С++

Сообщение Atragor »

Добавляем в цикл

Код: Выделить всё

printf("Renamed %s to %s\n", dir_ent->d_name, str);

Делаем 14 файлов f1.jpg-f14.jpg.
Запускаем:

Код: Выделить всё

Renamed f6.jpg to 2.jpg
Renamed f8.jpg to 3.jpg
Renamed f2.jpg to 4.jpg
Renamed f12.jpg to 5.jpg
Renamed f7.jpg to 6.jpg
Renamed f14.jpg to 7.jpg
Renamed f9.jpg to 8.jpg
Renamed f11.jpg to 9.jpg
Renamed f3.jpg to 10.jpg
Renamed f4.jpg to 11.jpg
Renamed f1.jpg to 12.jpg
Renamed f5.jpg to 13.jpg
Renamed f13.jpg to 14.jpg
Renamed f10.jpg to 15.jpg

После этого все файлы на месте. Теперь меняем 2,15 на 1,14 и запускаем еще раз:

Код: Выделить всё

Renamed 13.jpg to 1.jpg   // все хорошо
Renamed 14.jpg to 2.jpg   // 2.jpg больше нет с нами :)
Renamed 12.jpg to 3.jpg   // 3.jpg больше нет
Renamed 6.jpg to 4.jpg     // 4.jpg больше нет
Renamed 11.jpg to 5.jpg   // 5.jpg больше нет
Renamed 3.jpg to 6.jpg     // все хорошо
Renamed 5.jpg to 7.jpg     // 7.jpg больше нет
Renamed 15.jpg to 8.jpg   // 8.jpg больше нет
Renamed 7.jpg to 9.jpg     // 9.jpg больше нет
Renamed 4.jpg to 10.jpg   // 10.jpg больше нет
Renamed 2.jpg to 11.jpg   // все хорошо
Renamed 10.jpg to 12.jpg // все хорошо
Renamed 9.jpg to 13.jpg   // все хорошо
Renamed 8.jpg to 14.jpg   // все хорошо

8 файлов затерлись, 6 осталось.

Код: Выделить всё

$ls -l *.jpg | wc -l
6

Вывод - надо писать выходные файлы в отдельную папку, или генерировать другие имена.

ЗЫ Ну вот, пока писал, Rootlexx уже все объяснил :)
If you were MEANT to understand it, we wouldn't have called it 'code' © bash.org
Спасибо сказали:
Аватара пользователя
MUTOgen
Сообщения: 343
Статус: i like the way you move
ОС: OpenSuse 11.1

Re: Работа с файлами С++

Сообщение MUTOgen »

господа, не угостите может быть какой-нибудь ссылкой по теме работы с директориями?
Спасибо сказали:
Аватара пользователя
MUTOgen
Сообщения: 343
Статус: i like the way you move
ОС: OpenSuse 11.1

Re: Работа с файлами С++

Сообщение MUTOgen »

пробывал переделать вышеизложенный код в списки, но эффект тот же. писать в другую директорию не вариант.

раз уж чтение происходит статически то решил переделать вот как:

Код:

#include <stdio.h> #include <dirent.h> #include <string.h> #include <stdlib.h> int listF (const char* dir_name){ DIR* dir; char str[20],*t; struct dirent* dir_ent; if((dir = opendir(dir_name)) == NULL){printf("error");return 1;} dir_ent=readdir(dir); dir_ent=readdir(dir); while(dir_ent!= NULL){ if(dir_ent->d_name[(dir_ent->d_namlen)-1]=='3'){ t=strchr(dir_ent->d_name,' '); strcpy(str,t+1); printf("%s|%s\n",str,dir_ent->d_name); rename(dir_ent->d_name,str); closedir(dir); return 0; } dir_ent=readdir(dir); } closedir(dir); return 1; } int main(){ int n=0; while(n==0){ printf("!!\n"); n=listF("."); } return 0; }

()
Программа немного поменялась. Теперь она удаляет первые 4 символа из имени файлов с расширением .mp3 (проверка не жесткая, только на символ '3', т.к. в директории гарантировано будут только эти файлы). Так вот. По идее функция listF теперь изменив одну запись, завершается и возвращает 0. Если возвращает не 0, а 1, то значит требуемых файлов не осталось и из while мы выйдем. По идее при такой структуре не readdir не натолкнется на изменение списка имен файлов, а просто на этом же шаге функция завершится и далее заново откроется поток для чтения в следующем запуске функции listF. Т.е. насколько я понимаю, глючить не должно по той причине по которой глючило до этого. Но все же оно глючит... В частности есть странный глюк: при запуске проги она изменив один файл вылетает, а если запустить ее повторно то изменяется все остальные файлы.... причем в любом случае сделав дело, она завершается ошибкой... Что в ней не так? :unsure:
Спасибо сказали:
Аватара пользователя
Rootlexx
Бывший модератор
Сообщения: 4471
Статус: GNU generation
ОС: Debian GNU/Linux

Re: Работа с файлами С++

Сообщение Rootlexx »

MUTOgen
Смущают строки:
t=strchr(dir_ent->d_name,' ');
strcpy(str,t+1);
printf("%s|%s\n",str,dir_ent->d_name);

А что будет, если в имени файла не будет пробела? strchr вернёт NULL, и в третьей из приведённых строк будет обращение к памяти по адресу 0x1, что, разумеется, приведёт к ошибке сегментирования. Если же пробел даже есть, то после переименования программа, второй раз проходя папку, наткнётся-таки на переименованный файл без пробела в имени.
Кроме того, неясно, зачем в начале вы 2 раза вызываете:

Код: Выделить всё

dir_ent=readdir(dir);

Хотите пропустить элементы «.» и «..»? А кто сказал, что они обязательно будут первыми? Да и не нужно это, учитывая проверку, выполняющуюся в:

Код: Выделить всё

if(dir_ent->d_name[(dir_ent->d_namlen)-1]=='3')

На самом деле, многократно открывать и закрывать поток не нужно, есть же функция rewinddir().
Спасибо сказали:
Аватара пользователя
MUTOgen
Сообщения: 343
Статус: i like the way you move
ОС: OpenSuse 11.1

Re: Работа с файлами С++

Сообщение MUTOgen »

Rootlexx писал(а):
03.08.2008 18:26
MUTOgen
Смущают строки:
t=strchr(dir_ent->d_name,' ');
strcpy(str,t+1);
printf("%s|%s\n",str,dir_ent->d_name);

А что будет, если в имени файла не будет пробела? strchr вернёт NULL, и в третьей из приведённых строк будет обращение к памяти по адресу 0x1, что, разумеется, приведёт к ошибке сегментирования. Если же пробел даже есть, то после переименования программа, второй раз проходя папку, наткнётся-таки на переименованный файл без пробела в имени.
Кроме того, неясно, зачем в начале вы 2 раза вызываете:

Код: Выделить всё

dir_ent=readdir(dir);

Хотите пропустить элементы «.» и «..»? А кто сказал, что они обязательно будут первыми? Да и не нужно это, учитывая проверку, выполняющуюся в:

Код: Выделить всё

if(dir_ent->d_name[(dir_ent->d_namlen)-1]=='3')

На самом деле, многократно открывать и закрывать поток не нужно, есть же функция rewinddir().

спасибо за анализ, я понял ошибку. а насчет пробела - он будет обязательно. это программа из разряда "мне влом", она переименовывает большое количество mp3 файлов в папке которые некрасиво начинаются с "001 " "002 " и так далее. по поводу rewinddir(), упустил ее из виду когда разбирался с работой в директориях. непременно вернусь к ней.
Спасибо сказали:
Аватара пользователя
uptime
Сообщения: 1661
Статус: Drinker with computing problems
ОС: kubuntu 8.04

Re: Работа с файлами С++

Сообщение uptime »

MUTOgen писал(а):
03.08.2008 15:37
пробывал переделать вышеизложенный код в списки, но эффект тот же. писать в другую директорию не вариант.
...


с новой (временной) директорией вариант хороший:
1) создаём копии с новыми именами во временной директории
2) убиваем старые файлы
3) переносим новые файлы в старую директорию
4) удаляем временную директорию

успехов
The answer, my friend, is blowin' in the wind.
The answer is blowin' in the wind.
Спасибо сказали:
Аватара пользователя
MUTOgen
Сообщения: 343
Статус: i like the way you move
ОС: OpenSuse 11.1

Re: Работа с файлами С++

Сообщение MUTOgen »

uptime писал(а):
03.08.2008 18:50
MUTOgen писал(а):
03.08.2008 15:37
пробывал переделать вышеизложенный код в списки, но эффект тот же. писать в другую директорию не вариант.
...


с новой (временной) директорией вариант хороший:
1) создаём копии с новыми именами во временной директории
2) убиваем старые файлы
3) переносим новые файлы в старую директорию
4) удаляем временную директорию

успехов

попробую пожалуй... если есть хорошие ссылки на описание функций - поделитесь, буду рад :)
Спасибо сказали:
Galaxy Master
Сообщения: 142
ОС: Debian GNU/Linux

Re: Работа с файлами С++

Сообщение Galaxy Master »

может не совсем в тему...

а как на счет сначала в 1-м цикле не переименовывать сходу файлы, а составить их список, а потом вторым циклом - переименовать их уже не читая директорий, а беря имена из списка?
Спасибо сказали:
Аватара пользователя
Rootlexx
Бывший модератор
Сообщения: 4471
Статус: GNU generation
ОС: Debian GNU/Linux

Re: Работа с файлами С++

Сообщение Rootlexx »

Galaxy Master писал(а):
04.08.2008 11:43
а как на счет сначала в 1-м цикле не переименовывать сходу файлы, а составить их список, а потом вторым циклом - переименовать их уже не читаю директорий, а беря имена из списка?

Прочитайте это моё сообщение.
Спасибо сказали:
Аватара пользователя
MUTOgen
Сообщения: 343
Статус: i like the way you move
ОС: OpenSuse 11.1

Re: Работа с файлами С++

Сообщение MUTOgen »

Galaxy Master писал(а):
04.08.2008 11:43
может не совсем в тему...

а как на счет сначала в 1-м цикле не переименовывать сходу файлы, а составить их список, а потом вторым циклом - переименовать их уже не читая директорий, а беря имена из списка?

делал именно так. все равно были глюки с примером 2-15, 1-14. если я ошибаюсь то пните в пример программы... :ph34r:
Спасибо сказали:
Galaxy Master
Сообщения: 142
ОС: Debian GNU/Linux

Re: Работа с файлами С++

Сообщение Galaxy Master »

Rootlexx писал(а):
04.08.2008 11:44
Galaxy Master писал(а):
04.08.2008 11:43
а как на счет сначала в 1-м цикле не переименовывать сходу файлы, а составить их список, а потом вторым циклом - переименовать их уже не читаю директорий, а беря имена из списка?

Прочитайте это моё сообщение.


...да последнюю строчечку не дочитал... сорри.
Спасибо сказали: