• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Zmiana nazwy pliku - C++

Object Storage Arubacloud
0 głosów
2,375 wizyt
pytanie zadane 31 maja 2016 w C i C++ przez ignacjusz Bywalec (2,390 p.)
edycja 31 maja 2016 przez ignacjusz

Witam, ostatnio pisałem program, który zmienia nazwy plików (konkretnie: np. nazwa.jpg -> nazwa (0).jpg). Wszystko działa poprawnie oprócz przypadku w którym występują polskie znaki. Wtedy program pomija to i idzie dalej. Korzystam z funkcji rename, która wymaga łańcuchów w formacie c, więc muszę przekonwertować string za pomocą c_str(). Czy to coś zmienia. Jeśli będzie potrzebny kod to mogę wkleić.

komentarz 31 maja 2016 przez bartolinciu Dyskutant (7,580 p.)
Kod na pewno się przyda
komentarz 31 maja 2016 przez niezalogowany
Zauważ jaki zakres znaków jest legalny w char*, na który dokonujesz konwersji
komentarz 31 maja 2016 przez ignacjusz Bywalec (2,390 p.)
#include <iostream>
#include <fstream>
#include <windows.h>
#include <conio.h>

using namespace std;

//Plik zbierz.bat zbiera nazwy plików w folderze do pliku nazwy.txt

int main()
{
    ofstream czysc;
    czysc.open("name.txt");
    if(!czysc.good())
    {
        cout<<"Error with file!"<<endl;
        getch();
        exit(0);
    }
    czysc.close();

    system("start zbierz.bat");
    Sleep(100);

    fstream plik;
    plik.open("name.txt");

    if(!plik.good())
    {
        cout<<"Error with file!"<<endl;
        getch();
        exit(0);
    }

    string a,a1="",n1="";
    while(!plik.eof())
    {
        getline(plik, a);

        int ln=a.length();
        a1="";

        for(int i=0; i<ln; i++)
        {
            char c=a[i];
            if(c=='.')
                break;
            a1+=c;
        }

        if((ln>=4)&&(a[ln-4]=='.' && (a[ln-3]=='j' || a[ln-3]=='J'))) // sprawdzanie czy format .jpg lub .JPG
        {
            n1="";
            bool nawias=false;
            for(int i=0; i<ln; i++)
            {
                char c=a[i];
                if(c==')')
                    nawias=false;

                if(nawias==true)
                    n1+=c;

                if(c=='(')
                    nawias=true;
            }
            nawias=false;

            if(n1=="")
                goto dothis;

            continue;

            dothis:

            string old_name;
            string new_name;
            string ex=".jpg";
            old_name=a;
            new_name=a1+" (0)"+ex;

            rename(old_name.c_str(), new_name.c_str());

            cout<<old_name.c_str()<<" -> "<<new_name.c_str()<<endl;
        }
    }
    plik.close();


    cout<<"Uda\210o si\251!"<<endl;
    getch();

    return 0;
}
komentarz 31 maja 2016 przez ignacjusz Bywalec (2,390 p.)

Czyli, jeśli zamiast string użyję char[] to będzie dobrze?

komentarz 31 maja 2016 przez niezalogowany
Nie, char* oraz char[] to w tym kontekście to samo. Polecam rzucić okiem na ASCII Table, aby się przekonać dlaczego, ciebie interesuje coś takiego: https://stackoverflow.com/questions/15569155/how-to-rename-a-file-using-wstring
komentarz 2 czerwca 2016 przez ignacjusz Bywalec (2,390 p.)

Mam rozumieć, że interesuje mnie wstring bo obejmuje on "extended ASCII"? Gdy wkleiłem kod z linku, który mi podałeś, kompilator dawał błędy. Na stronie Micro$oftu znalazłem jeszcze _wrename , który przyjmuje wchar_t[] czyli wstring. teraz pytanie jak przekonwertować string na wstring. Znalazłem w internecie przykłady konwersji int, long, double itp. na wstring jednak nie było string. Co robić?

1
komentarz 3 czerwca 2016 przez draghan VIP (106,230 p.)

Posiłkowane SO:

#include <locale>
#include <codecvt>
#include <string>

#include <iostream>

int main()
{
    std::string pl_s = "String z polskimi znakami - zażółć gęślą jaźń.";

    std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;

    std::wstring pl_ws = converter.from_bytes(pl_s); // konwersja na wstring
    std::string reconverted = converter.to_bytes(pl_ws); // konwersja z wstring na string

    std::cout<<pl_s<<"\n"<<reconverted;
    return 0;
}

 

komentarz 3 czerwca 2016 przez ignacjusz Bywalec (2,390 p.)

fatal error: codecvt: No such file or directory

komentarz 3 czerwca 2016 przez draghan VIP (106,230 p.)
Kompilator zgodny z C++11?
komentarz 3 czerwca 2016 przez ignacjusz Bywalec (2,390 p.)
W CodeBloksie pisze GNU GCC nic więcej
komentarz 3 czerwca 2016 przez draghan VIP (106,230 p.)
komentarz 3 czerwca 2016 przez ignacjusz Bywalec (2,390 p.)
Zaznaczyłem flagę [-std=c++11] i dalej nic
komentarz 3 czerwca 2016 przez draghan VIP (106,230 p.)
To wychodzi na to, że masz stary kompilator. Powinieneś go uaktualnić.
komentarz 3 czerwca 2016 przez ignacjusz Bywalec (2,390 p.)
Jak?
komentarz 3 czerwca 2016 przez draghan VIP (106,230 p.)
Windows czy Linux?
komentarz 3 czerwca 2016 przez ignacjusz Bywalec (2,390 p.)
Winda
komentarz 3 czerwca 2016 przez draghan VIP (106,230 p.)

Pobierz instalkę MinGW stąd, zainstaluj. Potem w C::B, w ustawieniach kompilatora w zakładce "toolchain executables" zmieniasz ścieżkę na tą, gdzie instalowałeś MinGW. I powinno śmigać.

komentarz 3 czerwca 2016 przez ignacjusz Bywalec (2,390 p.)
Zainstalowałem, podałem ścieżkę, i teraz muszę wybrać odpowiednie .exe do kompilacji:

EDIT: Obrazka mi nie chce puścić
komentarz 3 czerwca 2016 przez ignacjusz Bywalec (2,390 p.)

img

 

komentarz 4 czerwca 2016 przez draghan VIP (106,230 p.)
Pousuwaj przedrostek "mingw32-" z nazw wszystkich narzędzi. :)
komentarz 4 czerwca 2016 przez ignacjusz Bywalec (2,390 p.)

Chyba działa, ale dalej jest fatal error: codecvt: No such file or directory

komentarz 4 czerwca 2016 przez draghan VIP (106,230 p.)
Na pewno podałeś dobrą ścieżkę? U mnie po domyślnej instalacji TDM działa bez zarzutu. Może wrzuć tego screena na jakiś hosting grafiki, bo tego nie da się odczytać.
komentarz 4 czerwca 2016 przez ignacjusz Bywalec (2,390 p.)

Udało się!

Przez przypadek podałem ścieżki do plików w folderze TDM-GCC-64, a scieżkę do folderu zostawiłem na mingw. Dziękuje za cierpliwość. Jeśli dodasz odpowiedź (bo piszemy na komentarzach pod pytaniem) to dam Ci naj. Czy teraz wystarczy, że przepisze swój kod na wstringu? Pytam, bo na wstringu nie działają operacje stringowskie.

komentarz 4 czerwca 2016 przez draghan VIP (106,230 p.)

Udało się!

Przez przypadek podałem ścieżki do plików w folderze TDM-GCC-64, a scieżkę do folderu zostawiłem na mingw. Dziękuje za cierpliwość.

Na zdrowie. :) Nawet jeśli sposób z konwersją na wstring nie zadziała, to masz teraz przynajmniej bardziej aktualny kompilator. :)

Jeśli dodasz odpowiedź (bo piszemy na komentarzach pod pytaniem) to dam Ci naj.

Nie ma sensu nic przepisywać, skoro wszystko jest tutaj. ;)

Czy teraz wystarczy, że przepisze swój kod na wstringu?

Oto jest zagadka. Jak nie spróbujesz, to się nie dowiesz. :)

 

komentarz 4 czerwca 2016 przez ignacjusz Bywalec (2,390 p.)

In function 'int main()': error: cannot convert 'std::__cxx11::wstring {aka std::__cxx11::basic_string<wchar_t>}' to 'const wchar_t*' for argument '1' to 'int _wrename(const wchar_t*, const wchar_t*)'|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===

komentarz 4 czerwca 2016 przez draghan VIP (106,230 p.)

Powinieneś użyć metody std::wstring::c_str() do uzyskania const wchar_t* z obiektu std::wstring.

komentarz 4 czerwca 2016 przez ignacjusz Bywalec (2,390 p.)

C++ mnie nie lubi... sad

komentarz 4 czerwca 2016 przez draghan VIP (106,230 p.)
Pokaż kod. ;)
komentarz 4 czerwca 2016 przez ignacjusz Bywalec (2,390 p.)
#include <iostream>
#include <fstream>
#include <windows.h>
#include <conio.h>
#include <locale>
#include <codecvt>
#include <string>

using namespace std;

int main()
{
    ofstream czysc;
    czysc.open("name.txt");
    if(!czysc.good())
    {
        cout<<"Error with file!"<<endl;
        getch();
        exit(0);
    }
    czysc.close();

    system("start zbierz.bat");
    Sleep(100);

    fstream plik;
    plik.open("name.txt");

    if(!plik.good())
    {
        cout<<"Error with file!"<<endl;
        getch();
        exit(0);
    }

    string a,a1="",n1="";
    while(!plik.eof())
    {
        getline(plik, a);

        int ln=a.length();
        a1="";

        for(int i=0; i<ln; i++)
        {
            char c=a[i];
            if(c=='.')
                break;
            a1+=c;
        }

        if((ln>=4)&&(a[ln-4]=='.' && (a[ln-3]=='j' || a[ln-3]=='J')))
        {
            n1="";
            bool nawias=false;
            for(int i=0; i<ln; i++)
            {
                char c=a[i];
                if(c==')')
                    nawias=false;

                if(nawias==true)
                    n1+=c;

                if(c=='(')
                    nawias=true;
            }
            nawias=false;

            if(n1=="")
                goto dothis;

            continue;

            dothis:

            string old_name;
            string new_name;
            string ex=".jpg";
            old_name=a;
            new_name=a1+" (0)"+ex;

            wstring_convert<codecvt_utf8<wchar_t>> converter;
            wstring w_old_name=converter.from_bytes(old_name);
            wstring w_new_name=converter.from_bytes(new_name);

            _wrename(w_old_name.c_str(), w_new_name.c_str());
        }
    }
    plik.close();


    cout<<"Uda\210o si\251!"<<endl;
    getch();

    return 0;
}

 

komentarz 5 czerwca 2016 przez draghan VIP (106,230 p.)
edycja 5 czerwca 2016 przez draghan

Ech ech... Ten kod nie jest najlepszej jakości.

Ale poza tym Twoim głównym problemem jest to, że zaprzęgasz do wylistowania katalogu plik wsadowy, który inaczej koduje ścieżki, niż w WinAPI.

Rozwiązaniem jest wykorzystanie WinAPI do listowania zawartości katalogu i odcięcie się od zewnętrznych narzędzi.

Ten kod również nie jest najlepszy (np. sprawdź, co się stanie jeśli w katalogu nie będzie żadnych plików *.jpg), ale wydaje mi się, że program zrobi to, czego od niego wymagasz.

W innych okolicznościach nie dałbym Ci gotowca, ale walczysz z tym już jakiś czas - może już wystarczy. ;)

#include <windows.h>
#include <iostream>
#include <string>
#include <vector>

std::string get_first_chunk(const std::string &filename);
std::string prepare_new_name(const std::string &old_name);

std::vector<std::string> get_files_in_dir(std::string path);

void rename_in_current_dir(const std::vector<std::string> &listFiles);

int main()
{
    std::vector<std::string> listed_files;
    listed_files = get_files_in_dir("./*.jpg");
    rename_in_current_dir(listed_files);
    return 0;
}

std::vector<std::string> get_files_in_dir(std::string path)
{
    WIN32_FIND_DATA find_data;
    HANDLE find_handle = FindFirstFile(path.c_str(), &find_data);

    std::vector<std::string> filenames;
    filenames.push_back(find_data.cFileName);

    while (FindNextFile(find_handle, &find_data))
        filenames.push_back(find_data.cFileName);

    return filenames;
}

std::string get_first_chunk(const std::string &filename)
{
    return filename.substr(0, filename.find('.'));
}

std::string prepare_new_name(const std::string &old_name)
{
    std::string extension = ".jpg";
    std::string new_name;
    std::string first_chunk;
    std::string bracket_content;

    int length = old_name.length();

    first_chunk = get_first_chunk(old_name);

    bool bracket = false;
    for(int i = 0; i<length; i++)
    {
        if(old_name[i] == ')')
            bracket = false;

        if(bracket == true)
            bracket_content += old_name[i];

        if(old_name[i] == '(')
            bracket = true;
    }

    if(bracket_content != "")
        return old_name;

    return first_chunk + " (0)" + extension;
}

void rename_in_current_dir(const std::vector<std::string> &listFiles)
{
    for(const auto &filename : listFiles)
    {
        std::string new_name = prepare_new_name(filename);
        int result = rename(filename.c_str(), new_name.c_str());
        if(result == 0) std::cout<<"succesfully renamed 1 file\n";
        else if(result == EACCES) std::cout<<"can't create file\n";
        else if(result == ENOENT) std::cout<<"can't find file to rename\n";
        else if(result == EINVAL) std::cout<<"new name contains forbidden characters\n";
        else std::cout<<"there is another error\n";
    }
}

Daj znać, czy to działa. Ja mam tylko anglojęzyczną wersję Windowsa, więc na 100% nie mam pewności poprawności dla polskich znaków diakrytycznych w nazwach plików.

EDIT: zapomniałem dopisać komentarz odnośnie niezłapanego wyjątku. Zdaje mi się, że jest to błąd w implementacji std::wstring_convert w MinGW. Pewności 100% nie mam, ale raczej powinno śmigać. Błędy w MinGW się zdarzają i to wcale nie tak rzadko - to tylko port GCC na Windows, a porty mają to do siebie, że to tylko... porty. ;)

komentarz 5 czerwca 2016 przez ignacjusz Bywalec (2,390 p.)

Działa!

Jeszcze tylko zrozumieć kod i bedzie ok smiley. Dziekuję za pomoc.

I jeszcze takie małe pytanie: Po co wszędzie pisać std:: jeśli mozna using namesace std;?

komentarz 5 czerwca 2016 przez draghan VIP (106,230 p.)

Jeszcze tylko zrozumieć kod i bedzie ok

Jak czegoś nie rozumiesz, to pisz. ;)

I jeszcze takie małe pytanie: Po co wszędzie pisać std:: jeśli mozna using namesace std;?

W ten sposób jawnie określasz pochodzenie danej klasy czy obiektu. Jest to jedna z dobrych praktyk. Aczkolwiek przy jednoplikowym programie nie ma to większego znaczenia.

Widzę, że przez nieuwagę zapomniałem jako argument get_files_in_dir() przesłać referencji do stałej, zamiast kopii... trudno. :P

komentarz 5 czerwca 2016 przez ignacjusz Bywalec (2,390 p.)

WIN32_FIND_DATA
FindFirstFile
push_back
FindNextFile

Wszytkie te funkcje i typy to częśc WINapi?

 

komentarz 5 czerwca 2016 przez draghan VIP (106,230 p.)

Prawie wszystkie. push_back jest metodą std::vector.

komentarz 5 czerwca 2016 przez ignacjusz Bywalec (2,390 p.)
Nie było tego w moim kodzie, bo nigdy nie grzebałem w WinAPI.

Jeszcze raz dzięki :).
komentarz 5 czerwca 2016 przez draghan VIP (106,230 p.)

Kiedy uczyłem się programować, coś liznąłem z WinAPI, ale już nie pamiętam wiele. Najważniejsze, to umieć korzystać z dokumentacji. ;)

Funkcja _wrename(), której użyłeś, jest częścią WinAPI.

Jako ciekawostkę powiem, że w nadchodzącym standardzie C++17 będzie wreszcie dodana obsługa systemu plików. W tej chwili można znaleźć przymiarki, szukając frazy "experimental/filesystem". Tutaj dokumentacja na cppreference. GCC w wersji 6 już udostępnia tę funkcjonalność - niestety nie jest to dostępne w tym kompilatorze, który z moją małą pomocą zainstalowałeś.

Zaloguj lub zarejestruj się, aby odpowiedzieć na to pytanie.

Podobne pytania

+1 głos
2 odpowiedzi 194 wizyt
0 głosów
0 odpowiedzi 331 wizyt
pytanie zadane 19 listopada 2019 w C i C++ przez cupoforanges Początkujący (380 p.)
0 głosów
1 odpowiedź 239 wizyt
pytanie zadane 30 października 2016 w C i C++ przez TheFeniks Gaduła (4,690 p.)

92,620 zapytań

141,474 odpowiedzi

319,813 komentarzy

62,004 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...