View Full Version : [C] Aiutino con fread & fwrite e array dati.
salvodel
28-11-2008, 10:14
Salve a tutti, dopo un po di ricerche infruttuose sia su google che sul forum mi ritorvo costretto a farvi una domanda su queste due funzioni.
Io devo leggere/salvare il file .dat che ho allegato(rinominato .txt per spedirlo) sfruttando solo le funzioni fread e fwrite. Precedentemente avevo fatto delle funzioni che leggevano/salvavano il file con fscanf/fprintf ma adesso devo utilizzare queste funzioni. Ho fatto le mie belle funzioncine ma ho dei risultati sbagliati. Potreste darmi una manina :help: ? Grazie
Queste sono le funzioni
int readPESI(double *p_ID, int dimens)
{
FILE *pFile;
double buffer;
int punti;
pFile = fopen ( "pesi.dat" , "rb" );
if (pFile==NULL) {fputs ("File error",stderr); exit (1);}
punti = fread (p_ID,sizeof(double),dimens,pFile);
if (punti != dimens) {fputs ("Errore letture",stderr); exit (3);}
return punti;
}
int writeOUTPUT(double *buffer, int punti)
{
FILE *pFile;
pFile = fopen("myfile.dat","wb" );
fwrite (buffer ,sizeof(double), punti, pFile);
fclose (pFile);
return 0;
}
salvodel
28-11-2008, 15:35
Nessuno mi da un aiutino :cry: ? Ora succede una cosa strana. Vi posto il mio programma:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <float.h>
int readFILE(double *p_ID, int dimens)
{
FILE *pFile;
int punti;
pFile = fopen ( "pesi.dat" , "rb" );
if (pFile==NULL) {fputs ("File error",stderr); exit (1);}
// copy the file into the buffer:
punti = fread(p_ID,sizeof(double),dimens,pFile);
if (punti != dimens) {fputs ("Reading error",stderr); exit (3);}
return punti;
}
int writeOUTPUT(double *buffer, int punti)
{
FILE *pFile;
pFile = fopen("myfile.dat","wb" );
fwrite (buffer ,sizeof(double), punti, pFile);
fclose (pFile);
return 0;
}
int main()
{
double *p_ID;
int punti,i;
int dimens;
dimens=20;
p_ID =(double *)calloc(dimens,sizeof(double));
if (p_ID == NULL) {fputs ("Memory error",stderr); exit (2);}
punti=readFILE(p_ID, dimens);
for(i=0;i<punti;i++)
printf("p_ID[%d]=%g\n",i,p_ID[i]);
writeOUTPUT(p_ID, punti);
system("PAUSE");
return 1;
}
Il mio programma legge il file ma quando faccio la printf di p_ID vedo dei numeri casuali ma quando apro il file che ho salvato vedo i numeri giusti MA solo e sempre la metà di dimens. Mi spiego: se gli dico di legere 20 numeri lui mi legge 20 numeri, mi plotta 20 numeri sbagliati ma salva 10 numeri corretti. Perché fa cosi :confused: ? Un aiutino :help: ! Non riesco a capire :muro: !
Grazie
Quello è un file di testo e non può essere letto con fread. O meglio, volendo puoi leggere il buffer testuale e poi trasformarlo in double, ma non ha senso.
Per leggere con fread il file deve essere binario quindi ci deve essere memorizzata la rappresentazione in memoria di ogni double.
salvodel
28-11-2008, 17:16
Quello è un file di testo e non può essere letto con fread. O meglio, volendo puoi leggere il buffer testuale e poi trasformarlo in double, ma non ha senso.
Per leggere con fread il file deve essere binario quindi ci deve essere memorizzata la rappresentazione in memoria di ogni double.
Come sempre grazie mille.
Comunque, premesso che devo,:cry:, utilizzare fread/fwrite(anzi a dire il vero delle varianti DOS_fread/DOS_write) cosa mi consigli di fare:
1 - leggere i numeri come testo con fread e poi convertirli in numeri
2 - aprire i file *.dat in Octave o Matlab e salvarli come file binari
grazie cionci
Allora leggiti la stringa fino allo spazio, o se le colonne sono predefinite leggi subito la dimensione corretta in un vettore di stringhe e poi ci aggiungi in fondo il carattere di fine stringa.
salvodel
28-11-2008, 21:24
Allora leggiti la stringa fino allo spazio, o se le colonne sono predefinite leggi subito la dimensione corretta in un vettore di stringhe e poi ci aggiungi in fondo il carattere di fine stringa.
Aspetta, aspetta... mi sono perso su come mi consigli di fare. I file sono caratterizzati da un numero di colonne note ma tu cosa intendi per predefinite? Spaziatura, tab, numero di cifre che compongono il numero?
Non mi abbandonare :ave: durante questo week-end!
Vincenzo1968
28-11-2008, 21:45
Ciao,
ogni file contiene, sempre, per ogni riga, due numeri separati da spazio? O il formato varia da file a file?
Stavo pensando di gestire la cosa con un automa a stati finiti(niente di complicato, lo vedrai quando posterò il codice).
:bimbo:
salvodel
28-11-2008, 23:37
Ciao,
ogni file contiene, sempre, per ogni riga, due numeri separati da spazio? O il formato varia da file a file?
Stavo pensando di gestire la cosa con un automa a stati finiti(niente di complicato, lo vedrai quando posterò il codice).
:bimbo:
Ciao Vincenzo, grazie per l'interessamento ma volevo precisare una cosa: il codice più che semplice non deve utilizzare particolari funzioni. Io ad esempio avevo fatto gia tutto con delle semplicissime fscanf/fprintf e tutto andava lisssio come con Casadei. Ora devo utilizzare un ambiente in FreeDOS e ci sono alcuni limiti...tra cui il fatto di dover utilizzare solo fread/fwrite.
Aspetto con impazienza il tuo codice.
Buonanotte
Aspetta, aspetta... mi sono perso su come mi consigli di fare. I file sono caratterizzati da un numero di colonne note ma tu cosa intendi per predefinite? Spaziatura, tab, numero di cifre che compongono il numero?
Non mi abbandonare :ave: durante questo week-end!
Numero di cifre fisse, un valore è composto da un numero di cifre e altri caratteri fissi ?
Anzi, facciamo prima, la lunghezza della riga è fissa ?
In tal caso conta la dimensione dei caratteri sulla riga, aggiungici un +4 in fondo (+1 per lo spazio, +1 per \r, +1 per \n, +1 per il carattere di fine stringa). Dovrebbe venire fuori 14 * 2 + 4 = 32
Leggi 31 byte con fread mettendoli direttamente nel vettore. Inserisci alla posizione 31 il carattere '\0'.
Usa sscanf per convertire i due numeri in double leggendo con lo specificatore "%Le %Le".
salvodel
29-11-2008, 10:56
Buongiorno cionci per adesso sto facendo cosi:
funzione Matlab
[fnome percorso]=uigetfile('*.dat','Scegli il file da convertire');
dati=load([percorso fnome]).';
fid = fopen('pesi.bin', 'wb');
fwrite(fid, dati, 'double');
fclose(fid);
le funzioni C rimangono uguali a quelle che ho postato prima e poi in matlab rifaccio la conversione:
fid = fopen('pesi.bin', 'rb');
dati = fread(fid, 'double');
fclose(fid);
Il dubbio che io non possa utilizzare sscanf. Non posso utilizzare la printf perché è definita troppo lenta e di conseguenza non vorrei che la ssprintf essendo della stessa famiglia abbia gli stessi problemi. Per adesso ho verificato non andare bene la printf e fprintf.
Grazie
PS
L'utilizzo della funzione atof ha senso? Non vorrei aver capito male come funziona.
Vincenzo1968
29-11-2008, 15:34
Ciao Vincenzo, grazie per l'interessamento ma volevo precisare una cosa: il codice più che semplice non deve utilizzare particolari funzioni. Io ad esempio avevo fatto gia tutto con delle semplicissime fscanf/fprintf e tutto andava lisssio come con Casadei. Ora devo utilizzare un ambiente in FreeDOS e ci sono alcuni limiti...tra cui il fatto di dover utilizzare solo fread/fwrite.
Aspetto con impazienza il tuo codice.
Buonanotte
Ciao,
sono stato giustamente richiamato dal moderatore: non si possono postare soluzioni complete. Rimango dell'idea che un automa a stati finiti sia l'ideale per questo tipo di problemi(considerando anche l'efficienza, in termini, dico, di velocità di esecuzione). Se vuoi ti posso spiegare come funziona. Non c'è bisogno di utilizzare particolari funzioni; soltanto loop & switch ;)
:bimbo:
salvodel
29-11-2008, 15:47
Mi dispiace che il moderatore ti abbia richiamato. Vorrei fare una precisazione, precedentemente avevo risolto la lettura dei file in altro modo adesso mi trovo costretto ad utilizzare fread e di conseguenza ho dovuto cambiare approccio.
A questo punto penso che avrebbe fatto comodo avere una soluzione piu autarchica come la tua piuttosto che fare la gabola di utilizzare un programma per convertire i dati.
Mi farebbe piacere sapere la tua soluzione ma non voglio farti avere problemi con il moderatore. Forse l'algoritmo in pseudocodice si puo postare ma vedi cosa ne pensa cionci. Per adesso devo andare avanti con questa strada.
Grazie ciao
Vincenzo1968
29-11-2008, 15:53
Mi dispiace che il moderatore ti abbia richiamato. Vorrei fare una precisazione, precedentemente avevo risolto la lettura dei file in altro modo adesso mi trovo costretto ad utilizzare fread e di conseguenza ho dovuto cambiare approccio.
A questo punto penso che avrebbe fatto comodo avere una soluzione piu autarchica come la tua piuttosto che fare la gabola di utilizzare un programma per convertire i dati.
Mi farebbe piacere sapere la tua soluzione ma non voglio farti avere problemi con il moderatore. Forse l'algoritmo in pseudocodice si puo postare ma vedi cosa ne pensa cionci. Per adesso devo andare avanti con questa strada.
Grazie ciao
No no, per me non è un problema avere problemi col moderatore. Sapessi le parolacce che ci scambiamo in pvt ;)
Prova a seguire i suggerimenti di Cionci(il moderatore in questione ;)) e posta, man mano, il codice. Poi, in caso di problemi, possiamo aiutarti a sistemarlo.
;)
:bimbo:
L'utilizzo della funzione atof ha senso? Non vorrei aver capito male come funziona.
Ha senso, ma devi leggere un numero alla volta o "giocare" con la stringa, passando la seconda lettura il puntatore alla stringa aggiungendo 15.
salvodel
29-11-2008, 23:31
Siccome le cose non vogliono mai andarmi lisci mi tocca tornare indietro. Con il mio metodo sembrava andare bene ma su un file più complesso ho dei problemi: la prima riga la riesco ad organizzare bene nella matrice ma a meta della seconda riga compare un numero sballato e da li in poi non corrispondo piu le colonne ed a volte ci sono anche valori sballati.
Ricapitolando cosa mi consigliate di fare? Vincenzo prima di avventurami con gli automi a stati finiti provo la soluzione di Cionci, da quel che ho capito dovrei leggere n byte per volta, giusto?
Prima vorrei un consiglio:
1.4430613e+000 3.6076467e+000_-2.6477394e-005 4.7404982e+001 3.9992000e+000 9.0209209e-001 4.0000000e-001
5.0506966e+000 3.6076293e+000__1.2055733e-006 4.7406928e+001 4.0000000e+000 9.0190732e-001 1.4000000e+000
Se capitano delle righe come questa dove il segno meno fa variare lo spazio tra due numeri come mi devo comportare? Ho frainteso il suggerimento?
Grazie, buonanotte.
Probabilmente la tua soluzione non tiene conto dei caratteri per andare capo. Aprendo il file in binario (con la b nella modalità di apertura). il carattere che manda a capo il testo è composto da due caratteri in realtà: \r e \n.
Gli spazi all'inizio te li dovrebbe ignorare atof.
Visto che non riesci a precalcolarti la dimensione dei gruppi da byte da leggere contemporaneamente allora ti consiglio anche io di leggerti un byte alla volta.
L'algoritmo è semplice:
0. NuovaParola = 0, Buffer contiene la stringa da convertire, N = 0
1. Car = Leggi un byte
2. Siamo alla fine del file ? Sì: vai al punto 5
3. Il Car è uno spazio o uno \r o uno \n: Se NuovaParola == 1 allora: esegui ConvertiInDouble(Buffer, N), NuovaParola = 0, N = 0
4. Per qualsiasi altro carattere: NuovaParola = 1, Buffer[N] = Car, N++
5. fine
ConvertiInDouble(Buffer, N) sarà semplicemente così:
1. Buffer[N] = '\0'
2. converto Buffer in double e lo aggiungo alla mia struttura dati
Ovviamente se devi tenere conto della colonna l'algoritmo sopra va modificato, ma è semplice.
Edit: poi di fatto è una macchina a stati con soli 2 stati ;) Anzi 3 se si conta la fine.
salvodel
30-11-2008, 12:17
Grazie cionci per i passi da seguire. Ho fatto un programmino in base alle tue istruzioni, mi manca sola la funzione ConvertiInDouble. La faccio con atof? Grazie.
Edit:
Non va :cry: !
Mi sa che il ciclo while non va bene.
#include <stdio.h>
#include <stdlib.h>
#define fnINPUT "vento.dat"
int ConvertiInDouble(char *buffer, double *vettore, int cont)
{
buffer[15]='\0';
vettore[cont]=atof(buffer);
return 1;
}
int main()
{
FILE *fdati;
char car;
int i,NuovaParola, N, lSize, cont, t, punti;
char *buffer;
double *vettore, **matrice;
int colonne=7;
lSize=16;//i numeri sono costituiti da 12 cifre piu segno, più "e"sponente e relativo segno. Che ne dici?
buffer = (char*) calloc(sizeof(char),lSize);
i=0; NuovaParola=0; N=0; cont=0;
fdati=fopen(fnINPUT,"r");
vettore=(double *)calloc(1,sizeof(double));
while(fread(&car,sizeof(char),1,fdati)==1)// è giusto?
{
if(car=='\r'||car=='\n'||car==' ')//lo spazio lo leggo cosi?
if(NuovaParola==1)
{
ConvertiInDouble(buffer, vettore, cont);
cont++;
vettore=(double *)realloc(vettore,(cont+1)*sizeof(double));
NuovaParola=0;
N=0;
}
else
{
buffer[N]=car;
N++;
NuovaParola=1;
}
}
punti=cont/7;
matrice = (double **)calloc(punti,sizeof(double *));
if(matrice==NULL)
printf("Righe matrice - Memoria esaurita!\n");
for(t=0; t<punti; t++)
{
matrice[t] = (double *)calloc(colonne,sizeof(double));
if(matrice[t]==NULL)
printf("Colonne matrice - Memoria esaurita! t= %d\n",t);
}
for(t=0;t<punti;t++)
for(i=0;i<colonne;i++)
matrice[t][i]=vettore[i+t*colonne];
for(t=0;t<10;t++){
for(i=0;i<colonne;i++)
printf("matrice[%d][%d]=%le\t",t,i,matrice[t][i]);
printf("\n");
}
system("PAUSE");
return 1;
}
Vincenzo1968
30-11-2008, 14:25
Dunque il numero delle colonne è variabile? Nel primo esempio ci sono due numeri per riga; nel secondo sono di più.
Un esempio di automa per un problema simile al tuo:
http://www.hwupgrade.it/forum/showthread.php?t=1816511
:bimbo:
salvodel
30-11-2008, 15:10
Dunque il numero delle colonne è variabile? Nel primo esempio ci sono due numeri per riga; nel secondo sono di più.
Un esempio di automa per un problema simile al tuo:
http://www.hwupgrade.it/forum/showthread.php?t=1816511
:bimbo:
Premesso che mi sono ammazzato a leggere la discussione,(non oso immaginare in che directory mi hai messo :D ) il problema è che potrebbe non andare bene per me nel senso che ci sono alcune funzioni che non ho testato e non so se ci sono, in particolare fseek e ftell. Ora provo se funzionano e poi riprovo il tuo codice.
Grazie
Vincenzo1968
30-11-2008, 15:28
Premesso che mi sono ammazzato a leggere la discussione,(non oso immaginare in che directory mi hai messo :D )
:D tranquillo, non ti ho messo in nessuna directory.
il problema è che potrebbe non andare bene per me nel senso che ci sono alcune funzioni che non ho testato e non so se ci sono, in particolare fseek e ftell. Ora provo se funzionano e poi riprovo il tuo codice.
Grazie
ftell e fseek sono funzioni standard. Dovrebbero esserci ;)
:bimbo:
salvodel
30-11-2008, 15:56
Purtroppo non sono in un ambiente "standard" altrimenti avrei utilizzato come facevo primo la fscanf :muro: . Cmq ho provato il tuo programma non funziona con i miei dati. Non so che fare :mc: .
Grazie cionci per i passi da seguire. Ho fatto un programmino in base alle tue istruzioni, mi manca sola la funzione ConvertiInDouble. La faccio con atof? Grazie.
Va bene atof...dici che la scanf è più lenta ed usi una realloc ??? La realloc è lentissima, alloca a blocchi di K double oppure usa una lista e dopo li metti tutti un vettore.
Per la correttezza: ma lo usi un debugger ? In tal caso dovresti sapere anche dove si trova l'errore.
Per la fread: http://www.cplusplus.com/reference/clibrary/cstdio/fread.html
In ogni caso è sbagliato questo:
buffer[15]='\0';
Perché secondo te passavo N alla funzione ?
In goni caso non hai riportato fedelmente il punto 4 del mio algoritmo. Rileggilo bene.
salvodel
30-11-2008, 16:41
In goni caso non hai riportato fedelmente il punto 4 del mio algoritmo. Rileggilo bene.
In quel punto mi dicevi di fare
Per qualsiasi altro carattere: NuovaParola = 1, Buffer[N] = Car, N++
{
buffer[N]=car;
N++;
NuovaParola=1;
}
non riesco a vedere l'errore, cambia solo l'ordine ed in ogni caso NuovaParola non mi servi qui ma nel if dopo quindi non penso che sia quello l'errore a cui ti riferisci. E' nel else?
Per quanto riguarda la fread, neanche qui ho trovato l'errore:
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
Lo so che sono una capra ma nella prima posizione c'è il puntatore ad una blocco di memoria per un char, nel secondo la dimensione del char, nel terzo quanti ne voglio leggere ed infine il puntatore al file. Dovrebbe ristiuire il numero di elementi letti ed ecco perche io ho messo quel while poiche mi deve dare sempre 1 tranne nel caso in cui non legge.
Dove sbaglio :help: !
Infatti l'fread dovrebbe andare bene ;)
L'else non va bene perché viene valutato solo se hai letto un carattere fra ' ', '\n' e '\r'. Invece l'else deve essere valutato per "Per qualsiasi altro carattere" diverso da ' ', '\n' e '\r'.
salvodel
30-11-2008, 16:57
Infatti l'fread dovrebbe andare bene ;)
L'else non va bene perché viene valutato solo se hai letto un carattere fra ' ', '\n' e '\r'. Invece l'else deve essere valutato per "Per qualsiasi altro carattere" diverso da ' ', '\n' e '\r'.
L'avevo trovato...ma sotto linux. Mi diceva che era un po ambigua scritta cosi ed adesso l'ho corretta ma mi da un segmentation foult che MVC mi pialla in pieno: mi è capitato spesso che mi "correggesse" errori in modo arbitrario.
Ora indago meglio sotto linux e poi ti faccio sapere.
L'avevo trovato...ma sotto linux. Mi diceva che era un po ambigua scritta cosi ed adesso l'ho corretta ma mi da un segmentation foult che MVC mi pialla in pieno: mi è capitato spesso che mi "correggesse" errori in modo arbitrario.
Ora indago meglio sotto linux e poi ti faccio sapere.
Non ho capito :confused:
Vincenzo1968
30-11-2008, 20:28
Salve a tutti, dopo un po di ricerche infruttuose sia su google che sul forum mi ritorvo costretto a farvi una domanda su queste due funzioni.
Io devo leggere/salvare il file .dat che ho allegato(rinominato .txt per spedirlo) sfruttando solo le funzioni fread e fwrite. Precedentemente avevo fatto delle funzioni che leggevano/salvavano il file con fscanf/fprintf ma adesso devo utilizzare queste funzioni. Ho fatto le mie belle funzioncine ma ho dei risultati sbagliati. Potreste darmi una manina :help: ? Grazie
Dunque non ti serve caricare un array di double(o float) in memoria? Se non devi elaborare i numeri ma creare una semplice copia del file originale, puoi fare semplicemente così:
#define BUFFER_SIZE 4096
void CopiaFile(const char *szFileInput, const char *szFileOutput)
{
FILE *fp1, *fp2;
unsigned char buffer[BUFFER_SIZE];
int numread;
fp1 = fopen(szFileInput, "rb");
if ( fp1 == NULL )
{
printf("Errore nell'apertura del file %s\n", szFileInput);
return;
}
fp2 = fopen(szFileOutput, "wb");
if ( fp2 == NULL )
{
printf("Errore nell'apertura del file %s\n", szFileOutput);
return;
}
numread = fread(buffer, 1, BUFFER_SIZE, fp1);
while ( numread )
{
fwrite(buffer, 1, numread, fp2);
numread = fread(buffer, 1, BUFFER_SIZE, fp1);
}
fclose(fp1);
fclose(fp2);
}
salvodel
01-12-2008, 08:27
Infatti l'fread dovrebbe andare bene ;)
Non fare piu questi scherzi!:ahahah: Che fai come i prof quando sbagliano che dicono: "Volevo vedere se stavate attenti!"
Non ho capito :confused:
Scusa se rispondo solo ora ma ho avuto problemi di linea: cmq non andava per uno stupido errore su un indice. Ora va alla grande.
Grazie.
Dunque non ti serve caricare un array di double(o float) in memoria? Se non devi elaborare i numeri ma creare una semplice copia del file originale, puoi fare semplicemente così:
No, io devo leggere dei numeri da le aborare ma li posso leggere solo con fread: li leggo come caratteri solo per questo motivo, se potessi utilizzare fscanf("%le") avrei gia finito da un pezzo visto che fino ad ora facevo cosi. Cmq grazie ad entrambi per avermi seguito ed aiutato.
PS
Forse tra poche ore torno con il problema inverso: fwrite. :Prrr:
Non fare piu questi scherzi!:ahahah: Che fai come i prof quando sbagliano che dicono: "Volevo vedere se stavate attenti!"
Ho visto che avevi dubbi su fread e nella documentazione c'è scritto in modo chiaro cosa ritorna in caso di successo ;)
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.