PDA

View Full Version : [C] I/O su file


Metal Gabber
11-01-2011, 00:35
Sì, lo so che internet è pieno di guide e topic che riguardano l'argomento, ma nessuno dei molti che ho guardato mi andava bene.

1) C'è un qualche modo per poter scrivere su un file ad una riga precisa? Sto finendo un progetto per l'università, e volevo aggiungere al mio programma un file txt per memorizzare le impostazioni del programma.
Per ora pensavo a qualcosa di semplice, tipo un numero per ogni impostazione, tutti separati da un 'a capo'.
Il problema a questo punto è che se mentre eseguo il programma vado a cambiare l'impostazione che viene memorizzata nella seconda riga del file settings.txt, non so come fare per modificare solo quella.

2) C'è un modo per leggere da un file una riga precisa? Attualmente, nel mio progetto, ho adottato questa soluzione:

//il numero della riga del file che devo leggere è memorizzata in 'sel'
int i = 0;
while(i <= sel) //finché i è <= della riga che ho scelto...
{
fscanf(file, "%s", s);//...salva in s la parola della riga corrente
i++;
}

non c'è una soluzione più elegante?

WarDuck
11-01-2011, 12:18
Secondo me ti conviene fare in modo di usare impostazioni del tipo

CHIAVE = VALORE

Magari ognuna su una linea per facilitare la lettura.

Poi le coppie (chiave, valore) puoi metterle all'interno di una mappa.

In questo modo per altro non vincoli l'utente a mettere le impostazioni in un ordine particolare.

Metal Gabber
12-01-2011, 07:15
Preferivo non usare, per ora, il metodo "chiave=valore" per evitare di dover estrarre ogni volta il valore: se tengo solo un numero l'accesso è più immediato, infatti io so già che il numero della prima riga si riferisce a una cosa, quello della seconda ad un'altra e così via.

edit: non ho capito se la tua risposta si riferiva anche alla mia seconda domanda

WarDuck
12-01-2011, 16:00
Preferivo non usare, per ora, il metodo "chiave=valore" per evitare di dover estrarre ogni volta il valore: se tengo solo un numero l'accesso è più immediato, infatti io so già che il numero della prima riga si riferisce a una cosa, quello della seconda ad un'altra e così via.

edit: non ho capito se la tua risposta si riferiva anche alla mia seconda domanda

Se usi la coppia CHIAVE=VALORE il caricamente lo fai una volta sola, all'inizio del programma senza aver bisogno di leggere ogni volta da file (se ho capito cosa volevi fare te).

Chiaramente facendo così non ti serve andare a pescare una riga in particolare.

Metal Gabber
12-01-2011, 20:21
Ma il punto non è quello, anche perché il caricamento posso farlo una volta sola anche se uso il mio metodo.

Per ora il primo problema l'ho risolto facendo sì che ogni volta che viene modificata un'impostazione vengono riscritte anche quelle che sono rimaste uguali (se l'utente modifica un'impostazione, viene riscritto il file settings.txt).

Il secondo problema invece è che devo andare a leggere una precisa riga all'interno di un txt che contiene 280.000+ parole (divise da 'a capo'), e stavo cercando una soluzione più elegante di quella che ho scritto prima (che consiste praticamente nel leggerle tutte finché non arrivo alla riga che volevo io).

FrancoBross
18-01-2011, 23:25
ma sentito parlare delle funzioni seek o lseek che muovono il cursore all'interno del file?

kwb
19-01-2011, 14:21
Io ho un problema analogo.

Ho una matrice che si modifica con l'esecuzione del programma... Ogni modifica deve essere scritta su file.
Al termine del programma, in cima al file, devo scrivere del testo .
Il problema è che se torno indietro con fseek ( o rewind ) quando vado a scrivere mi va a cancellare x caratteri, tanti quanti sono i caratteri da scrivere... Di conseguenza mi cancella parte della matrice...
Si può facilmente ovviare a questo mio problema aggiungendo \n a sufficienza all'inizio del file. È chiaro però che non è una soluzione molto bella...
Una soluzione sarebbe quella di memorizzare la matrice modificata dentro una linked list e fare un nuovo nodo ad ogni modifica della matrice.
Poi stampare il testo e a seguire ogni nodo della linked list. Lo voglio evitare...

C'è altro modo?
Segue un esempio del file:

Testo

Matrice passo 1
Matrice passo 2
...
Matrice passo X

In rosso è la parte che viene aggiunta al termine dell'esecuzione della modifica della matrice

banryu79
19-01-2011, 15:21
...cut...

Scusa, perchè non puoi/vuoi mettere il testo in coda alle modifiche della matrice?

Oppure potresti spezzare il file in due file diversi: uno per la matrice e sue modifiche, l'altro per il testo.
Oppure in tre file (sto immaginando a cosa ti possono servire, e tiro a indovinare):
- file con la sola matrice originale;
- file con le modifiche relative alla matrice
- file con il testo relativo alla matrice

kwb
19-01-2011, 15:50
Scusa, perchè non puoi/vuoi mettere il testo in coda alle modifiche della matrice?

Oppure potresti spezzare il file in due file diversi: uno per la matrice e sue modifiche, l'altro per il testo.
Oppure in tre file (sto immaginando a cosa ti possono servire, e tiro a indovinare):
- file con la sola matrice originale;
- file con le modifiche relative alla matrice
- file con il testo relativo alla matrice

Non posso perchè le specifiche date richiedono che ci sia un unico file con tutto dentro formattato come ho scritto.

banryu79
19-01-2011, 16:14
Non posso perchè le specifiche date richiedono che ci sia un unico file con tutto dentro formattato come ho scritto.
Se il testo è modficabile a piacere e senza limiti allora non vedo altrernative al fatto di dover riscrivere ogni volta il file.
Se invece è limitabile, riservi all'inizio del file un tot di spazio solo per il testo: durante l'esecuzione del programma, le modifiche alla matrice le memorizzi in append al file, mentre al termine del programma, se il testo è stato editato, sovvrascrivi la porzione iniziale riservata del file con il testo stesso.
Puoi riempire lo spazio riservato al testo con il carattere nullo '\0'.

kwb
19-01-2011, 17:06
Ho risolto mediante la funzione tmpfile() .
La matrice la memorizzo nel file temporaneo, poi quando ho finito, scrivo il testo e ricopio dal file temporaneo la matrice! :D

pabloski
19-01-2011, 17:07
concordo con banryu, il formato del tuo file non ti consente di ricavare il numero di righe di testo dall'offset sul file

non puoi dire che il byte 398423 corrisponde sicuramente all'inizio della riga 20948

è per questo motivo che i database usano gli indici

banryu79
19-01-2011, 17:28
Ho risolto mediante la funzione tmpfile() .
La matrice la memorizzo nel file temporaneo, poi quando ho finito, scrivo il testo e ricopio dal file temporaneo la matrice! :D
Funziona, ma è una soluzione "meno efficiente" di quella che ti ho proposto prima: la mia ti evita di scrivere ogni volta il file, vengono solo appese le modifiche alla matrice. E se il testo non viene toccato non fa altro, se invece viene modificato comunque non occorre creare un nuovo file.
però tutto dipende dal fatto di avere o non avere un limite fisso di dimensione disponibile per il testo.

P.S.:
Io partivo dal presupposto che il programma, avviandosi, deve leggere il file per inizializzare la matrice; in pratica il file contiene lo storico di tutte le modifiche fatte ad una matrice originale che viene modificata e ricorda il suo stato e le varie transizioni per sempre (o almeno finchè esiste detto file :))

kwb
19-01-2011, 20:05
Funziona, ma è una soluzione "meno efficiente" di quella che ti ho proposto prima: la mia ti evita di scrivere ogni volta il file, vengono solo appese le modifiche alla matrice. E se il testo non viene toccato non fa altro, se invece viene modificato comunque non occorre creare un nuovo file.
però tutto dipende dal fatto di avere o non avere un limite fisso di dimensione disponibile per il testo.

P.S.:
Io partivo dal presupposto che il programma, avviandosi, deve leggere il file per inizializzare la matrice; in pratica il file contiene lo storico di tutte le modifiche fatte ad una matrice originale che viene modificata e ricorda il suo stato e le varie transizioni per sempre (o almeno finchè esiste detto file :))

Il file di input ( che contiene la matrice di partenza ) NON corrisponde al file di output.
Continuo a non capire come vuoi risolvere tu il problema... A me sembra efficientissima questa soluzione, poichè:
- Il file finale viene modificato una e una sola volta ( aperto -> modificato -> chiuso )
- Il file temporaneo viene aperto una volta, ogni modifica viene messa in coda al file ( come è giusto che sia ) e, al termine delle modifiche, viene copiato tutto dentro il file finale di output. Il file temporaneo viene chiuso e cancellato.

Metal Gabber
20-01-2011, 21:46
ma sentito parlare delle funzioni seek o lseek che muovono il cursore all'interno del file?

sì, ma non so di quanti caratteri mi devo spostare in avanti a partire dall'inizio del file, visto che è composto da parole di diversa lunghezza...

kwb
20-01-2011, 23:52
sì, ma non so di quanti caratteri mi devo spostare in avanti a partire dall'inizio del file, visto che è composto da parole di diversa lunghezza...

Non puoi anche tu fare come ho fatto io? Ovvero usare la funzione tmpfile(), ti salvi tutte le impostazioni su questo file temporaneo, e poi quando hai terminato, le sovrascrivi a quelle che ci sono già sul file

Metal Gabber
22-01-2011, 06:33
Per la scrittura delle impostazioni non c'è problema, visto che sono solo 2 le riscrivo ogni volta che avviene una modifica, ma io stavo chiedendo se c'era un modo più elegante per leggere una riga precisa da un file rispetto a quello che ho messo nel primo post.

kwb
22-01-2011, 11:43
Per la scrittura delle impostazioni non c'è problema, visto che sono solo 2 le riscrivo ogni volta che avviene una modifica, ma io stavo chiedendo se c'era un modo più elegante per leggere una riga precisa da un file rispetto a quello che ho messo nel primo post.

A parte spostarsi con fseek alla riga... Non vedo altre soluzioni

pabloski
22-01-2011, 12:13
A parte spostarsi con fseek alla riga... Non vedo altre soluzioni

lo puoi fare solo se sai perfettamente ogni riga dove comincia, in pratica se hai un indice

l'indice ovviamente ha senso se occupa uno spazio che è una frazione del contenuto indicizzato, in quel caso lo si legge tutto in memoria e lo si usa da lì

oppure potresti benissimo imporre che ogni riga ha una dimensione in bytes fissa ( ovviamente è la dimensione massima che un'opzione può raggiungere )....i bytes extra li riempi di zero, però almeno così può crearti una formula semplice semplice per convertire offset <--> numero di riga

FrancoBross
24-01-2011, 23:39
ma in che ambiente fai girare il tutto?

Metal Gabber
26-01-2011, 01:30
Windows