Probleme mit Positionierung und Einlesen/Schreiben

TechM

Grünschnabel
Hallo,

als erstes möchte ich sagen ich bin ein C-. Ich sitze seit Montag morgen vor meinem Rechner, bin total am verzweifeln und versuche ein Programm zu schreiben, welches Werte aus folgender Textdatei (Auszug: es handlt sich um die FETT gedruckten Werte) Werte ausliest, diese dann in eine Formel einfügt und den resultierenden Wert in eine neue (Text)Datei einfügt.

Zyklische Erfassung Spitzenwertmessung_-1820N Zeit: 18,078613 Sec 22.01.2003 19:00:38
Gespeichert bei: 200 Zyklus Gespeichert für: 3 Segmente
Punkte: 2
Zeit Vertikal Weg Vertikal Kraft
Sec mm N
11,550537 -0,073262166 -2303,3469
11,588135 0,09793396 -234,5567

[...] es geht hier so noch 3000 Zeilen lang so weiter. Immer wieder das gleiche Muster.

Hier mein Quelltext wie weit ich bin (Ist aber in C und nicht C++)

Code:
#include <stdio.h>
#include <stdlib.h>

main()
{
	FILE *quelle, *ziel;
	char name_q[255], name_z[255];
	int c;
	char s[256];
	int i = 0;
	
	long pos = 0;
	printf("Name Quelldatei : ");
    scanf("%s",name_q);
    quelle=fopen(name_q,"r");

	printf("Name Zieldatei : ");
    scanf("%s",name_z);
    ziel=fopen(name_z,"w");

	
	printf("\nAnzahl der Stellen einrücken (vom Anfang): ");
	scanf("%ld",&pos);
	fflush(stdin);

	fseek(quelle, 0L, SEEK_SET);

	
	while( (c=getc(quelle)) != EOF)
	{


		if(c=='\n')
		{
			fseek(quelle, pos, SEEK_CUR);
			s[i]='\0';
			i=0;
			fprintf(ziel,"%s\n",s);
			puts(s);
		}
		else s[i++]=c;
		
		
		/*putc(c,ziel);
		putc(c,stdout);

		fseek(quelle, pos, SEEK_CUR);*/ //Überbleibsel, ohne Verwendung!
	
	}	
	
}

mein Problem ist folgendes:
Ich komm nicht drauf, wie ich in der geöffneten Datei an eine bestimmte Position gelange (so weit bin ich ja schon mit SEEK) UND eine der fettgedruckten Zahlen entnehme um sie danach (zwischendrin müsste sie ja noch in eine simple Formel eingesetzt werden) in eine andere Textdatei zu schreiben. Einzelne Zeichen kann ich ja mit
"fgetc"
entnehmen, aber eine Zeichenkette?
Das ganze könnte man doch in eine Schleife setzen (welche mit EOF abbricht) um alle Werte zu entnehmen?

Könnt ihr mir evtl. Tipps/Anregungen geben mit was ich das machen könnte?
Freue mich über jegliche Hilfestellung/links etc etc.


Vielen dank im voraus!

Grüße


p.s. habe es auch in einm anderen froum gepostet. ich hoffe das geht klar.
 
Du hast - wie immer - mehrere Möglichkeiten:
1. Das ganze in PERL schreiben, das ist für solche Sachen ideal (PERL heißt Practical Extraction and Report Language). Da kannst du die Datei dann zeilenweise auslesen und mit regulären Ausdrücken bearbeiten.
2. Wenn Du bei C/C++ bleiben willst, dann verwende C++. Dort kannst Du mit den Stream-Klassen recht einfach Werte einlesen und die dann weiterverarbeiten.
3. Wenn Du das unbedingt mit C machen willst, dann liest Du erst mal zeichenweise ein bis Du in der 6.Zeile angelangt bist (nach dem 5. '\n'). Dann bist Du an der Position der ersten Zahl. Ab hier machst Du in einer Schleife folgendes:
- zeichenweise lesen bis zum ersten Leerzeichen (die Zahl wird nicht gebraucht, also überlesen)
- zeichenweise lesen bis zur nächsten Zahl (in Deinem Beispiel 1 Leerzeichen überlesen)
- zeichenweise lesen bis zum nächsten Leerzeichen und Zeichen in einen Puffer speichern
- Inhalt des Puffers in eine double-Variable umwandeln (mit atof(...)) und Puffer wieder leeren
- zeichenweise lesen bis zum Zeilenende und Zeichen in einen Puffer speichern
- Inhalt des Puffers in eine double-Variable umwandeln und Puffer wieder leeren
- mit den 2 double-Variablen die Berechnung anstellen und Ergebnis in die Ausgabedatei schreiben
- Schleife von vorne beginnen
Das machst Du bis das Dateiende erreicht ist.
 
Hier noch ein Programmvorschlag in C++:
Code:
#include <fstream>
#include <sstream>
#include <string>

using namespace std;

int main(int argc, char* argv[])
{
	//argumente prüfen
	if (argc < 3) return -1;

	string strLine;
	double d1, d2, d3, dOut;
	int iLineCount = 0;

	//Dateien öffnen
	ifstream in(argv[1]);
	if(!in) return -2;
	ofstream out(argv[2]);
	if(!out) return -3;

	//Datei lesen
	do
	{
		//Zeile einlesen
		getline(in, strLine);
		//alles OK?
		if(in)
		{
			//alles OK!
			//Zeile zählen
			iLineCount++;
			if(iLineCount > 5)
			{
				//ab 6. Zeile
				//Kommata durch Punkte ersetzen
				for(string::iterator itStr = strLine.begin(); itStr != strLine.end(); itStr++)
					if((*itStr) == ',') (*itStr = '.');
				//string in stringstream kopieren
				stringstream ssLine(strLine);
				//Zahlen aus stringstream auslesen
				ssLine >> d1 >> d2 >> d3;
				//Berachnung durchführen
				dOut = d2 * d3;
				//Genauigkeit der Ausgabe setzen
				out.precision(20);
				//Ergebnis ausgeben
				out << "Ergebnis Zeile " << iLineCount << ": " << dOut << endl;
			}
		}
	//bis Dateiende oder Fehler
	}while(in);

	return 0;
}
 
danke jokey2,

also PERL wäre für mich völlig neu, sodass ich bei C/C++ bleibn möchte.

Leider hatten wir in der Schule nur C sodass auch C++ mit einigen Befehlen/Funktionenn neu für mich ist. Aber wie man sieht sind meine C-Kenntnisse auch sehr bschränkt um es mal milde auszudrücken.

Also was ich schelecht verständlich ausgedrückt habe, war das dieser Textblock sich periodisch wiederholt:

Zyklische Erfassung Spitzenwertmessung_-1820N Zeit: 18,078613 Sec 22.01.2003 19:00:38
Gespeichert bei: 200 Zyklus Gespeichert für: 3 Segmente
Punkte: 2
Zeit Vertikal Weg Vertikal Kraft
Sec mm N
11,550537 -0,073262166 -2303,3469
11,588135 0,09793396 -234,5567

Also es geht dann wieder mit einem neuen Block weiter.

Zyklische Erfassung Spitzenwertmessung_-1820N Zeit: 18,078613 Sec 22.01.2003 19:00:38
Gespeichert bei: 200 Zyklus Gespeichert für: 3 Segmente
Punkte: 2
Zeit Vertikal Weg Vertikal Kraft
Sec mm N
11,550537 -0,073262166 -2303,3469
11,588135 0,09793396 -234,5567


etc. etc.


Ich möchte nochmal auf deinen Tipp mit der Art wie du es mit C machen würdest zu sprechen kommen.

Meinst du ich soll es mit "getc" zeichenweise einlesen? Wie soll dann die Bedingung sein, dass es nach dem 5. '\n' in der Zeile weitermacht?
Und das mit dem "Puffer" muss ich zugeben, verstehe ich auchnicht ganz.

Werde mir aber dennoch das mit dem fstream ansehen, wenn du meint es geht leichter.

Ist jemandem bekannt, ob es einen ähnlichen Quelltext schon irgendwo gibt? Ich komme damit besser klar wenn ih die Quelltexte vor mir habe.

Danke für eure Hilfe.

Grüße
 
Hallo,

habe mir das jetzt angesehen und denke ich kann dem folgen.
Aber wie zige ich dem programm welche Datei er zum lesen/schreiben öffnen soll?

mein problem ist das verständnis von diesen zeilen:

Code:
int main(int argc, char* argv[])

und

Code:
ifstream in(argv[1]);
	if(!in) return -2;
	ofstream out(argv[2]);
	if(!out) return -3;

ich geben hie rja keine datinamn an. also in C würde ich da an "gets" oder "scanf" denken, um sie einzulesen.

komme mit dem argc und argv nicht klar.

vielen dank!

grüße
 
Die Parameter der main-Funktion sind folgende:
argc: Anzahl der dem Programm beim Aufruf (Kommandozeile) übergebenen Parameter. Da der erste Parameter immer der Programmname ist, ist argc immer mindestens 1.
argv: Ein Array von char*, welches die Parameter enthält. argv[0] ist also immer der Programmname.

Ich habe in meinem Beispiel vorausgesetzt, das dem Programm beim Aufruf der Name der zu lesenden Datei als 1. Parameter und der Name der Ausgabedatei als 2. Parameter übergeben wird.

Mit
Code:
ifstream in(argv[1])
lege ich ein Objekt der Klasse ifstream (eine C++ Eingabe-Dateiklasse) mit dem Name 'in' an. Ich übergebe ihr gleich den Namen der zu lesenden Datei, damit sie gleich bei der Objekterzeugung geöffnet wird.

Mit
Code:
if(!in)...
prüfe ich, ob das Öffnen geklappt hat. Die Objekte der fstream-Klasse (Oberklasse von ifstream und ofstream) können so auf ihren Status getestet werden. Wenn alles OK ist, liefern sie true zurück, sonst false.

Mit
Code:
ofstream out(argv[2])
mache ich das gleiche wie bei 'in', nur daß es sich bei 'ofstream' um eine Ausgabedatei handelt und der Name der Ausgabedatei übergeben wird.

Ich habe das Programm etwas abgeändert, so daß jetzt die Dateinamen auch eingegeben werden können, wenn keine Parameter übergeben werden. Außerdem liest es jetzt die Blöcke, wie Du es in Deinem letzten Post angegeben hast. Der Blockanfang wird durch das Wort 'Zyklische' markiert.

Code:
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>

using namespace std;

int main(int argc, char* argv[])
{
    string strFileIn, strFileOut;
    string strLine, strTest;
    double d1, d2, d3, dOut;
    int iLineCount = 0, iBlockCount = 0;

    //argumente prüfen
    if (argc < 3)
    {
        //keine oder zuwenig Parameter angegeben -> nach den Dateinamen fragen
        cout << "Eingabedatei angeben: ";
        cin >> strFileIn;
        cout << endl;
        cout << "Ausgabedatei angeben: ";
        cin >> strFileOut;
        cout << endl;
    }
    else
    {
        //Dateinamen aus Parameter-Array übernehmen
        strFileIn = argv[1];
        strFileOut = argv[2];
    }

    //Dateien öffnen
    ifstream in(strFileIn.c_str());
    if(!in) return -2;
    ofstream out(strFileOut.c_str());
    if(!out) return -3;

    //Datei lesen
    do
    {
        //Zeile einlesen
        getline(in, strLine);
        //alles OK?
        if(in)
        {
            //alles OK, kein Fehler aufgetreten und Datei noch nicht zu Ende
            //string in stringstream kopieren
            stringstream ssLine(strLine);
            ssLine >> strTest;
            //Wenn das 1. Wort 'Zyklische' ist, Zeilenzähler zurücksetzen und Blockzähler erhöhen
            if(strTest == "Zyklische")
            {
                iLineCount = 0;
                iBlockCount++;
                out << "Block " << iBlockCount << ":" << endl;
            }
            //Zeile zählen
            iLineCount++;
            //Wenn Zeile leer ist, nichts machen
            if(strLine.empty())
                continue;
            if(iLineCount > 5 && iBlockCount > 0)
            {
                //ab 6. Zeile
                //Kommata durch Punkte ersetzen
                for(string::iterator itStr = strLine.begin(); itStr != strLine.end(); itStr++)
                    if((*itStr) == ',') (*itStr = '.');
                //string in stringstream kopieren
                stringstream ssLine(strLine);
                //Zahlen aus stringstream auslesen
                ssLine >> d1 >> d2 >> d3;
                //Berachnung durchführen
                dOut = d2 * d3;
                //Genauigkeit der Ausgabe setzen
                out.precision(20);
                //Ergebnis ausgeben
                out << "Ergebnis Zeile " << iLineCount << ": " << dOut << endl;
            }
        }
    //bis Dateiende oder Fehler
    }while(in);

    return 0;
}
 
Hallo jokey2,


also ich muss sagen, ich finde es unglaublich wie viel Mühe du dir gegeben hast! Vielen Dank für deine Hilfe und mach weiter so! :)


Habe gerade keine Zeit aber werde mir das Programm dann mal ansehen.


Grüße
 
Hallo,

also möchte mich für den Quelltext noch mal bedanken. Habe ihn jetzt etwas abgeändert um an meine Ziele zu kommen und es läuft.

Einiges würde ich gern aber noch ändern. Hier der aktuelle gesamte Quelltext:

Code:
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <cmath>

using namespace std;

int main(int argc, char* argv[])
{
    string strFileIn, strFileOut;
    string strLine, strTest;
    double d1, d2, d3, d4, d5, d6, dOut, dQuo, c0 = 11926.309;
	double dx;
	double c1, c2, c3, c4;
    int iLineCount = 0, iBlockCount = 0;
	
    //argumente prüfen
    if (argc < 3)
    {
        //keine oder zuwenig Parameter angegeben -> nach den Dateinamen fragen
        cout << "Eingabedatei angeben: ";
        cin >> strFileIn;
        cout << endl;
        cout << "Ausgabedatei angeben: ";
        cin >> strFileOut;
        cout << endl;
    }
    else
    {
        //Dateinamen aus Parameter-Array übernehmen
        strFileIn = argv[1];
        strFileOut = argv[2];
    }

    //Dateien öffnen
    ifstream in(strFileIn.c_str());
    if(!in) return -2;
    ofstream out(strFileOut.c_str());
    if(!out) return -3;

    //Datei lesen
    do
    {
        //Zeile einlesen
        getline(in, strLine);
        //alles OK?
        if(in)
        {
            //alles OK, kein Fehler aufgetreten und Datei noch nicht zu Ende
            //string in stringstream kopieren
            stringstream ssLine(strLine);
            ssLine >> strTest;
            //Wenn das 1. Wort 'Zyklische' ist, Zeilenzähler zurücksetzen und Blockzähler erhöhen
            if(strTest == "Zyklische")
            {
                iLineCount = 0;
                iBlockCount++;
            }

            //Zeile zählen
            iLineCount++;
            //Wenn Zeile leer ist, nichts machen
            if(strLine.empty())
                continue;

			if(iLineCount == 2 && iBlockCount > 0)
            {
                //für 2. Zeile
                //string in stringstream kopieren
                stringstream ssLine(strLine);
				ssLine >> strTest;
                //Zeichenketten aus stringstream auslesen
                ssLine >> c1 >> c2 >> c3 >> c4 >> dx >> c6 >> c7 >> c8;
				out << "Block " << iBlockCount << " bei Lastwechsel " << dx << endl;
			}
                

            if(iLineCount == 6 && iBlockCount > 0)
            {
                //für 6. Zeile
                //Kommata durch Punkte ersetzen
                for(string::iterator itStr = strLine.begin(); itStr != strLine.end(); itStr++)
                    if((*itStr) == ',') (*itStr = '.');
                //string in stringstream kopieren
                stringstream ssLine(strLine);
                //Zahlen aus stringstream auslesen
                ssLine >> d1 >> d2 >> d3;
            }

			if(iLineCount == 7 && iBlockCount > 0)
            {
                //ab 7. Zeile
                //Kommata durch Punkte ersetzen
                for(string::iterator itStr = strLine.begin(); itStr != strLine.end(); itStr++)
                    if((*itStr) == ',') (*itStr = '.');
                //string in stringstream kopieren
                stringstream ssLine(strLine);
                //Zahlen aus stringstream auslesen
                ssLine >> d4 >> d5 >> d6;
                //Berechnung durchführen
                dOut = ((d6 + fabs(d3)) / (fabs(d2) + d5));
				dQuo = (dOut / c0);
                //Genauigkeit der Ausgabe setzen
                out.precision(10);
                //Ergebnis ausgeben
                out << dOut << endl;
		out << dQuo << endl;
	            }
        }
    //bis Dateiende oder Fehler
    }while(in);

    return 0;
}

Also die Rechenoperationen stimmen jetzt. Die Ergebnisse sind richtig. Wäre es noch möglich die Bearbeitung von Zeile 6. und 7. "eleganter" darzustellen (Eher unwichtig)?

Hier
Code:
if(iLineCount == 2 && iBlockCount > 0)
            {
                //für 2. Zeile
                //string in stringstream kopieren
                stringstream ssLine(strLine);
				ssLine >> strTest;
                //Zeichenketten aus stringstream auslesen
                ssLine >> c1 >> c2 >> c3 >> c4 >> dx >> c6 >> c7 >> c8;
				out << "Block " << iBlockCount << " bei Lastwechsel " << dx << endl;

versuche ich die Lastwechsel, also die hier fettgedruckte Zahl aufzunehemn da sie auschlaggebend ist. Mein Problem ist, dass ich beim einlesen der zeile zuerst das erste Wort(Zeichenkette) einlese und danach nur einzelne Zeichen.
In C gibt es ja einen Unterschied zwsichen char *c (einzelne Zeichen) und char *s (Zeichenkette bis tab, leerzeile, linefeed etc). Wie it das in C++?

Zyklische Erfassung Spitzenwertmessung_-1820N Zeit: 18,078613 Sec 22.01.2003 19:00:38
Gespeichert bei: 200 Zyklus Gespeichert für: 3 Segmente
Punkte: 2
Zeit Vertikal Weg Vertikal Kraft
Sec mm N
11,550537 -0,073262166 -2303,3469
11,588135 0,09793396 -234,5567



Auch hätte ich gern anfangs eine Abfrage, ab welchen Lastwechsel die Berechnung starten und bei welchem sie enden soll. In diesem Beispiel erhöht sich die Zahll um jeweils 100 pro "Absatz". Die Realisierung fällt mir sehr schwer.


Nun ich möchte das Ergebnis evtl. in Excel vorliegen haben, also würde ich es als .csv Datei absepeichern.

Nun müssten "Anzahl der Lastwechsel bzw. Blocknummer", "dOut" und "dQuo" nebeneinander in Excel stehen, damit man mit den daten einfach weiterarbeiten kann.

Ich habe es folgendermasßen versucht jedoch wird das Ergebnis totaler Schwachsinn:

Code:
out << "Block " << iBlockCount << " bei Lastwechsel " << dx << ";" << dOut << ";" << dQuo << endl;

Hat jemand eine Idee wie ich diese Probleme lösen kann?


Danke für eure Antworten im voraus.


Grüße
 
Hallo, das problem mit der csv Datei hat sich erledigt. Es lag an der lokalen Einstellung von Excel. Habe das jetzt geändert und es klappt wunderbar.

Jedoch komme ich nicht darauf, woran es liegt, dass beim einlesen (folgender Quelltext) an "fünfter" Stelle die gesuchte Zahl (in Antwort davoir fett gedruckt) liegt?

Wo ist der Fehler im Code?

Müsste imho doch an 3. Stelle liegen.

Also:

1.Stelle: "Gespeichert" // 2. Stelle: "bei:" // 3. Stelle (das was ich will): "200"

Kann mir jemand weiterhelfen?

Hier der Quelltext den ich meine:

Code:
if(iLineCount == 2 && iBlockCount > 0)
            {
                //für 2. Zeile
                //string in stringstream kopieren
                stringstream ssLine(strLine);
				ssLine >> strTest;
                //Zeichenketten aus stringstream auslesen
                ssLine >> c1 >> c2 >> c3 >> c4 >> dx >> c6 >> c7 >> c8;
			}
 

Neue Beiträge

Zurück