Προς το περιεχόμενο

Εισαγωγή text file στη c


makis89

Προτεινόμενες αναρτήσεις

Καλημέρα....Θα ήθελα τη βοήθειά σας ...

 

Θέλω να γράψω ένα πρόγραμμα στη c που θα ανοίγει ένα αρχείο txt το οποίο θα είναι στην ακόλουθη μορφή:

 

12345,fdafaaf,sdfsaf

 

Δηλαδή θα έχουμε int,string,string

Εγώ θέλω να διαβάσω κάθε αντικείμενο ανάμεσα στα κόμματα χωριστά. Για παράδειγμα θέλω τον ακέραιο να τον αποθηκεύσω σε μία μεταβλητή, το fdafaaf σε ένα string κλπ

 

Αυτό που ρωτάω είναι πώς μπορώ να πάρω κάθε αντικείμενο που βρίσκεται ανάμεσα σε κόμματα ;

 

Σκέφτηκα να περάσω όλη τη γραμμή σε ένα string, και με ένα for να ξεχωρίσω κάθε τι που είναι ανάμεσα στα κόμματα...αλλά μήπως υπάρχει καμιά πιο εύκολη λύση ;

 

Ευχαριστώ !

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Καλημέρα....Θα ήθελα τη βοήθειά σας ...

 

Θέλω να γράψω ένα πρόγραμμα στη c που θα ανοίγει ένα αρχείο txt το οποίο θα είναι στην ακόλουθη μορφή:

 

12345,fdafaaf,sdfsaf

 

Δηλαδή θα έχουμε int,string,string

Εγώ θέλω να διαβάσω κάθε αντικείμενο ανάμεσα στα κόμματα χωριστά. Για παράδειγμα θέλω τον ακέραιο να τον αποθηκεύσω σε μία μεταβλητή, το fdafaaf σε ένα string κλπ

 

Αυτό που ρωτάω είναι πώς μπορώ να πάρω κάθε αντικείμενο που βρίσκεται ανάμεσα σε κόμματα ;

 

Σκέφτηκα να περάσω όλη τη γραμμή σε ένα string, και με ένα for να ξεχωρίσω κάθε τι που είναι ανάμεσα στα κόμματα...αλλά μήπως υπάρχει καμιά πιο εύκολη λύση ;

 

Ευχαριστώ !

 

Καλημέρα ο παρακάτω κώδικας ανοίγει ένα αρχείο κειμένου το οποίο βρίσκεται στην μορφή που μας έδωσες και τεμαχίζει τα περιεχόμενα κάθε γραμμής με βάση το "," αποθηκεύοντας τα επιμέρους κομμάτια σε ένα πίνακα δομών για ξεχωριστή προσπέλαση κάθε φορά. Έτσι αποθηκεύω αλλού τον αριθμό, αλλού το πρώτο string και αλλού το δεύτερο string. To περιβάλλον υλοποίησης είναι ο C++ Builder 2007 σε Windows XP Pro SP2.

 

>
//---------------------------------------------------------------------------

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

#define BUFSZ 256
#define TOKENS 3

/* Seperator. */

const char *seperator = ",";

typedef struct _Line
{
int LineNumber;
char *LBuffer;
char *NLBuffer;
}Line;

#pragma hdrstop

//---------------------------------------------------------------------------
/* Functions. */
void _perror(const char *Msg)
{
printf("ERROR:%s\n", Msg ? Msg : "NULL Message.");
}

int GetLineFromFile(const char *filename, int *Cnt, Line **ptrLine)
{
if(!filename)
{
	_perror("Invalid File Name.");
	return -1;
}
else
{
	FILE *fileptr = NULL;
	if((fileptr = fopen(filename, "rt")) == NULL)
	{
		_perror("Open File.");
		return -2;
	}
	else
	{
		/* Basic Variables. */
		char *tokenPtr = NULL;
		char *TBuffer = NULL;
		Line *Lineptr = NULL;
		/* Case Status. */
		int nCase = 0, jDx = 0;
		/* Error Checking. */
		static int nError = 0;
		/* Get Memory. */
		if((TBuffer = calloc(BUFSZ, sizeof(char))) == NULL)
		{
			_perror("Memory Fault.");
			/* Close File. */
			fclose(fileptr);
			return -3;
		}
		if((Lineptr = malloc(sizeof(Line))) == NULL)
		{
			_perror("Memory Fault.");
			/* Free memory. */
			free(TBuffer);
			fclose(fileptr);
			return -4;
		}
		else
		{
			while(fgets(TBuffer, BUFSZ, fileptr) != NULL)
			{
				if(TBuffer[strlen(TBuffer)-1] == '\n')
					TBuffer[strlen(TBuffer)-1] = '\0';

				tokenPtr = strtok(TBuffer,seperator);
				if(!tokenPtr)
				{
					nError = 1;
					_perror("Invalid Text Line Type.");
					break;
				}
				else
				{
					while(tokenPtr && nCase < TOKENS)
					{
						switch(nCase)
						{
							case 0:
								sscanf(tokenPtr, "%d", &Lineptr[jDx].LineNumber);
								break;
							case 1:
								Lineptr[jDx].LBuffer = strdup(tokenPtr);
								break;
							case 2:
								Lineptr[jDx].NLBuffer = strdup(tokenPtr);
								break;
						default:
						   break;
						}
						tokenPtr = strtok(NULL, seperator);
						/* Advance Case Status. */
						nCase++;
					}
				}
				/* Advance jDx. */
				jDx++;
				/* Zero nCase. */
				nCase = 0;
				/* Clear TBuffer. */
				memset(TBuffer, 0 , strlen(TBuffer));
				/* Realloc Line. */
				Lineptr = realloc(Lineptr, (jDx+1) * sizeof(Line));
			}
			if(nError)
			{
				free(TBuffer);
				free(Lineptr);
				fclose(fileptr);
				return -4;
			}
			/* EXIT SUCCESS. */
			else
			{
				/* Return Values. */
				*ptrLine = Lineptr;
				*Cnt = jDx;
				free(TBuffer);
				fclose(fileptr);
				return 0;
			}
		}
	}
}
}

#pragma argsused
int main(int argc, char* argv[])
{
int i,nCnt = 0;
Line *ptrLine = NULL;

if(!GetLineFromFile("file.txt", &nCnt, &ptrLine))
{
	for(i = 0; i < nCnt; i++)
		printf("NumberRead:%d\nFirstStringRead:\"%s\"\nSecondStringRead:\"%s\"\n\n"
		, ptrLine[i].LineNumber, ptrLine[i].LBuffer, ptrLine[i].NLBuffer);
}
printf("Hit Enter to continue...");
getchar();
return 0;
}
//---------------------------------------------------------------------------

 

Για να τρέξεις το πρόγραμμα δημιούργησε ένα άδειο project σε C, κάνε copy-paste στο άδειο αρχείο του project και δημιούργησε στο φάκελο Debug του project ένα αρχείο με το όνομα file.txt και δώσε του πληροφορίες.

 

Παράδειγμα Αρχείου file.txt:

 

3,nikos,androu

12,antwnis,sparoy

345,fddds,ghhhssgfg

1256,kwstas,boka

 

Εκτυπωμένα αποτελέσματα για το παράδειγμα αρχείου:

 

NumberRead:3

FirstStringRead:"nikos"

SecondStringRead:"androu"

 

NumberRead:12

FirstStringRead:"antwnis"

SecondStringRead:"sparoy"

 

NumberRead:345

FirstStringRead:"fddds"

SecondStringRead:"ghhhssgfg"

 

NumberRead:1256

FirstStringRead:"kwstas"

SecondStringRead:"boka"

 

Hit Enter to continue...

 

Bokarinho!!!

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

αν ξέρεις πως κάθε γραμμη ειναι στανταρ της μορφης

πχ <int>,<string>,<string>

 

μπορεις να χρησιμοποιησεις την sscanf ως εξης

>
// μη ξεχάσεις τα κόμματα αναμεσα στα %d,%s etc
sscanf( buffer, "%d,%s,%s", &intVar1, stringVar1, stringVar2); 

 

όπου buffer ειναι η μεταβλητη που εχει τη σειρα που διαβασες από το αρχειο, intVar1, stringVar1 κτλ ειναι οι μεταβλητες στις οποιες θες να αποθηκευεσεις τις τιμες αναμεσα στα κομματα.

 

επαναλαμβάνεις για οσες γραμμες του αρχειου θες

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ευχαριστώ πολύ και τους δύο... Τελικά το έκανα έτσι:

 

sscanf( buffer, "%d,%s,%s", &intVar1, stringVar1, stringVar2);

 

Βέβαια χρησιμοποίησα δομές αντί για μεταβλητές αλλά αυτό είναι άλλο :-D

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Τελικά έχω ακόμα πρόβλημα...

Στο .txt μου έχω μέσα int,string,string,string,string,int,int

Στην sscanf βάζω "%d,%s,%s,%s,%s,%d,%d" αλλά δεν κάνει σωστά τις αντιστοιχίες. Πχ το πρώτο int το βάζει στο αντίστοιχό του αλλά μετά, τα υπόλοιπα string τα βάζει σε ένα. Ενώ όταν αντικαταστήσω τα κόμματα με κενά δουλεύει κανονικότατα :fear:

 

Τί μπορεί να φταίει ;

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Η λογική η δική μου με το πρόγραμμα που σου έγραψα δεν σε ικανοποιούσε; Με λίγες μικρές μετατροπές μπορείς να κάνεις εύκολα αυτό που θες χωρίς να χρησιμοποιήσεις την sscanf. Τώρα δική σου υπόθεση είναι το τι θα πράξεις.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

λοιπον μια αλλη προσεγγιση

 

παρνεις μια γραμμη απο το αρχειο καθε φορα με την fgets

> 
FILE* fPtr;
char linebuffer[100];  // maximum line length 100-1
char* tmp;
...
tmp = fgets(lienbuffer,100, fPtr);
...

 

αν το tmp==NULL τοτε εφτασε στο EOF χωρις να διαβαστει χαρακτηρας. Εχεις λοιπον τωρα το linebuffer που περιεχει μια γραμμη. Εσυ ξέρεις ακριβως το format καθε γραμμης, εχεις πχ πεδια που χωριζονται με κομματα. Θα χρησιμοποιησουμε την strtok για αυτη τη δουλεια

 

πχ για <int>,<string>,<int>

 

>

while( fgets(linebuffer, 100, fPtr) != NULL)  // για καθε γραμμη
{
    char* tmp1 = strtok(linebuffer,",");  //take portion of string (token)until first comma
    intVar1 = atoi(tmp1);     // get you 1st integer
    tmp1 = strtok(NULL,",");    // get token until 2nd comma (notice that now NULL is passed as argument, meaning that we continue from where we were)
    strcpy( yourstring1, tmp1);  // copy from tmp1 (until 2nd comma)
     tmp1 = strtok(NULL,",");    // get token until the end
    // now get the 2nd integer (after the 2nd comma)
    intVar2 = atoi(tmp1);
}

 

ο κωδικας ειναι απο το μυαλο μου οποτε μπορει να εχει λαθη αλλα ειμαι στη δουλεια τωρα. Κοιτα το documentation της strtok, και customarise τον κωδικα για το δικο σου format

 

ps. η λυση ειναι παρομοια με αυτη του bokarinho , απλα στο εκανα πολυ λιανά ωστε να φτιαξεις κατι που καλυπτει τις αναγκες σου

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Τελικά έχω ακόμα πρόβλημα...

Στο .txt μου έχω μέσα int,string,string,string,string,int,int

Στην sscanf βάζω "%d,%s,%s,%s,%s,%d,%d" αλλά δεν κάνει σωστά τις αντιστοιχίες. Πχ το πρώτο int το βάζει στο αντίστοιχό του αλλά μετά, τα υπόλοιπα string τα βάζει σε ένα. Ενώ όταν αντικαταστήσω τα κόμματα με κενά δουλεύει κανονικότατα :fear:

 

Τί μπορεί να φταίει ;

 

H sscanf με %s στο fromat string θα διαβάσει ένα string μέχρι να βρει κενό. Μπορείς να καθορίσεις διαφορετική συμπεριφορά χρησιμοποιόντας τα [] αντί για το s. Για παράδειγμα η %[Α-z] θα διαβάσει μόνο τους χαρακτήρες από το Α μέχρι το z (που σημαίνει ότι αν βρεί διαφορετικό χαρακτήρα θα σταματήσει). Στην περίπτωση σου βολεύει να καθορίσεις ποιόν χαρακτήρα δεν θα διαβάσει (εδώ το ',') βάζοντας %[^,] (το string μπορεί να περιέχει οποιοδήποτε χαρακτήρα, συμπεριλαμβανομένου και του κενού, εκτός από το κόμμα)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

H sscanf με %s στο fromat string θα διαβάσει ένα string μέχρι να βρει κενό. Μπορείς να καθορίσεις διαφορετική συμπεριφορά χρησιμοποιόντας τα [] αντί για το s. Για παράδειγμα η %[Α-z] θα διαβάσει μόνο τους χαρακτήρες από το Α μέχρι το z (που σημαίνει ότι αν βρεί διαφορετικό χαρακτήρα θα σταματήσει). Στην περίπτωση σου βολεύει να καθορίσεις ποιόν χαρακτήρα δεν θα διαβάσει (εδώ το ',') βάζοντας %[^,] (το string μπορεί να περιέχει οποιοδήποτε χαρακτήρα, συμπεριλαμβανομένου και του κενού, εκτός από το κόμμα)

 

χαχα αυτο δεν το ηξερα, ωραιος bilco

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Μπορείς εξίσου απλά να χρησιμοποιήσεις την fscanf για να διαβάσεις τα αλφαριθμητικά και τους ακέραιους και στην συνέχεια με την χρήση της συνάρτησης strtok να αφαιρέσεις το κόμμα(,) από τα αλφαριθμητικά

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Χρειάζεται προσοχή όταν γίνετε χρήση της scanf (& family) με το %s specifier καθώς δεν γίνεται έλεγχος των ορίων του string/array προορισμού.

 

Ο σωστός τρόπος χρήσης είναι με length specifier.

 

Λάθος τρόπος:

 

>
stest.c
--------

#include <stdio.h>

int main(void) {
 char buf[10];

 scanf("%s", buf);

 printf("buf = %s\n", buf);

 return 0;
}

 

Εκτέλεση:

 

>
# gcc -Wall -O2 -W stest.c -o stest

# ./stest
sdsdsd  <== input
buf = sdsdsd

# ./stest
askldljkasdklasldkaslkdlkasd <== input = buffer overflow
buf = askldljkasdklasldkaslkdlkasd
Segmentation fault

 

Σωστός τρόπος

 

>
stest2.c
----------

#include <stdio.h>

int main(void) {
 char buf[10];

 scanf("%9s", buf);

 printf("buf = %s\n", buf);

 return 0;
}

 

Εκτέλεση:

 

>
# gcc -Wall -O2 -W stest2.c -o stest2

# ./stest2
asdasdasd <== input
buf = asdasdasd

# ./stest2
asjkdjasdasjkdaskdkasdsadjas <== input, no buffer overflow
buf = asjkdjasd

 

Το ίδιο ισχύει και για το specifier %[..]

 

Links:

 

http://securityficus.org/blog/2007/08/11/scanf-is-an-underrated-source-of-security-bugs/

http://en.wikipedia.org/wiki/Scanf

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Σας ευχαριστώ όλους...

Τα παραπάνω δεδομένα τα παίρνω από ένα αρχείο. Το αρχείο αυτό πρέπει να το ανοίγω για ανάγνωση-εγγραφή αλλά και όταν δεν υπάρχει πρέπει να το δημιουργώ. Μπορεί να γίνονται αυτά ταυτόχρονα ; Έστω ότι για το read-write βάζω mode "r+" ... Άν βάλω "w+" ώστε να δημιουργείται το αρχείο αν δεν υπάρχει, σβήνει όλα τα περιεχόμενά του.:rolleyes: Τί κάνουμε σε αυτήν την περίπτωση ; Μία σκέψη είναι ότι άν το fopen("arxeio.txt","r+") είναι NULL να κάνω ένα fopen("arxeio.txt","w+"). Είναι σωστή η λογική μου ;

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Μια απλή λύση είναι να ανοίξεις το αρχείο .txt με to notepad και να πας edit->replace. Αντικαθιστάς όλα τα κόμματα με κενό κάνοντας μόνο ένα click!!! Στη συνέχεια χρησιμοποιείς την fscanf(file,"%s %s %d",....klp). Ελπίζω να βοηθήει αυτό.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Σας ευχαριστώ όλους...

Τα παραπάνω δεδομένα τα παίρνω από ένα αρχείο. Το αρχείο αυτό πρέπει να το ανοίγω για ανάγνωση-εγγραφή αλλά και όταν δεν υπάρχει πρέπει να το δημιουργώ. Μπορεί να γίνονται αυτά ταυτόχρονα ; Έστω ότι για το read-write βάζω mode "r+" ... Άν βάλω "w+" ώστε να δημιουργείται το αρχείο αν δεν υπάρχει, σβήνει όλα τα περιεχόμενά του.:rolleyes: Τί κάνουμε σε αυτήν την περίπτωση ; Μία σκέψη είναι ότι άν το fopen("arxeio.txt","r+") είναι NULL να κάνω ένα fopen("arxeio.txt","w+"). Είναι σωστή η λογική μου ;

 

Απλά άνοιξε το να το διαβάσεις να δεις αν υπάρχει, μία ωραία συναρτησούλα να κάνει την δουλειά είναι αυτή:

>
int FileExists(const char *_filename)
{
FILE *ptrFile = NULL;
if(ptrFile = fopen(_filename, "r")) != NULL)
{
	fclose(ptrFile);
	return 1;
}
return 0;
}

 

Επιστρέφει True (διάφορο του μηδέν) αν όντως υπάρχει και False (μηδέν) αν δεν υπάρχει.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Αρχειοθετημένο

Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.

  • Δημιουργία νέου...