Dateien mit C-Programm kopieren



  • Hallo Leute!

    Da ich in den letzten Tagen ein bischen zuviel Zeit hatte habe ich mich aufgemacht, das cp-Kommando der Bash zumindest annährend in der Funktion zu klonen. Prinzipiell ist das ja auch kein Problem und mit ein paar Zeilen zu bewältigen. Nur ist eine Lösung der Sorte:

    int c; while((c=fgetc(in)!=EOF) fputc(c, out);

    nicht zwingend effektiv, da sich der Lese/Schreibkopf der HD zu oft hin-und herbewegen muss. Ein Buffer, wie ich ihn im folgenden Listing verwendet habe wäre da schon eine tolle Sache, wenn es da nich doch noch einen Fehler im folgenden Programm gibt, den ich selbst auch nach langer Suche nicht finden kann. Da ich aber schon solange herumüberlegt und probiert habe kann ich das Problem auch nicht mehr beiseite legen. Deshalb wäre ich euch für eine mögliche Lösung bzw. Erläuterung des Fehlers sehr dankbar.

    #include <stdio.h>
    #define BUFFER 20
    
    int main(int argc, char *argv[]) {
      int c[BUFFER+1], i, len;
      FILE *in=fopen(argv[1], "r");
      FILE *out=fopen(argv[2], "w");
     read_write:
      for(i=0; ((c[i]=fgetc(in))!=EOF) && (i<=BUFFER); i++) len=i;
      for(i=0; i<=len; i++) fputc(c[i], out); 
      if(len==BUFFER) goto read_write;
      fclose(in); fclose(out);
    }
    

    PS: Im groben funktioniert das obige Listing sogar, nur das jeweils 21-Zeichen wird nicht mehr aus dem Buffer kopiert oder kommt erst gar nicht darein.



  • Naja irgendwie ist das eine ziemlich seltsame Methode um eine Datei zu kopieren.
    Außerdem arbeitest du mit goto... *ouch*

    Ich würde dir mal einen Blick auf die Funktion fread bzw. fwrite empfehlen.

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[]) 
    {
      FILE* pIn = NULL;
      File* pOut = NULL;
      long int filesize = 0;
      char* buffer = NULL;
    
      pIn = fopen( (char*)argv[1], "r");
      if(pIn == NULL) exit(1);
      fseek(pIn, 0, SEEK_END);
      filesize = ftell(pIn);
      rewind(pIn);
    
      buffer = (char*) malloc(filesize);
      if(buffer == NULL) exit(2);
      fread(buffer, sizeof(char), filesize, pIn);  
      fclose(pIn);
    
      pOut = fopen( (char*)argv[2], "w+");
      if(pOut == NULL) exit(1);
      fwrite(buffer, sizeof(char), filesize, pOut);
      fclose(pOut);
      free(buffer);
      return 0;
    }
    

    Oder so ähnlich. Ist einfacher und wahrscheinlich auch schneller als immer fgetc und diesen Schleifen zu arbeiten.



  • Hallo MAG und danke für deine schnelle Antwort!

    Mir war auch bei dem schreiben des Programms ein möglicher Lösungsansatz mit fgets bekannt, indem man einfach n-Zeichen einfach in einen Buffer einliest und diese dann mit fputs wieder aus dem Buffer herausschreiben kann. Diese Lösung ist zwar kaum länger, als ganz ohne Puffer zu arbeiten, erschien mir jedoch auch noch als zu einfach, da auf fertige Funktionen zurückgegriffen wird. Aus rein sportlicher Sicht wollte ich deshalb nur die grundlegensten Mittel verwenden. Auch die Goto-Anweisung gehörte für mich dazu. Trotzdem interessiert mich nun, was ich in meinem Listing falsch gemacht habe. Schließlich habe ich die Schleifen schon tausendmal in meinem Kopf durchgespielt und bin immer wieder zu dem Ergebnis gekommen, dass es normalerweise fehlerfrei laufen müsste. Versteh mich nicht falsch - deine Lösung ist mit Sicherheit viel strukturierter und einfacher zu verstehen, als das von mir oben angeführte Listing nur versuche ich jetzt auch zu verstehen, was ich bei meiner Lösung falsch gemacht habe.

    PS: Wenn du mal versuchen könntest, hinter den Fehler in meiner Lösung zu kommen wäre ich dir wirklich sehr dankbar. Ansonsten aber wie schon gesagt vielen Dank für deine Bemühungen.



  • Warum das Rad neu erfinden? Die Funktionen gibts nicht aus Spass und wenn du bei größeren Programmen statt bereits fertigen Funktionen eigene schreibst für triviale Aufgaben wirst du
    a) nie fertig und
    b) in an sich überflüssigen Codezeilen untergehen



  • Nochmals danke für eure Posts! Vor allem MAG hat mir sehr bei meinem Problem das Rat neu zu erfinden geholfen, auch, wenn er mich genauso, wie Diamond davon überzeugen wollte, auf fertige Bibliotheksfuntktionen zurückzugreifen. Dies tue ich ja auch meistens nur wollte ich diesmal rein aus sportlichem Ehrgeiz darauf verzichtem. Und? Es ist mir fast genau 24 Std. später gelungen eine Version zu schreiben, die wirklich nur mit fgetc und fputc eine Datei, beliebiger Größe kopiert. Hier das 'leicht' veränderte Listing als Beweis dazu :D:

    #include <stdio.h>
    #include <stdlib.h>
    
    int getFLEN(FILE *fd) {
      int i, len;
      for(i=0; fgetc(fd)!=EOF; i++) len=i;
      return len;
    }
    
    int main(int argc, char *argv[]) {
      int i, len, c;
      int *s;
      FILE *in=fopen(argv[1], "r");
      FILE *out=fopen(argv[2], "w");
      len=getFLEN(in); rewind(in);
      if((s = (int*) malloc(len*sizeof(*s)))==NULL) return -1;
      for(i=0; i<=len; i++) (*s++)=fgetc(in);
      s-=len;
      for(i=0; i<len; i++) fputc(*s++, out);
      fclose(in); fclose(out);
    }
    


  • beliebig? kopier mal eine datei groesser 1 gig. wenn du glueck hast, stuerzt dein programm ab.

    du solltest wissen:
    * das OS benutzt sehr wahrscheinlich puffer, also wird jedes fgetc/fputc durch einen puffer geschleift und der schreib/lesekopf wird nicht belastet.
    * zeichenweise ganze dateien kopieren ist grober unfug, weil du so rechenzeit verschwendest
    * ein schreib/lesepuffer so gross wie die datei ist grober unfug. eine angemessene groesse von mehreren KB oder MB tuts auch.



  • * die Datei zweimal lesen um sie einmal zu kopieren ist.....



  • ... purer wahnsinn!

    ich glaube, die funktion habe ich unterbewusst ueberlesen, um mir die qualen zu ersparen...



  • Hallo c.rackwitz, hallo LordJackson!

    Ihr habt ja recht mit dem Programm da oben kann man nur "effektiv" Dateien kopieren, die kleiner sind, als der freie Arbeitsspeicher, der einem zur Verfügung steht. Bei größeren Dateien wird der Prozess geswappt und alles muss dreimal gelsesn und doppelt geschrieben werden - und das alles über die HD. Dass dies nicht der Königsweg ist weiß ich. Deshalb war mein primäres Ziel ja auch das erste Listing zu verwenden, das einen Buffer verwendet, in den bei jedem Durchgang x - im Beispiel 21 - Zeichen eingelsesen werden unm diese dann gleich wieder in die Datei zu schreiben. Leider scheint sich in den Schleifen ein Fehler zu verstecken. Findet ihn, dann verwende ich das bessere Listing oder macht mir nen Vorschlag, wie man eure Vorschläge in Code realisieren kann.

    PS: Zu meiner getFLEN()-Funktion kann ich euch nur fragen, was ihr meint, was fseek wohl macht? Intern wird die funktion doch genau so arbeiten, wie meine im obigen Listing, nämlich vom ersten bis zum letzten Zeichen die vorliegende Datei auszulesen und auf EOF zu warten.



  • #include <stdio.h>
    
    #define BUFLEN 1024
    
    int main(int argc, char **argv)
    {
        char buf[BUFLEN];
        int numread;
        FILE *inf, *of;
    
        if (argc < 3)
        {
            puts("not enough arguments!");
            puts("program <infile> <outfile>");
            return 1;
        }
    
        if (!(inf = fopen(argv[1], "rb")))
        {
            puts("error: fopen(infile);");
            return 2;
        }
    
        if (!(of = fopen(argv[2], "wb")))
        {
            puts("error: fopen(outfile);");
            fclose(inf);
            return 3;
        }
    
        while (!ferror(inf) && (numread = fread(buf, 1, BUFLEN, inf)))
        {
    		printf("%d read\n", numread);
    		fwrite(buf, 1, numread, of);
    		if (feof(inf) || ferror(of))
    			break;
        }
    
        fclose(of);
        fclose(inf);
    
        return 0;
    }
    


  • Arthur_Dent schrieb:

    [...], was ihr meint, was fseek wohl macht? Intern wird die funktion doch genau so arbeiten, wie meine im obigen Listing, nämlich vom ersten bis zum letzten Zeichen die vorliegende Datei auszulesen und auf EOF zu warten.

    Äh, nein? 😃



  • fseek machts anders und funktioniert garantiert nicht SO (mit feof()).

    http://www-ccs.ucsd.edu/c/stdio.html#fseek



  • Hallo!
    Ich geb ja zu, dass die letzten Listings nicht so der Brenner waren, aber jetzt habe ich es endlich geschafft, das erste zu Perfektionieren. Wahrscheinlich werdet ihr lachen, was ihr im Zweifelsfalls auch schon jetzt tut, aber es funktioniert wirklich - und das nur mit fgetc und fputc. Damit ihr aber nicht sagen könnt, dass ich vollkommen unbelehrbar bin habe ich sogar fseek benutzt, um die Dateilänge zu bekommen.

    Nun sied mal ehrlich, ist dieses Listing nicht der Hammer?

    #include <stdio.h>
    #include <stdlib.h>
    #define BUFFER 1024
    
    int main(int argc, char *argv[]) {
      int c[BUFFER+1], len, flen, i;
      FILE *in=fopen(argv[1], "r");
      FILE *out=fopen(argv[2], "w");
      fseek(in, 0, SEEK_END);
      flen=ftell(in);
      rewind(in);
     read_write:
      for(i=0; flen>0 && i<=BUFFER; i++, flen--) { c[i]=fgetc(in); len=i; }
      for(i=0; i<=len; i++) fputc(c[i], out);
      if(BUFFER==len) goto read_write;
      fclose(in); fclose(out);
    }
    

    PS: Interessanterweise lag das Problem in der ersten for-Schleife.



  • ersetz doch mal deinen goto-loop mit einem do {} while ();



  • Das ist ohne goto auch ziemlich einfach und sieht dann wie folgt aus:) :

    #include <stdio.h>
    #include <stdlib.h>
    #define BUFFER 4096
    
    int main(int argc, char *argv[]) {
      int i, flen,  len=BUFFER, c[BUFFER+1];
      FILE *in=fopen(argv[1], "r");
      FILE *out=fopen(argv[2], "w");
      fseek(in, 0, SEEK_END);
      flen=ftell(in);
      rewind(in);
      while(BUFFER==len) {
      for(i=0; i<=BUFFER && flen>0; i++, flen--) { c[i]=fgetc(in); len=i; }
      for(i=0; i<=len; i++) fputc(c[i], out);
      }  fclose(in); fclose(out);
    }
    

Log in to reply