Binarne kopiowanie plików, Argumenty wiersza poleceń w "C"

0

Jako zadanie na końcu rozdziału z książki S.Prata mam

Napisz program kopiujacy pliki ,który pobiera nazwępliku żródłowego i docelowego z wiersza poleceń. Skorzystaj ze standardowego wejścia/wyjścia i trybu binarnego.

Mój kod to:

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>;

int main(int argc, char * argv[])
{
    long count,end;
    FILE *in, *out;
    int ch;

    if( argc != 3)
    {
        fprintf(stderr,"Nie poprawana liczba argumentow");
        Sleep(2000);
        exit(1);

    }

    if (   (in = fopen(argv[1],"rb") ) != NULL )
    {
        fprintf(stderr,"Blad otwarcia pliku %s", argv[1]);
        Sleep(2000);
        exit(2);
    }

    if (   (out = fopen(argv[1],"wb") ) != NULL )
    {
        fprintf(stderr,"Blad otwarcia strumienia zapisu do %s", argv[2]);
        Sleep(2000);
        exit(3);

    }

    fseek(in,0L,SEEK_END);
    end = ftell(in);

    for(count = 0L ; count < end ; count++)
    {
        fseek(in,count,SEEK_SET);
        ch = getc(in);
        fputc(ch,out);
    }  

    return 0;
} 

Wywołuje pogram za pomocą wiersza poleceń(próbowałem przed nazwami plików(argumentów) dać ścieżkę))

start C:\program.exe pierwszy.txt drugi.txt

Jednak program wywala mi błąd odczytu. Czy mógłby mi ktoś powiedzieć co jest błędne w kodzie ewentualnie może źle uruchamiam program.

Dziękuje za Waszą pomoc i pozdrawiam.

0

fseek(in,count,SEEK_SET);
ch = getc(in);
fputc(ch,out);

aaarrggh.... toż to będzie wieki trwało, nawet jeśli byłoby bez błędu.

1
viruss3000 napisał(a)
if (   (in = fopen(argv[1],"rb") ) != NULL )
if (   (out = fopen(argv[1],"wb") ) != NULL )

Tak się kończy robienie copy & paste :)

1

Ma znaczenie na ile pakietów podzielę dane wejściowe

Ma ogromne znaczenie, bo w ten sposób dla pliku 1 GB będziesz robił miliard razy (z hakiem) fseek/getc/fputc.

0

Dziękuje za Waszą pomoc ale program niestety nadal nie kopiuje zawartości pliku ;(

Kod po porwakach to:

 #include<stdio.h>
#include<stdlib.h>
#include<windows.h>;

int main(int argc, char * argv[])
{
    long count,end;
    FILE *in, *out;
    int ch;

    if( argc != 3)
    {
        fprintf(stderr,"Nie poprawana liczba argumentow");
        Sleep(2000);
        exit(1);

    }

    if (   (in = fopen(argv[1],"rb") ) == NULL )
    {
        fprintf(stderr,"Blad otwarcia pliku %s", argv[1]);
        Sleep(2000);
        exit(2);
    }

    if (   (out = fopen(argv[2],"wb") ) == NULL )
    {
        fprintf(stderr,"Blad otwarcia strumienia zapisu do %s", argv[2]);
        Sleep(2000);
        exit(3);

    }

    fread(out,sizeof(in), 1 , in);
    fclose(in);
    fclose(out);

    printf("Kopiowanie zakonczone");
    Sleep(2000);

    return 0;
}

Próbowałem też tak i dalej nic

 while(bytes = fread(temp,sizeof(char), ROZMIAR_BUF,in) > 0 )
        fwrite(temp,sizeof(char), bytes, out);
0

sizeof(in) zwraca rozmiar wskaźnika (4 w programie 32-bitowym) a nie rozmiar pliku na dysku.

0

Witam,

Mam ten sam problem, stoję w tym samym miejscu co twórca tego wątku. Problem nie jest rozwiązany, ma ktoś jeszcze jakieś sugestie do tego ćwiczenia? Mi nie kopiuje plików tylko zawiesza się program po włączeniu.

Mam coś takiego:

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>

int main(int argc, char * argv[])
{
    long licznik, koniec;
    FILE * fwsk1, * fwsk2;
    long * c;
    if(argc!=3)
        {
            printf("Za malo argumentow!");
            getch();
            exit(1);
        }

    if((fwsk1=fopen(argv[1], "rb"))==NULL || (fwsk2=fopen(argv[2], "wb"))==NULL)
        {
            printf("Blad w odczycie plikow!");
            getch();
            exit(2);
        }
    fseek(fwsk1, 0L, SEEK_END);
    koniec=ftell(fwsk1);
    for(licznik=0; licznik<koniec; licznik++)
        {
            fseek(fwsk1, licznik, SEEK_SET);
            fseek(fwsk2, licznik, SEEK_SET);
            fread(c, sizeof(long), 1, fwsk1);
            fwrite(c, sizeof(long), 1, fwsk2);
        }
    fclose(fwsk1);
    fclose(fwsk2);
    getch();
    return 0;      
}
1
Luke2 napisał(a):

Mam ten sam problem, stoję w tym samym miejscu co twórca tego wątku. Problem nie jest rozwiązany, ma ktoś jeszcze jakieś sugestie do tego ćwiczenia? Mi nie kopiuje plików tylko zawiesza się program po włączeniu.

A czytałeś odpowiedzi w tym wątku?

Luke2 napisał(a):
if(argc!=3)
{
printf("Za malo argumentow!");
getch();
exit(1);
}

Nie ma czegoś takiego jak getch() w używanych przez Ciebie bibliotekach. Nie przepisuj na pałę z innych programów.
getch() jest w curses, których i tak tu nie potrzebujesz.
W stdio jest getchar(), ale po co Ci on tutaj?
Dlaczego exit() zamiast return?

Luke2 napisał(a):
if((fwsk1=fopen(argv[1], "rb"))==NULL || (fwsk2=fopen(argv[2], "wb"))==NULL)
{
printf("Blad w odczycie plikow!");
getch();
exit(2);
}

Fajnie... A teraz postaw się w sytuacji użytkownika. Dostajesz komunikat Blad w odczycie plikow i kombinuj teraz którego pliku nie można odczytać i dlaczego.
BTW, to jest raczej błąd otwarcia.
Znasz znaczenie flagi "b" w argumencie określającym tryb otwarcia? Wiesz co ona robi (a raczej czego nie robi) w Linuksie?

Luke2 napisał(a):
fseek(fwsk1, 0L, SEEK_END);
koniec=ftell(fwsk1);

Użyj stat() to określenia rozmiaru pliku. Kiedy chcesz sprawdzić ile kilometrów jest z Gdańska do Krakowa to też wskakujesz w samochód i jedziesz, czy patrzysz na mapę/Google/cokolwiek?

Luke2 napisał(a):
for(licznik=0; licznik<koniec; licznik++)
{
fseek(fwsk1, licznik, SEEK_SET);
fseek(fwsk2, licznik, SEEK_SET);
fread(c, sizeof(long), 1, fwsk1);
fwrite(c, sizeof(long), 1, fwsk2);
}

Źle. fread() i fwrite() jako pierwszy argument przyjmują wskaźnik zawierający adres do zaalokowanego miejsca w pamięci, z/do którego będą odczytywać/zapisywać. Ty przekazujesz wskaźnik wskazujący "w kosmos". long *c nie zaalokuje Ci magicznie miejsca w pamięci pod c. Zaalokuje jedynie miejsce pod *c.
I co z tym odczytywaniem po długości long? Tryb binarny nie oznacza, że masz użyć typów liczbowych. fread() i fwrite() nie interesuje jaki typ danych jest pod przekazanym wskaźnikiem. Je obchodzi tylko adres do bloku pamięci i rozmiar tego bloku.
Zaalokuj bufor o rozmiarze np. 4kB i użyj jego.
Nie sprawdzasz czy odczyt/zapis się udał. A co jeśli np. podczas kopiowania zabraknie miejsca w systemie plików?
No i ten fseek()... Skąd Ty to wziąłeś? fread() i fwrite() przesuwają kursor pliku w miarę odczytu/zapisu. Nie musisz go ręcznie popychać. Nie wspominając już o tym, że robisz to źle (long ma więcej bajtów niż 1).

Luke2 napisał(a):
fclose(fwsk1);
fclose(fwsk2);
getch();
return 0;      
}

I znowu ten getch(). Dobrze, że chociaż tym razem dałeś return.

Ten kod wygląda na składany z kilku innych, ze szczyptą własnej, szalonej inwencji twórczej. To bardzo dobrze, jednakże warto także poczytać dokumentację wykorzystywanych funkcji zanim zacznie się ich używać. Mniej okazji do pytania innych dlaczego coś nie działa.

0

Dziękuję za obszerną wypowiedź, daje mi dużo do myślenia i dużo zapału do jeszcze cięższej pracy. Używałem exit() zamiast return, tak mnie nauczyły przykłady z książki (i tu się pewnie kłania to, że złą książkę czytam, bo nie jest nią "Język ANSI C"). getch() ktoś raz polecał zamiast getchar() i użyłem jej po to, aby ktoś przeczytał komunikat o błędzie zanim zniknie, chociaż te komunikaty nie są kompletne jak mówiłeś. Nie pisałem tego programiku pod innych userów tylko pod siebie, proszę o wyrozumiałość. Użyłem trybu binarnego w Windowsie, nie w Linuxie co miało znaczenie gdyż chciałem przekopiować plik z wartościami binarnymi. Funkcji stat() nie znałem do tej pory i wyszukałem koniec pliku na swój sposób. Dalej to też tragedia, źle zrozumiałem fread() i fwrite(). Przepraszam za kłopot, po prostu brnę do przodu za szybko z tymi rozdziałami i się potykam. Dzięki jeszcze raz za odpowiedź i pozdrawiam serdecznie.

2
Luke2 napisał(a):

Dziękuję za obszerną wypowiedź, daje mi dużo do myślenia i dużo zapału do jeszcze cięższej pracy.

Gooood, gooood... [zacieranie rąk z szyderczym uśmieszkiem na ustach]

Luke2 napisał(a):

Używałem exit() zamiast return, tak mnie nauczyły przykłady z książki (i tu się pewnie kłania to, że złą książkę czytam, bo nie jest nią "Język ANSI C").

Tę funkcję stosuje się raczej do zakończenia działania programu z funkcji innej niż main. W pozostałym przypadku jej użycie jest uznawane za nieeleganckie. To tak, jakbyś wyskakiwał z wody zamiast z niej wyjść na brzeg... like a sir.

Luke2 napisał(a):

getch() ktoś raz polecał zamiast getchar() i użyłem jej po to, aby ktoś przeczytał komunikat o błędzie zanim zniknie,

Takie "wstrzymywanie terminala" robi się w przypadku stosowania IDE, które np. prezentuje wynik działania w oknie zamykanym automatycznie po zakończeniu działania programu. Teraz chyba tylko Dev ma taki "ficzer". Normalnie nie powinno się czegoś takiego robić, szczególnie w programach nieinteraktywnych.

Luke2 napisał(a):

chociaż te komunikaty nie są kompletne jak mówiłeś. Nie pisałem tego programiku pod innych userów tylko pod siebie, proszę o wyrozumiałość.

Po pierwsze, wyrabiaj sobie nawyki. Po drugie, Ty także jesteś użytkownikiem tego programu. Jeśli wystąpiłby ten błąd, to Ty musiałbyś kombinować którego pliku nie udało się otworzyć i dlaczego.

Luke2 napisał(a):

Użyłem trybu binarnego w Windowsie, nie w Linuxie co miało znaczenie gdyż chciałem przekopiować plik z wartościami binarnymi.

No widzisz, napisałeś że masz tę samą sytuację co autor wątku, ale nie poinformowałeś nas, że dotyczy ona innego systemu operacyjnego. W przypadku Windows użycie flagi "b" jest prawidłowe. Jednakże, robi ona co innego niż myślisz. Tryb tekstowy nie oznacza, że będziesz czytał tekst, a tryb binarny - liczby. Odczyt i zapis jest tego samego - bajtów. Nie ma znaczenia czy w danych są wartości z "dolnej" tablicy ASCII czy z całej. Tryb tekstowy pod Windows zamienia automatycznie znaki LF (line feed, 0x0A, '\n') na CR LF (carriage return i line feed, 0x0D 0x0A, "\r\n"), gdyż w tym systemie nową linię oznacza się kombinacją dwóch znaków. Tryb binarny takiej translacji przy odczycie/zapisie nie robi.

Luke2 napisał(a):

Funkcji stat() nie znałem do tej pory i wyszukałem koniec pliku na swój sposób.

Szalona inwencja twórcza jest i tak lepsza od braku inwencji jakiejkolwiek. Próbowałeś, zostałeś poprawiony, wzbogaciłeś się o nową wiedzę. Ciesz się.

Luke2 napisał(a):

Dalej to też tragedia, źle zrozumiałem fread() i fwrite().

Pytanie tylko czy zrozumiałeś co zrobiłeś źle. Inną kwestią jest czy wiesz jak to zrobić dobrze. Poczytaj, popróbuj, a jak nic nie wykombinujesz - pytaj.

Luke2 napisał(a):

Przepraszam za kłopot, po prostu brnę do przodu za szybko z tymi rozdziałami i się potykam.

Nie masz za co przepraszać zbytnio. I nie ucz się języka C "na szybko". Wymaga on skupienia i zrozumienia jak coś działa i dlaczego. Bez tego będzie tylko trudniej i więcej błędów trudnych do wykrycia. Przykładem jest chociażby ten Twój long *c, który wynika z braku wiedzy o wskaźnikach (lub wiedzy niekompletnej).

Na zachętę podpowiem Ci, że nie musisz znać rozmiaru pliku kopiowanego, a tym samym używać pętli for (aczkolwiek pętla będzie konieczna). Zobacz w dokumentacji co i w jakich przypadkach zwraca funkcja fread().

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0