Newsgroup: it.comp.lang.c++
Titolo: Ennesima riga di un file di testo

Salve
Ho bisogno di andare all'ennesima riga di un file di testo.
Ho provato il metodo seekg ma mi sposta il puntatore ell'ennesimo
carattere del file.
L'unico modo per fare ciò che voglio io (per adesso) è stata quella di
ciclare con una getline finchè non trovo la riga giusta.
Esiste un metodo per fare ciò che voglio io?
Grazie mille

 Grazie mille


Puo' provare il seguente metodo. Comunque non sarebbe possibile
confrontare l'efficienza dei due metodi senza effettuare delle misure
nel caso specifico.
Saluti.
#include <iostream>
#include <string>
#include <limits>
int main()
{
    const int righe_da_ignorare = 1000;
    std::streamsize mx = std::numeric_limits<std::streamsize>::max();
    for( int i = 0; i < righe_da_ignorare && std::cin.ignore( mx,
'\n' ); ++i ) {
        ;
    }
    if( std::cin ) {
        std::string str;
        std::getline( std::cin, str );
    }
	return 0;
}

 ricerca sequenziale.
Fortunatamente è un file di lunghezza fissa.
Ogni riga contiene un termine (in pratica è una wordlist).
E mi serve entrare in modo random nella mia wl e prendere termini
(ecco perchè mi serve l'ennesima riga!) a caso...
Un altro vincolo: usare metodi della classe fstream.
Cosa mi consigli di fare?

 Fortunatamente è un file di lunghezza fissa.
non era questo il mio dubbio. La lunghezza totale del file 
conta solo nella misura in cui vuoi poter stimare a priori 
se si possa caricarlo in ram.
Io chiedevo se le righe contenute fossero di lunghezza fissa.
Non è una soluzione impossibile (potrebbero essere inserite 
in spazi preallocati, riempiti a destra o a sinistra con 
caratteri "blank", tipo lo spazio.
Se è questa l'alternativa, è sufficiente che tu sappia 
quanto è l'ampiezza di ciascuna riga (che è costante), e ci 
aggiungi la dimensione del newline (1 o 2 byte, o 2 o 4 
byte, se usi gli ascii o gli unicode, assumendo che sia 
stata usata una convenzione univoca di separatori). Sia 
quindi W l'ampiezza in byte di ciascuna linea.
Il primo byte del file è all'offset 0 o 1 (dipendentemente 
dalle primitive che usi) : a tale valore aggiungi W * (N-1) 
byte, dove N è il numero di riga one-based, ed esegui il 
seek (fseek o altra primitiva di posizionamento ... devi 
usare files a accesso random ovviamente, non sequenziale) e 
sei posizionato alla riga voluta.
Se la lunghezza record è variabile, vedasi il post precedente
ciao
Soviet


Esiste un metodo per fare ciò che voglio io?
L'unico è quello che hai adottato. Dovresti sapere che i file
cosiddetti "di testo" sono, per loro natura, dei file sequenziali,
quindi non è possibile un accesso random.

 cosiddetti "di testo" sono, per loro natura, dei file sequenziali,
scusa, ma cosa intendi "per loro natura" ?
Un file non lo puoi aprire come ti pare, usando ovviamente 
gli appositi flag delle funzioni di apertura (tipo open, 
fopen etc) ?
Perlomeno se si aprono come file nudi e crudi ... come 
stream bufferizzati non saprei dire, magari in quel caso hai 
ragione tu, non mai avuto ho molta dimestichezza con gli stream.
In ogni caso il file fisico sottostante lo si può sempre, 
penso senza eccezioni, vedere come file grezzo, binario, e 
quindi procurarsi l'accesso che più viene comodo.
ciao
Soviet


 scusa, ma cosa intendi "per loro natura" ?
Intendo dire che un file "di testo" è una pura e semplice convenzione;
un file è un file. Il contenuto testuale si assume, per convenzione,
suddiviso in righe, terminate da sequenze di caratteri (al limite uno
solo) che, proprio perché soggette a convenzione, variano da una
piattaforma all'altra. Il file puoi aprirlo come ti pare e usando
l'API che ti pare, ma in nessun modo, comunque, potrai accedere in
modo random ad una riga.

Andrea Laforgia ha scritto:

ahh, okay, si allora sono d'accordo. Non si può evitare 
almeno un parsing completo iniziale per localizzare le righe.
Dopo si può accedere random, ma è un modo di aggirare il 
vincolo che dici : che non si possono fare assunzioni a priori.
Non avevo capito bene (pensavo intendessi che non si può 
leggere in modo random tout court, invece intendevi in modo 
"aware" del contenuto senza averlo prima predigerito)
ciao
Soviet

Dopo si può accedere random
No, non si può comunque, perché "accedere random" significa aprire il
file in modalità binaria (quindi non come file di testo). Come già
detto, i file di testo sono, per loro natura, dei file sequenziali.

 detto, i file di testo sono, per loro natura, dei file sequenziali.
Ciao
Soviet_Mario

Si ma mica sono formati mutualmente esclusivi.
Vedi sopra. Certo che lo sono. Se apri un file in modalità testo, stai
decidendo di elaborarlo secondo certe convenzioni specifiche della
piattaforma.

 rinunciare, di fatto, ad aprirlo come file di testo.
Questo è chiaro. La questione è se è possibile accedere in modo random 
ai caratteri di un file di testo. Insomma puoi utilizzare fseek? Io 
direi di sì, anche se non hai garantito che ogni carattere occupi un 
byte. Immagino che fseek si comporti su un file allo stesso modo, 
indipendentemente dal fatto che il file sia aperto in modo "b" o "t".
E.

 direi di sì
Non su file di testo.

 si che puoi, basta guardarli come file binari.
Vedi sopra. Se li guardi come file binari, non li stai trattando come
file di testo.
Per il bene dell'OP vale quanto già detto: non è possibile accedere in
maniera random a una linea di un file di testo; i file di testo sono
sequenziali; per accedere alla linea n, bisogna NECESSARIAMENTE
leggere le n-1 righe.
Punto.

 file di testo.
E l'ho capito, e già lo sapevo ... ma cosa importa ?
Tra l'altro, se uno usa la gestione binaria in modo giusto 
(cioè non infila dentro caratteri non ammessi, dipendenti 
dal contesto, tipo ctrl-Z o ascii non stampabili o zeri 
binari), neppure esclude di potere al contempo usare anche 
primitive di testo di livello più alto (a patto ovviamente 
che metta in conto di aggiornare lo stato di parsing, ma 
questo è ovvio).
ciao
soviet_mario


 scusa, non è per polemizzare né insistere sterilmente 
Allora il punto è:
- non è possibile accedere in modo casuale alle righe di un file di 
testo (la tua soluzione scorre l'intero file e quindi non risolve la 
questione, mi pare che su questo siamo d'accordo)
- sembra che Andrea stia pure dicendo che non si può usare fseek su un 
file di testo. Su questo ho i miei dubbi. A parte che sperimentalmente 
fseek funziona, non vedo perché dovrebbe essere sbagliato usarlo.
- leggere le righe del file dopo averlo aperto in modalità binaria non 
mi pare la soluzione giusta, perché non è portabile. Infatti devi essere 
tu a gestire i diversi possibili formati dei file di testo. Ci sono 
almeno tre diversi formati per i '\n' nei file di testo, mi pare che 
siano: Unix (CR), Dos/Windows (CR/LF), Mac (LF). Ma non so se puoi 
escludere che ce ne siano altri.
E.

 portabili.
Certo. E quindi la cosa migliore è proprio usare queste funzioni (fgets 
direi) per scorrere il file.
E.

Ripensando all'intero thread, potrei aver commesso un errore 
di valutazione circa le necessità dell'OP, anche se in buona 
fede (e in parte perché avevo visto una vaga somiglianza con 
problema che ebbi a mia volta).
Cioè, sono partito dal presupposto che gli servisse poter 
lavorare a lungo sul file dato, in molte "passate" distinte, 
un po' come si fa per caricare o salvare settaggi e 
parametri (con ReadProfileString e WriteProfileString) varie 
volte.
Non mi ha sfiorato, ma in effetti ci poteva stare benissimo, 
l'idea che all'OP potesse interessare fare una singola 
passata sul file di testo, quindi un'elaborazione 
sequenziale una tantum.
Se questo era il caso, allora in effetti i miei suggerimenti 
non solo non apportano alcun reale vantaggio sulla scansione 
standard con fgets o analoghi, ma sono anche più difficili e 
tediosi da codificare, per cui in questo caso la strategia è 
del tutto inadatta.
Non so neppure valutare quando possa scattare una soglia 
minima di convenienza (in termini di efficienza), intesa 
come numero minimo di "passate" o accessi random ripetuti da 
valere la spesa di un parsing preliminare come quello 
proposto. Ancora con un paio di passate soltanto, potrebbe 
non valer la pena di escogitare workaround.
Certo, se uno deve rielaborare lo stesso file una decina di 
volte, tipo localizzare molte volte la stessa chiave e 
modificarne il valore associato, allora magari comincia a 
essere conveniente il parsing binario a mano rispetto alla 
scansione totale ogni volta fino a trovare la stringa, ma 
quel "dieci passate" è solo un numero indicativo, spannometrico.
ciao
Soviet_Mario
CUT


In realta' questo non e' scontato, anche se e' cio' a cui ci hanno
abituato UNIX e i suoi discendenti. Sistemi operativi che supportano
nativamente diversi formati di file possono dare l'illusione che un
file di testo sia accedibile in modo casuale, assumendo l'equivalenza
linea/record.
In ogni caso, anche nella remota eventualita' che l'OP si trovasse a
lavorare su un sistema operativo simile, queste funzionalita'
potrebbero essere disponibili solo attraverso specifiche librerie, dal
momento che lo standard non le prevede.
Ciao,
Nicola