Von einer Bildschirmausgabe zum abspeichern in einer Datei
-
nixversteher schrieb:
Ok, dann evtl anders
Warum verwendest du nicht einfach nur einen anderen Dateinamen für die Ausgabedatei?
-
Ok, Ausgabe komplett abändern ist gar nciht gut.
Um das Fehlerabfangen kümmer ich mich noch, ich würde das Programm nur gerne erst mal zum laufen bringen um was in der Hand zu haben damit ich meinen Bericht schreiben kann
-
Dann doch FILE* (so sehr es mich sträubt, das zu empfehlen) - jetzt mußt du "nur" noch den übergebenen Dateinamen umbauen (oder du übergibst der Funktion gleich zwei verschiedene Dateinamen).
-
MFK schrieb:
Warum verwendest du nicht einfach nur einen anderen Dateinamen für die Ausgabedatei?
Ich nehme jetzt erst mal einen festen Dateinamen um erst einmal die Funktion zu bekommen.
Der fprintf funzt bei mir nur überhauptnicht:void Konvert(const char *filename) { FILE *f = fopen(filename, "rb"); if (f) { DEA_ARCHIV_TYP DEARecord; while(!feof(f)) { fread(&DEARecord, sizeof(DEARecord), 1, f); struct tm stm = *localtime(&DEARecord.Startzeit); FILE *fout = fopen("test.txt", "w"); fprintf(fout,"%02d.%02d.%04d %02d:%02d.%02d,%03d : ", stm.tm_mday , stm.tm_mon , stm.tm_year + 1900 , stm.tm_hour , stm.tm_min , stm.tm_sec , DEARecord.Millisec > 0 ? DEARecord.Millisec : 0); fprintf(fout,"DEARecord: Zustand = %d, Kennung = %d, Grund = %c\n", DEARecord.Wert.Zustand , DEARecord.Kennung , DEARecord.Grund); } fclose(f); }
Bei dem Code habe ich beim Kompilieren kein Problem, allerdings schmiert mir das Programm nach 3 Dateien ab und die Konvertierung wird weder ausgegeben noch in die Datei geschrieben.
-
CStoll schrieb:
Dann doch FILE* (so sehr es mich sträubt, das zu empfehlen) - jetzt mußt du "nur" noch den übergebenen Dateinamen umbauen (oder du übergibst der Funktion gleich zwei verschiedene Dateinamen).
Das "nur" macht mir etwas Angst.
Und von mir kommt ein "wie" oder "womit"
-
@Absturz: Hast du mal im Debugger verfolgt, was da passiert? (btw solltest du die Ausgabe-Datei auch wieder schließen, wenn du fertig bist)
@Umbau des Dateinamens: mit std::string wäre es einfach, mit char* wird es ein wenig komplizierter. Ich würde strrchr() den Punkt im Dateinamen suchen und alle Zeichen dahinter mit der neuen Endung überschreiben (strcpy()).
-
womit arbeitest du nochmal also welcher entwicklungsumgebung?
versuch es doch mal zu debuggen und schau dir an was bei fread rauskommt und ob nach fopen dein fout überhaupt einen sinnvollen wert hat (also keinen fehlerwert z.B.)
um die fehlerbehandlung solltest du dich imo sofort kümmern, das hilft meist unerklärliche fehler durchsichtiger zu machen
*ich sollte noch n kaffee trinken ich bin einfach zu langsam* *GG*
-
Ich arbeite mit Dev-C++.
Ich versuch es mal mit dem Debugger, danke.
-
Aussager Debugger:
Eine Zugriffsverletzung (Segmentation Fault) trat in ihrem Programm auf??
Ist das etwas wovor ich gewarnt wurde?
-
Hi,
ich glaube nicht, dass das (zuverlässig) geht.
printf() und IOStreams sind einfach sehr unterschiedliche Konzepte für dieselbe Aufgabe.Ich kann Dir nur zeigen, wie man das in C++ eigentlich machen würde:
#incude <iomanip> using std::setw; using std::setfill; ostream& operator<<(ostream& ost, struct tm const * stm) { return ost << setw(2) << setfill('0') << stm->tm_mday << " " << setw(2) << setfill('0') << stm->tm_mon << " " << setw(4) << setfill('0') << stm->tm_year + 1900 << " " << setw(2) << setfill('0') << stm->tm_hour << " " << setw(2) << setfill('0') << stm->tm_min << " " << setw(2) << setfill('0') << stm->tm_sec; } ostream& operator<<(ostream& ost, DEA_ARCHIV_TYP const& rec) { struct tm * stm = localtime(&rec.Startzeit); return ost << stm << " " << setw(3) << setfill('0') << (rec.Millisec > 0 ? rec.Millisec : 0) << " " << "DEARecord: Zustand = " << rec.Wert.Zustand << ", Kennung = " << rec.Kennung << ", Grund = " << rec.Grund; } FILE *f = fopen(filename, "rb"); if (f) { DEA_ARCHIV_TYP DEARecord; while(!feof(f)) { fread(&DEARecord, sizeof(DEARecord), 1, f); cout << DEARecord << "\n"; ofstream out("Logfile"); out << DEARecord << "\n"; } fclose(f);
Allerdings habe ich jetzt nur die Ausgabe "angepasst".
Als Designtipp hätte ich noch:- Entweder das Einlesen ebenso über den operator>>() machen (geht aber nur, solange DEA_ARCHIV_TYP "default-konstruierbar" ist; sonst über eine Factoryklasse)
- Lege die Informationen nicht binär ab !
Zweiteres macht unglaublich Ärger:
- Das Speicherlayout von Klassen ist nicht festgelegt, ein anderer Compiler, andere Version, andere Compileflags, ... machen damit sofort alle Deine Files ungültig.
- Bei Debuggen ist das die Hölle ! Nimm lieber "lesbare" Files ! Da finde man alles wieder.
- Der Unterschied zwischen Deine "Anzeige-Funktion" und der Form, in der die Records in der Datei liegen, ist überflüssig.
- Mit einem "lesbaren Format", brauchst Du nur einen operator<<().
- spätestens mit "inneren Verweisen" (z.B. wenn Deine Klasse string, char*, ... enthält), klappt das mit dem "Binärspeichern" sowieso nicht mehr.
- Zwar wird der "Einlesecode" aufwendiger, aber gleichzeitig wird der Aufruf viel flexibler, eionfacher und "schöner":ifstream f(filename); ofstream out("Logfile"); while(f) DEA_ARCHIV_TYP DEARecord; f >> DEARecord; out << DEARecord << "\n"; }
bzw. (da Du ja offensichtlich mehrere davon einlesen möchtest)
ifstream f(filename); vector<DEA_ARCHIV_TYP> DEARecord; copy(istream_iterator<DEA_ARCHIV_TYP>(f), // wendet operator>>(f, ...) an istream_iterator<DEA_ARCHIV_TYP>(), // Kennzeichen für "EOF" back_inserter(DEARecord));
... dann hast Du alle DEA_ARCHIV_TYP-Objekte aus der Datei in den Vektor DEARecord gepackt und kannst mittels
DEARecord[0], DEARecord[1], ....
auf sie zugreifen.P.S.: Das Handling von localtime() scheint mir fehlerhaft zu sein (auch, wenn es gelegentlich funktionieren mag). Gemeint ist localtime so, dass man nur den Pointer zurückgibt ... kannst in meinem Code sehen.
Gruß,
Simon2.
-
benutz bitte den editier button oben rechts wenn du einem pot etwas hinzufügen möchstest :p
setz mal bei fread einen breakpoint und bei fopen für die zieldatei, das klingt haargenau danach als ob dasa öffnen fehlschlägt und dein fout ins nirvana zeigt, kann auch ausm fread kommen ... setz einfach die breakpoints und wenn der debugger da steht, lass dir die werte von den varialben f, fout, DEARecord und stm anzeigen ... was mir spanisch vorkommt ist
struct tm stm = *localtime(&DEARecord.Startzeit);
kann das wer am rande erklären oder liegt hier evtl. ein fehler ?!
füge mal
if (fout == NULL) { int Error = GetLastError(); printf("Fehler %d", Error); <--- breakpoint }
nach fopen ein und setz nen breakpoint da ein wenn du dort reinstolperst kannst ja mal nach der beschreibung zu dem fehlercode schauen
-
Ja, vermutlich - schau mal genau hin, wo dieser Fehler auftritt.
(und auch auf die Gefahr hin, mich zu wiederholen: Kontrolliere auf Fehler (z.B. beim Öffnen der Dateien))
-
Du verwendest in einem Struct, was du einlesen willst eine Union. Ist sichergestellt, dass die .pls-Datei an der Stelle, wo du unsigned char und float vereinigt hast, auch immer sizeof(float) Bytes (binär) vorhanden sind?
EDIT: Du solltes dein Struct (sodann du denn dabei bleiben willst) nicht eins zu eins (binär) aus der Datei kopieren, sondern die Werte nacheinander explizit zuweisen (falls es sich um ein binär-Format handelt).
Seg-Faults ließen sich einfacher vermeiden, wenn du statt char* std::string verwendest und statt diverser Arrays eben einen Container aus der STL (std::vector, std::list, std::map, etc.).
Grüße... Heiko
-
Ok, danke erst mal am Anfang!
Dann muss ich allerdings sagen, dass ich 60% eurer Vorschläge nicht wirklich verstanden habe.
Ich versuch es jetzt mal der Rehei nach und schau dann mal was ich davon hinbekomme
-
nixversteher schrieb:
...
Dann muss ich allerdings sagen, dass ich 60% eurer Vorschläge nicht wirklich verstanden habe....Zu den anderen Vorschlägen will ich nix sagen, aber meinen ersten kann ich nochmal erläutern:
1.) Ausgeben eines Objekts (hier eines DEA_ARCHIV_TYP-Objekts) in eigene Funktion auslagern
2.) Diese Funktion nenne ich "operator<<()" und sie wird mit "... << ..." aufgerufen (z.B. wird beicout << "Simon"
deroperator<<(ostream&, char const*)
alsoperator<<(cout, "Simon")
aufgerufen.)
3.) Diese Funktion kann man mit jedem ostream nutzen (egal, ob cout, ofstream, ...).Zusatz: Ich habe einen eigenen operator<<() für "struct tm*" geshrieben, weil man den immer mal gebrauchen kann.
Gruß,
Simon2.
-
Also, das Programm läuft, noch nicht ganz wie es soll, aber es läuft
Ich habe jetzt eine 2 Variable mit in die Funktion Konvert() übergeben und darin den passend veränderten Dateinamen.
Jetzt steh ich noch vor einem Problem worauf ich mir mal gar keinen Reim machen kann: Ich habe im ersten Verzeichnis, in der die nicht konvetierten Dateien stehen ca. 13700 Dateien. Die möchte ich alle Konvertiert haben, allerdings steigt mein Programm nach der 509ten Datei aus, hab ich evtl irgendwo ne Bereichsüberschreitung oder eine Variable die dann überläuft???
Oder gibts da sonst eine erklärung für?Danke schon mal bis hierher!!
using namespace std; void Konvert(const char *filename, const char *datei); #pragma pack(push,2) typedef float FLOAT; typedef unsigned char UCHAR; typedef char CHAR; typedef short int SHORT; typedef time_t DATE_TIME; typedef union _proz_wert_union { /* Union für den Prozeßwert */ FLOAT Wert; /* für Analogeingänge einen Float */ UCHAR Zustand; /* für Digitaleingänge einen UCHAR */ } PROZ_WERT_UNION; /* 4 Byte entsprechend dem größen Member */ typedef struct _dea_archiv_typ { /* Bytes Bedeutung */ DATE_TIME Startzeit; /* 4 Startzeit des Intervalls */ SHORT Millisec; /* 2 Millisec. bei Echtzeitverarb. sonst. -1 */ PROZ_WERT_UNION Wert; /* 4 union für den Prozeßwert */ UCHAR Kennung; /* 1 Kennung des archivierten Wertes */ CHAR Grund; /* 1 Archivierungsgrund */ } DEA_ARCHIV_TYP; /* 12 Byte pro Archiveintrag */ #pragma pack(pop) int main () { char pathname[MAX_PATH + 1]; char maskname[MAX_PATH + 1]; char fullname[MAX_PATH + 1]; char pfad[MAX_PATH + 1]; char ganz[MAX_PATH + 1]; char dat[MAX_PATH + 1]; strncpy(pathname, "C:\\Osnabrueck\\DEA\\2007\\09\\", MAX_PATH); strncpy(maskname, pathname, MAX_PATH); strncat(maskname, "*", MAX_PATH); HANDLE fHandle; WIN32_FIND_DATA wfd; fHandle=FindFirstFile(maskname,&wfd); do { if (!( (wfd.cFileName[0]=='.') && ( (wfd.cFileName[1]=='.' && wfd.cFileName[2]==0) || wfd.cFileName[1]==0 ) )) { if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { MessageBox(0,wfd.cFileName,"Folgendes Verzeichnis wurde gefunden:",0); // Datei ist keine, sondern ein Verzeichnis... } else { cout << wfd.cFileName << endl; //Namen der Dateien ausgeben strncpy(fullname, pathname, MAX_PATH); strncat(fullname, wfd.cFileName, MAX_PATH); strncpy(pfad, "C:\\Osnabrueck\\DEA\\2007\\KONV\\09\\", MAX_PATH); strncpy(ganz, pfad, MAX_PATH); strncpy(dat, pfad, MAX_PATH); strncat(dat, wfd.cFileName, MAX_PATH); strncat(dat, ".txt", MAX_PATH); Konvert(fullname,dat); } } } while (FindNextFile(fHandle,&wfd)); FindClose(fHandle); cin.get(); } void Konvert(const char *filename,const char *datei) { FILE *fout = fopen(datei, "w"); FILE *f = fopen(filename, "rb"); if (f) { DEA_ARCHIV_TYP DEARecord; while(!feof(f)) { fread(&DEARecord, sizeof(DEARecord), 1, f); struct tm stm = *localtime(&DEARecord.Startzeit); fprintf(fout,"%02d.%02d.%04d %02d:%02d.%02d,%03d : ", stm.tm_mday , stm.tm_mon +1 , stm.tm_year + 1900 , stm.tm_hour -2 , stm.tm_min , stm.tm_sec , DEARecord.Millisec > 0 ? DEARecord.Millisec : 0); fprintf(fout,"DEARecord: Zustand = %d, Kennung = %d, Grund = %c\n", DEARecord.Wert.Zustand , DEARecord.Kennung , DEARecord.Grund); } fclose(f); } // cin.get(); //return 0; }
-
Du solltest natürlich auch die Ausgabedatei per fclose() schließen, wenn du sie nicht mehr brauchst.
(übrigens sehen die ganzen strncpy()-Serien im Hauptprogramm etwas unnötig aus)
-
Oh ähh, ja richtig da war was...
Danke läuft.
Hab mit den "strncpy()-Serien" etwas rumprobiert und so läuft es am besten, und mit den wenigsten FehlernDanke nochmal an alle beteiligten!!
-
nixversteher schrieb:
...
... typedef float FLOAT; typedef unsigned char UCHAR; typedef char CHAR; typedef short int SHORT; typedef time_t DATE_TIME; ... int main () { char pathname[MAX_PATH + 1]; char maskname[MAX_PATH + 1]; char fullname[MAX_PATH + 1]; char pfad[MAX_PATH + 1]; char ganz[MAX_PATH + 1]; char dat[MAX_PATH + 1]; strncpy(pathname, "C:\\Osnabrueck\\DEA\\2007\\09\\", MAX_PATH); strncpy(maskname, pathname, MAX_PATH); strncat(maskname, "*", MAX_PATH); ... strncpy(fullname, pathname, MAX_PATH); strncat(fullname, wfd.cFileName, MAX_PATH); strncpy(pfad, "C:\\Osnabrueck\\DEA\\2007\\KONV\\09\\", MAX_PATH); strncpy(ganz, pfad, MAX_PATH); strncpy(dat, pfad, MAX_PATH); strncat(dat, wfd.cFileName, MAX_PATH); strncat(dat, ".txt", MAX_PATH); ...
Also DAS ist definitv überflüssig und unübersichtlich. Für sowas wurde String genommen.Aber ich habe den Eindruck, als wollest Du eigentlich sowieso nicht wirklich etwas lernen, sondern nur "solange fummeln, bis irgendwas irgendwie klappt"...
Schade, hätte ich das vorher gewusst, hätte ich mir einiges an Zeit gespart.
Gruß,
Simon2.
-
Gut möglich, dass es überflüssig ist.
Ich würde nicht sagen, dass ich nichts lernen wollte, aber programmieren an sich war noch nie mein Lieblingssport, und ich denke da wirst du mir zustimmen, man benötigt ein gewisses Händchen für sowas. Und genau das hatte ich noch nie, deshalb habe ich versucht das unvermeidlich nötige zu lernen bzw zu verstehen.
Ich kann auch nicht abstreiten, dass mir persönlich es egal ist wie ein Programm im Endeffekt aussieht solange es das macht was es soll...
Vielen Dank für deine Mühe!