Работа с файлами С++ (...)
Модератор: Модераторы разделов
-
MUTOgen
- Сообщения: 343
- Статус: i like the way you move
- ОС: OpenSuse 11.1
Работа с файлами С++
Какими средствами можно выяснить расширение файла если я работаю с библиотекой dirent.h (читаю директорию и меняю мена файлов с расширением jpg)?
-
nesk
- Сообщения: 2268
- Статус: Линукссаксовец
- ОС: MS Windows XP Home SP3
Re: Работа с файлами С++
расширение - это просто часть имени файла
анализируйте d_name, если эта строка заканчивается на .jpg , то наверно это то, что Вам надо
анализируйте d_name, если эта строка заканчивается на .jpg , то наверно это то, что Вам надо
Внимание: У меня под рукой нет машины с Linux. Я не использую эту ОС. Ответы я даю либо по памяти, либо мне помогает гугл. Тщательно читайте маны по тем командам и конфигурационным файлам, которые я упоминаю.
0xDEFEC8ED
0xDEFEC8ED
-
MUTOgen
- Сообщения: 343
- Статус: i like the way you move
- ОС: OpenSuse 11.1
Re: Работа с файлами С++
я немного неправильно задал вопрос... надо шире... какими средствами можно изменять имена файлов в директориях основываясь на возможностях С/С++ (библиотеки, функции и т.д.)
-
MUTOgen
- Сообщения: 343
- Статус: i like the way you move
- ОС: OpenSuse 11.1
Re: Работа с файлами С++
все, проблему решил с помошью функции rename.
-
MUTOgen
- Сообщения: 343
- Статус: i like the way you move
- ОС: OpenSuse 11.1
Re: Работа с файлами С++
возникла проблема с функцией rename. вот есть код на С:
нужно чтобы в текущей директории все файлы с расширением .jpg переименовались с x по y (т.е. например от 5.jpg до 10.jpg, в коде взято от 1 до 14). Так вот, если для одной директории эта прога выполнилась, то второй раз файлы не переименовываются в ней, например если добавляю еще файлов. Может я не правильно использую какие-то функции?
Код:
#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: Работа с файлами С++
Код:
#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. Т.е. где-то в середине совершенно случайным образом (не обязательно пятерка) выпадает цифра. Код вроде бы железный и идет по счетчику... где там может теряться значение?
-
Rootlexx
- Бывший модератор
- Сообщения: 4471
- Статус: GNU generation
- ОС: Debian GNU/Linux
Re: Работа с файлами С++
MUTOgen
В вашей программе readdir() читает не статичную папку. После каждого прочтения следующего элемента файл условно переименовывается, при этом, разумеется, содержимое папки меняется. Как будет себя вести readdir() в такой ситуации, чётко не определено. В зависимости от реализации, она может в конце концов прочесть элемент, соответствующий уже переименованному файлу, что приведёт к описанной коллизии (в вашем примере уже переименованный файл 5 снова переименовывается), причём неизвестно, когда это наступит. А может, readdir() в один прекрасный момент вернёт NULL, что приведёт к слишком раннему завершению программы.
Для выяснения причин я бы посоветовал включить в код вывод отладочной информации, такой как: значение errno, имя текущего файла, новое имя файла, значение счётчика.
Что касается правильного написания программы, лучше сначала прочитать все необходимые элементы, занести их в, скажем, список, а далее уже переименовывать.
В вашей программе readdir() читает не статичную папку. После каждого прочтения следующего элемента файл условно переименовывается, при этом, разумеется, содержимое папки меняется. Как будет себя вести readdir() в такой ситуации, чётко не определено. В зависимости от реализации, она может в конце концов прочесть элемент, соответствующий уже переименованному файлу, что приведёт к описанной коллизии (в вашем примере уже переименованный файл 5 снова переименовывается), причём неизвестно, когда это наступит. А может, readdir() в один прекрасный момент вернёт NULL, что приведёт к слишком раннему завершению программы.
Для выяснения причин я бы посоветовал включить в код вывод отладочной информации, такой как: значение errno, имя текущего файла, новое имя файла, значение счётчика.
Что касается правильного написания программы, лучше сначала прочитать все необходимые элементы, занести их в, скажем, список, а далее уже переименовывать.
-
Atragor
- Сообщения: 681
- Статус: ...
Re: Работа с файлами С++
Добавляем в цикл
Делаем 14 файлов f1.jpg-f14.jpg.
Запускаем:
После этого все файлы на месте. Теперь меняем 2,15 на 1,14 и запускаем еще раз:
8 файлов затерлись, 6 осталось.
Вывод - надо писать выходные файлы в отдельную папку, или генерировать другие имена.
ЗЫ Ну вот, пока писал, Rootlexx уже все объяснил
Код: Выделить всё
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
- Сообщения: 343
- Статус: i like the way you move
- ОС: OpenSuse 11.1
Re: Работа с файлами С++
пробывал переделать вышеизложенный код в списки, но эффект тот же. писать в другую директорию не вариант.
раз уж чтение происходит статически то решил переделать вот как:
()
Программа немного поменялась. Теперь она удаляет первые 4 символа из имени файлов с расширением .mp3 (проверка не жесткая, только на символ '3', т.к. в директории гарантировано будут только эти файлы). Так вот. По идее функция listF теперь изменив одну запись, завершается и возвращает 0. Если возвращает не 0, а 1, то значит требуемых файлов не осталось и из while мы выйдем. По идее при такой структуре не readdir не натолкнется на изменение списка имен файлов, а просто на этом же шаге функция завершится и далее заново откроется поток для чтения в следующем запуске функции listF. Т.е. насколько я понимаю, глючить не должно по той причине по которой глючило до этого. Но все же оно глючит... В частности есть странный глюк: при запуске проги она изменив один файл вылетает, а если запустить ее повторно то изменяется все остальные файлы.... причем в любом случае сделав дело, она завершается ошибкой... Что в ней не так?
раз уж чтение происходит статически то решил переделать вот как:
Код:
#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. Т.е. насколько я понимаю, глючить не должно по той причине по которой глючило до этого. Но все же оно глючит... В частности есть странный глюк: при запуске проги она изменив один файл вылетает, а если запустить ее повторно то изменяется все остальные файлы.... причем в любом случае сделав дело, она завершается ошибкой... Что в ней не так?
-
Rootlexx
- Бывший модератор
- Сообщения: 4471
- Статус: GNU generation
- ОС: Debian GNU/Linux
Re: Работа с файлами С++
MUTOgen
Смущают строки:
А что будет, если в имени файла не будет пробела? strchr вернёт NULL, и в третьей из приведённых строк будет обращение к памяти по адресу 0x1, что, разумеется, приведёт к ошибке сегментирования. Если же пробел даже есть, то после переименования программа, второй раз проходя папку, наткнётся-таки на переименованный файл без пробела в имени.
Кроме того, неясно, зачем в начале вы 2 раза вызываете:
Хотите пропустить элементы «.» и «..»? А кто сказал, что они обязательно будут первыми? Да и не нужно это, учитывая проверку, выполняющуюся в:
На самом деле, многократно открывать и закрывать поток не нужно, есть же функция rewinddir().
Смущают строки:
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: Работа с файлами С++
Rootlexx писал(а): ↑03.08.2008 18:26MUTOgen
Смущают строки:
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: Работа с файлами С++
с новой (временной) директорией вариант хороший:
1) создаём копии с новыми именами во временной директории
2) убиваем старые файлы
3) переносим новые файлы в старую директорию
4) удаляем временную директорию
успехов
The answer, my friend, is blowin' in the wind.
The answer is blowin' in the wind.
The answer is blowin' in the wind.
-
MUTOgen
- Сообщения: 343
- Статус: i like the way you move
- ОС: OpenSuse 11.1
Re: Работа с файлами С++
попробую пожалуй... если есть хорошие ссылки на описание функций - поделитесь, буду рад
-
Galaxy Master
- Сообщения: 142
- ОС: Debian GNU/Linux
Re: Работа с файлами С++
может не совсем в тему...
а как на счет сначала в 1-м цикле не переименовывать сходу файлы, а составить их список, а потом вторым циклом - переименовать их уже не читая директорий, а беря имена из списка?
а как на счет сначала в 1-м цикле не переименовывать сходу файлы, а составить их список, а потом вторым циклом - переименовать их уже не читая директорий, а беря имена из списка?
-
Rootlexx
- Бывший модератор
- Сообщения: 4471
- Статус: GNU generation
- ОС: Debian GNU/Linux
Re: Работа с файлами С++
Galaxy Master писал(а): ↑04.08.2008 11:43а как на счет сначала в 1-м цикле не переименовывать сходу файлы, а составить их список, а потом вторым циклом - переименовать их уже не читаю директорий, а беря имена из списка?
Прочитайте это моё сообщение.
-
MUTOgen
- Сообщения: 343
- Статус: i like the way you move
- ОС: OpenSuse 11.1
Re: Работа с файлами С++
Galaxy Master писал(а): ↑04.08.2008 11:43может не совсем в тему...
а как на счет сначала в 1-м цикле не переименовывать сходу файлы, а составить их список, а потом вторым циклом - переименовать их уже не читая директорий, а беря имена из списка?
делал именно так. все равно были глюки с примером 2-15, 1-14. если я ошибаюсь то пните в пример программы...
-
Galaxy Master
- Сообщения: 142
- ОС: Debian GNU/Linux
Re: Работа с файлами С++
Rootlexx писал(а): ↑04.08.2008 11:44Galaxy Master писал(а): ↑04.08.2008 11:43а как на счет сначала в 1-м цикле не переименовывать сходу файлы, а составить их список, а потом вторым циклом - переименовать их уже не читаю директорий, а беря имена из списка?
Прочитайте это моё сообщение.
...да последнюю строчечку не дочитал... сорри.