» »

[C++] Portabilna funkcija za kopiranje datotek

[C++] Portabilna funkcija za kopiranje datotek

zhigatsey ::

Živjo, rad bi si napisal portabilno funkcijo za kopiranje datotek.
Do sedaj sem tole spacal skupi. Ker mi je stl, se dokaj neznana in nimam
se pravega obcutka za cpp, bi vas prosil da mi pomagate dopolniti tole funkcijo.
Recimo preverjanje napak. Kakšen try blok, preverjanje streamov ob odprtju, al pa kaj podobnega. V glavnem da bi bila funkcija tako napisana kot mora biti, in da me ne bo sram ko jo bo videl kaksen c++ guru.:) Funkcija sprejme tri parametre in sicer vhodno datoteko, ciljno datoteko v katero se bo prekopirala , in parameter overwrite. Ce je overwrite true potem se ciljna datoteka prepise tudi ce ze obstaja.
// FileCopy
bool FileCopy(const char* Src, const char Dest, bool Overwrite)
{
    const int BUF_SIZE = 4096;

    // File exists and not owerwrite
    if (FileExists(FileName) && (!Owerwrite))
        return false;
    
    ifstream in(Src, ios_base::in | ios_base::binary); // Input file 
    ofstream out(Dest, ios_base::out | ios_base::binary); // Output file
    
    char buf[BUF_SIZE];
    do {
        in.read(&buf[0], BUF_SIZE); 
        out.write(&buf[0], in.gcount());
    } while (in.gcount() > 0); 

    in.close( );
    out.close( );
}


Hvala za odgovore.
  • razdelilo iz: OwcA ()

zhigatsey ::

Aja pozabil sem še to da funkcija FileExists zgleda takole, če bo kdo hotel poskusiti prevesti.

// FileExists
bool FileExists(const char* FileName)
{
    bool Flag = false;
    fstream Fin;
    Fin.open(FileName, ios::in);
    if (Fin.is_open()) {
        Flag = true;
    }
    Fin.close();
    return Flag;
}


pa še to da je v funkciji FileCopy napakica ker manjka še zvezdica na drugem parametru, (char*)

zhigatsey ::

Se opravičujem...
Zgornja funkcija file copy je polna napak... Sem bil površen...
Malo sem popravil in dodal malo preverjanja napak, upam da imate kakšen komentar na tole funkcijo.

// FileExists
bool FileExists(const char* FileName)
{
    bool Flag = false;
    fstream Fin;
    Fin.open(FileName, ios::in);
    if (Fin.is_open()) {
        Flag = true;
    }
    Fin.close();
    return Flag;
}

// FileCopy
bool FileCopy(const char* Src, const char* Dest, bool Overwrite)
{
    const int BUF_SIZE = 4096;

    // File exists and not owerwrite
    if (FileExists(Dest) && (!Overwrite))
    {
        cerr << "Error: Destination file already exist!" << endl;
        return false;
    }

    ifstream in(Src, ios_base::in | ios_base::binary); // Input file
    ofstream out(Dest, ios_base::out | ios_base::binary); // Output file

    // Check input file stream
    if (in.bad()) {
        cerr << "Error: Cannot open source file!" << endl;
        return false;
    }

    // Check output file stream
    if (out.bad()) {
        cerr << "Error: Cannot open destination file!" << endl;
        return false;
    }

    char buf[BUF_SIZE];
    do {
        in.read(&buf[0], BUF_SIZE);
        out.write(&buf[0], in.gcount());
    } while (in.gcount() > 0);

    in.close( );
    out.close( );
}

zhigatsey ::

Še en popravek, na koncu funkcija FileCopy vrne true..

// FileExists
bool FileExists(const char* FileName)
{
    bool Flag = false;
    fstream Fin;
    Fin.open(FileName, ios::in);
    if (Fin.is_open()) {
        Flag = true;
    }
    Fin.close();
    return Flag;
}

// FileCopy
bool FileCopy(const char* Src, const char* Dest, bool Overwrite)
{
    const int BUF_SIZE = 4096;

    // File exists and not owerwrite
    if (FileExists(Dest) && (!Overwrite))
    {
        cerr << "Error: Destination file already exist!" << endl;
        return false;
    }

    ifstream in(Src, ios_base::in | ios_base::binary); // Input file
    ofstream out(Dest, ios_base::out | ios_base::binary); // Output file

    // Check input file stream
    if (in.bad()) {
        cerr << "Error: Cannot open source file!" << endl;
        return false;
    }

    // Check output file stream
    if (out.bad()) {
        cerr << "Error: Cannot open destination file!" << endl;
        return false;
    }

    char buf[BUF_SIZE];
    do {
        in.read(&buf[0], BUF_SIZE);
        out.write(&buf[0], in.gcount());
    } while (in.gcount() > 0);

    in.close( );
    out.close( );

    return true;
}

zhigatsey ::

Še malo popravkov, sedaj funkcija dela kot bi morala....
Res pa bi vas prosil če imate kakšen nasvet, kako bi funkcijo izboljšali...
Tudi ne vem če sem se lotil s pravega konca..
Sploh kar se tiče preverjanja napak.

// FileCopy
bool FileCopy(const char* Src, const char* Dest, bool Overwrite)
{
    const int BUF_SIZE = 4096;

    // Source file not exists
    if (!FileExists(Src)) {
        cerr << "Error: Source file not exists!" << endl;
        return false;
    }

    // Destination file exists and not owerwrite
    if (FileExists(Dest) && (!Overwrite)) {
        cerr << "Error: Destination file already exist!" << endl;
        return false;
    }

    ifstream in(Src, ios_base::in | ios_base::binary); // Input file
    ofstream out(Dest, ios_base::out | ios_base::binary); // Output file

    // Check input file stream
    if (in.bad()) {
        cerr << "Error: Cannot open source file!" << endl;
        return false;
    }

    // Check output file stream
    if (out.bad()) {
        cerr << "Error: Cannot open destination file!" << endl;
        return false;
    }

    char buf[BUF_SIZE];
    do {
        in.read(&buf[0], BUF_SIZE);
        out.write(&buf[0], in.gcount());
    } while (in.gcount() > 0);

    in.close();
    out.close();

    return true;
}

Gundolf ::

OK no tkole štirje komentarji (in nekaj godrnjanja na koncu)...

Imaš polno return statementov. Sicer jaz ne zagovarjam metode enega samega returna in jih tudi sam namečem v svoje funkcije kolikor jih je pač treba ... Ampak tale tvoj primer je po svoje posrečen za prikaz, zakaj multipli returni niso vedno dobri. Recimo da datoteke out ne moreš odpreti - bum, return false. Kdo bo pa zaprl datoteko in? No tu imaš srečo da delaš v C++u, ki to stori zate, ampak potem pridemo pa do novega vprašanja - zakaj eksplicitno zapreš obe datoteki pred regularnim koncem programa? Torej na kratko povedano, ali se znebi explicitnega zapiranja (tako ali tako se zgodi avtomatično) ali pa ga obdrži (če se spomniš kak dober razlog) in spremeni strukturo funkcije tako, da bo imela le en exit point (return). Se pravi da bo šla vedno čez to čiščenje na koncu.

Morda način, da tip errorja vrneš kar kot text v cerr ni najboljši. Kaj če bo koga zanimalo zakaj je funkcija failala in bi rad sprogramiral primerne odzive na različne razloge za fail? Tough luck!

Kaj se zgodi, če sta Dest in Src enaka?

Tistemu Owerwrite lahko daš neko default vrednost, recimo false (dopuščam možnost, da to že sedaj imaš v deklaraciji).

Mislim da bi se dalo tudi kaj povedati o brezveznem definiranju ios_base::in ko ustvarjaš ifstream ampak v to nisem 100%, tako da ti prepuščam, da sam malo pogooglaš (ali pa kar sprobaš izpustit).

Slogovno se še malo potrudi, zdaj imaš nekje spremenljivke z malo, nekje z veliko, tudi poimenovanje je raznoliko (in, Fin). Malo poenoti zadeve in se pri tem po možnosti oprimi kakšnega uveljavljenega sloga (recimo funkcije in spremenljivke z malo, classi z veliko začetnico...). Čeprav to je že čisto stvar estetike.

zhigatsey ::

O hvala za komentarje,
Sam prihajam iz delphi okolja, in v c++ potem vse bolj cudno izpade.
Glede piimenovana spremenljivk bom popravil... Za napake pa vem da bi jih moral
"generirati" z throw, če se ne motim samo ne vem točno kako bi to naredil....
Tudi ne vem če je dovolj preverjati tokove samo z "bad()". Bo popravil in spet kaj poslal.

Shinobi ::

Se sama sreca, da si vzel C++ (ifstream etc...), meni se je skoraj zmesalo, ko sem pisal neki loader z fread in sem imel exceptione nastavljene, pa se je Microsoft Visual C++ 2003 skoraj strgalo. Kr neke faulte mi je metal. Ko sem isto kodo prevedel z Intel C++ kompajlerjem 9 in vse warninge na highest, pa threat warings as errors je vse skupaj delalo kot bi moralo. Od zdaj naprej kadar je le mozno uporabljam vsaj dva kompajlerja, da vem da je vse vredu. Microsoft ji jih je ze parkat posteno zagodel!

Vesoljc ::

> Živjo, rad bi si napisal portabilno funkcijo za kopiranje datotek.

class AFileManager {
public:
 virtual int FileCopy(const char* Src, const char* Dest, bool Overwrite) = 0;
};

class StdLibFileManager: public AFileManager {
public:
   int FileCopy(const char* Src, const char* Dest, bool Overwrite)
   {
        // std::io 
   }
};

class Win32FileManager: public AFileManager {
public:
   int FileCopy(const char* Src, const char* Dest, bool Overwrite)
   {
        // win32 filecopy 
   }
};


//header
// globalni pointer
extern AFileManager *gpFileManager;

// source
AFileManager          *gpFileManager;
// globalan instanca
#ifdef _WIN32
   Win32FileManager      gFileManager;
#else
   StdLibFileManager     gFileManager;
#endif
//
gpFileManager = (AFileManager*)&gFileManager
Abnormal behavior of abnormal brain makes me normal...

Shinobi ::

Vesoljc:

Vse to je nepotrebno, ker po ANSI/ISO standardu bo to delalo v vsakem C++ prevalajniku.

ifstream, ostream, cin, cout mora delat vsepovsod. tako na Win32, OSX, Linux, Unix, VXWORKS, PS2, XBOX, Gsmi...

zhigatsey ::

Živjo,
Za preverjanje napak bi vas vprašal za mnenje...
Kako nej to naredim... Sam sem mislil da ob vsaki napaki vrnil neko številko... in potem
bi preverjal v catch če je bila ta številka in izpisal ustrezno sporočilo o napaki...
Kaj pa vi mislite...

Hvala za odgovore...

Shinobi ::

bool Test(****)
{
try
{ open files, read file, duplicate. close files; return true; }
catch (int napaka)
{
cout < "Prislo je do napake st: " < napaka < endl;
return false;
}
catch (...)
{
cout < "Zgodila se je neka napaka." < endl;
return false;
}
//Do sem sploh nebi smeli prit?
}

Gundolf ::

Ja Shinobi (glede tistega ali program pride do končnega komentarja). Ampak je treba poudarit, da le zato ker imaš znotraj try in vseh catch blokov return statement. Drugače se izvajanje nadaljuje normalno tudi izven catch bloka. Primer:
int main() {
   try {
      danger();
   } catch(...) {
      cout << "danger threw exception\n";
      return 1;
   }
   cout << "the end\n";
   return 0;
}


shigatse - glede exceptionov (velja za večino jezikov) takole - uporabljaš jih le v izjemnih primerih. Poskus odpiranja fajla, ki ne obstaja, to ravno ni. Iz istega razloga ti ifstream ne vrže exceptiona. če poskusiš odpreti neobstoječ fajl, medtem ko operator new vrže exception, če zmanjka spomina. Torej, kako implementirati vračanje napak, ki so dokaj pogoste - ali z vračanjem nekega classa, ki definira napako(e), ali z vračanjem inta (enuma), ali pa z definiranjem funkcije znotraj classa, katerega lahko kasneje preverjaš podobno kot ifstream. Še kaka možnost bi se našla.

Zgodovina sprememb…

  • spremenil: Gundolf ()

Vesoljc ::

@shinobi
zaenkrat res sprasuje samo za filecopy, kjer pac rabis samo iostream, ampak kaj kmalu (mogoce, ane) bo pa hotel se kaj vec (dir operacije, search, fileinfo). in ce na zacateku zadevo postavi portabilno (z uporabo abstrakcije) mu to prihrani precej tezav...
Abnormal behavior of abnormal brain makes me normal...

zhigatsey ::

Živjo,

Prebral sem vaše odgovore in popravil kodo... Če vam še kaj ni všeč oz. bi se
dalo narediti bolje pa kar povejte...... Delam si eno tako knjižnjico, zaenkrat sem si
zadal cilj da bom naredi z std knjiznjico vse kar se bo dalo... Za naprej pa ne vem,
lahko bi uporabil tudi boost lib..., vendar je pa to zato da malo bolj spoznam cpp in
standardno knjiznjico...

Tole je izsek iz headerja...

//------------------------------------------------------------------------------
// Files methods
//------------------------------------------------------------------------------

//  FileCopyErrors
enum FileCopyErrors {
    FILE_OPEN_ERR,
    FILE_DUPLICATE_ERR,
    FILE_DEST_EXISTS_ERR
};

// FileRemove - Remove file
bool FileRemove(const string& fileName);
// FileRename - Rename a file or directory
bool FileRename(const string& oldName, const string& newName);
// FileExists
bool FileExists(const string& fileName);
// FileCopy
bool FileCopy(const string& src, const string& dest, bool overwrite = false);


tukaj pa je se definirano....

// FileExists
bool FileExists(const string& fileName)
{
    bool flag = false;
    fstream in;
    in.open(fileName.c_str(), ios::in);
    if (in.is_open()) {
        flag = true;
    }
    in.close();
    return flag;
}

// FileCopy
bool FileCopy(const string& src, const string& dest, bool overwrite)
{
    const int BUF_SIZE = 4096;
    bool result = false;

    // Source and Destination are equal
    if (src == dest) {
        throw FILE_DUPLICATE_ERR;
    }

    // Source file not exists
    if (!FileExists(src)) {
        throw FILE_OPEN_ERR;
    }

    // Destination file exists and not owerwrite
    if (FileExists(dest) && (!overwrite)) {
        throw FILE_DEST_EXISTS_ERR;
    }

    ifstream in(src.c_str(), ios_base::in | ios_base::binary); // Input file
    ofstream out(dest.c_str(), ios_base::out | ios_base::binary); // Output file

    // Check input file stream
    if ((!in.bad()) && (!out.bad())) {
        char buf[BUF_SIZE];
        do {
            in.read(&buf[0], BUF_SIZE);
            out.write(&buf[0], in.gcount());
        } while (in.gcount() > 0);
        result = true;
    }
    else {
        throw FILE_OPEN_ERR;
    }

    in.close();
    out.close();

    return result;
}

64202 ::

> enum FileCopyErrors

V c++ je tudi std::exception, pa izpeljes svoje. Drugace se pa pri iostreamih da baje vklopiti tudi exceptione, nisem pa se uporabljal...
I am NaN, I am a free man!

OwcA ::

Razcepljeno v Kdaj uporabiti izjeme?.
Otroška radovednost - gonilo napredka.

Gundolf ::

Ena opomba shigatse: to, da ti funkcija FileCopy vrne bool je malo (beri: zelo) zavajujoče, ker je to tako ali tako vedno true.


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

Keylogger

Oddelek: Programska oprema
352663 (1390) Blisk
»

Java skeniranje map in podmap

Oddelek: Programiranje
61161 (1050) nightrage
»

c# seminarska

Oddelek: Programiranje
112685 (2358) tuned
»

c# tiho tiskanje slik.

Oddelek: Programiranje
101949 (1620) OmegaM
»

[C] MySQL

Oddelek: Programiranje
292823 (1845) Tutankhamun

Več podobnih tem