Pagina 1 di 1
QT4 & file di testo [RISOLTO]
Inviato: mer 28 mag 2008, 17:17
da tgmx
Ciao Ragazzi,
dovrei ricavare in QT4 il numero di righe in un file di testo mooooolto grande. La prima soluzione adottata era la seguente:
Codice: Seleziona tutto
if (!file.open(QFile::ReadOnly | QFile::Text))
{
return;
}
QTextStream stream(&file);
//calcolo quante righe ci sono nel file:
int num_righe=0;
while(!stream.readLine().isNull())
{
num_righe++;
}
ma dato che il file, come ho detto, è molto grande ci mette troppo a fare questo while.
Tra l'altro ho visto che da console è possibile ottenere questo valore molto velocemente:
Sapete consigliarmi un modo veloce per avere questo valore senza richiamare ws da programma e possibilmente usando funzioni di libreria delle QT4 ?
Grazie.
Re: QT4 & file di testo
Inviato: mer 28 mag 2008, 20:24
da mcosta
Se ti interessa il solo numero di righe io farei così
Codice: Seleziona tutto
int linesCount(const QString& _fileName)
{
QFile file(_fileName);
if(!file.open(QFile::ReadOnly))
return 0;
int lines = 0;
char ch;
while(!file.atEnd())
{
file.getChar(&ch);
#ifdef Q_WS_MAC
if(ch == '\r') // Su MacOS il fine linea è '\r'
#else
if(ch == '\n')
#endif
break;
++lines;
}
return lines;
}
Re: QT4 & file di testo
Inviato: mer 28 mag 2008, 23:07
da tgmx
Effettivamente non è male come idea, domani la provo, credo però ci sia un errore:
Codice: Seleziona tutto
while(!file.atEnd())
{
file.getChar(&ch);
if(ch == '\n')
break;
++lines;
}
in questo modo all'arrivo del fine linea esco dal while, immagino intendessi:
Codice: Seleziona tutto
while(!file.atEnd())
{
file.getChar(&ch);
if(ch == '\n')
++lines;
}
a parte questo dettaglio credo che la tua soluzione sia più veloce di quella che ho postato all'inizio, domani ti faccio sapere.
Grazie.

Re: QT4 & file di testo
Inviato: gio 29 mag 2008, 9:53
da tgmx
Ho provato la nuova soluzione e un po' migliora ma resta comunque molto più lenta del comando "wc -l file.txt"...
Eppure ho visto i sorgenti del comando "wc" e per calcolare il numero delle righe usa proprio il metodo che mi ha consigliato mcosta:
http://www.gnu.org/software/cflow/manua ... mmand.html
A cosa puù essere dovuta questa differenza di comportamente? Possibile sia solo il fatto che wc e in C mentre io uso quella parte di codice in C++ ?
Re: QT4 & file di testo
Inviato: gio 29 mag 2008, 11:24
da mcosta
Mi scuso per l'erroraccio nel codice proposto
Comunque la differenza di velocità rispetto a "wc" potrebbe essere dovuta al fatto che la classe QFile delle Qt esegua una serie di controlli per garantire l'accesso "protetto" al file.
Se ti interessa la velocità pura probabilmente ti conviene utilizzare le primitive base (non credo che la classe fstream del C++ sia molto più lenta delle primitive C).
Re: QT4 & file di testo
Inviato: gio 29 mag 2008, 11:41
da tgmx
mcosta ha scritto:Mi scuso per l'erroraccio nel codice proposto
Comunque la differenza di velocità rispetto a "wc" potrebbe essere dovuta al fatto che la classe QFile delle Qt esegua una serie di controlli per garantire l'accesso "protetto" al file.
Se ti interessa la velocità pura probabilmente ti conviene utilizzare le primitive base (non credo che la classe fstream del C++ sia molto più lenta delle primitive C).
Ora ho anche provato ad inserire nel mio codice la parte di "wc" che esegue l'operazione di conto:
Codice: Seleziona tutto
FILE *fp = fopen (fileName.toAscii(), "r");
if (!fp)
return;
char ch;
while ((ch = getc (fp)) != EOF)
{
if ((ch) == '\n')
num_righe++;
}
fclose(fp);
ma non ho notato grandi miglioramenti... o mi sfugge qualcosa o magari wc è compilato con qualche particolare ottimizzazione...
Per adesso mi trovo costretto ad utilizzare QProcess:
Codice: Seleziona tutto
QProcess proc;
proc.start("wc -l "+fileName);
if(proc.waitForFinished(30000)) //se è terminato correttamente e nel tempo stabilito
{
QString str(proc.readAllStandardOutput());
num_righe = str.split(" ")[0].toInt();
}
in questo modo è una "scheggia" ma mi gioco la portabilità su windows...
In attesa di un'illuminazione mi trovo costretto ad usare questo altrimenti il programma ci mette più di un minuto.
Re: QT4 & file di testo
Inviato: ven 30 mag 2008, 0:25
da alessiodf
prova a bufferizzare un po che rendi tutto velocissimo.. ti costa un po di piu' in memoria pero'
QByteArray QIODevice::read ( qint64 maxSize ) ad esempio con questa.. potresti leggere blocchi di file di tipo umm 10k (solitamente non si va sopra i 4k per portabilita' su sistemi micro tipo una calcolatrice .) e su sti 10k (che stanno in memoria) potresti contare quanti \r o \r\n vi sono
questa e' una lettura non carattere per carattere, ma bufferizzata. e' piu' performante perche' il file viene mappato in memoria centrale con spezzoni piu' grandi.
nessuno ti vieta di caricare un file enorme (100mega) in memoria in un colpo solo :>
Re: QT4 & file di testo
Inviato: ven 30 mag 2008, 8:31
da tgmx
alessiodf ha scritto:prova a bufferizzare un po che rendi tutto velocissimo.. ti costa un po di piu' in memoria pero'
QByteArray QIODevice::read ( qint64 maxSize ) ad esempio con questa.. potresti leggere blocchi di file di tipo umm 10k (solitamente non si va sopra i 4k per portabilita' su sistemi micro tipo una calcolatrice .) e su sti 10k (che stanno in memoria) potresti contare quanti \r o \r\n vi sono
questa e' una lettura non carattere per carattere, ma bufferizzata. e' piu' performante perche' il file viene mappato in memoria centrale con spezzoni piu' grandi.
nessuno ti vieta di caricare un file enorme (100mega) in memoria in un colpo solo :>
Ora provo, però non è possibile caricare tutto in memoria dato che il file è da più di 500MB

.
Continuo però a non caqpire come fa "wc" ad essere così veloce....
Re: QT4 & file di testo
Inviato: ven 30 mag 2008, 9:53
da alessiodf
500 mega? umm.. allora io leggerei a pezzi di addirittura 100k

comunque, basta fare un po di prove..
Re: QT4 & file di testo
Inviato: ven 30 mag 2008, 11:49
da tgmx
alessiodf ha scritto:500 mega? umm.. allora io leggerei a pezzi di addirittura 100k

comunque, basta fare un po di prove..
Alla fine questo è ciò che ho fatto:
Codice: Seleziona tutto
QByteArray lettura;
while(!(lettura=file.read(500*1024)).isEmpty())
{
QApplication::processEvents();
for(int i=0; i<lettura.size(); i++)
{
if(lettura.at(i)=='\n')
num_righe++;
}
}
in questo modo la velocità di scansione del file si avvicina molto a quella di "wc" quindi non posso che ritenermi soddisfatto....
Ho provato ad alzare utleriormente la quantità di byte bufferizzata ma non sembra migliorare quindi mi sono fermato a 500K.
Grazie mille del consiglio

.
PS. Per completezza, ammesso che interessi a qualcuno

, descrivo un po' meglio cosa fa questa piccola applicazione così magari può essere utile a qualcun'altro:
il programma ha lo scopo di caricare su un db mysql dei dati che si trovano in un file di testo sotto forma di stringhe di lunghezza fissa. Il fatto è che essendo un file molto grande questa operazione richiede del tempo così ho pensato di visualizzare a video una piccola barra di scorrimento. La barra di scorrimento però va inizializzata (giustamente) con un valore minimo e massimo in modo che lo scorrimento percentuale sia fedele allo stato dell'operazione in corso. In conclusione mi serviva sapere il numero di righe nel file prima di iniziare a caricarle nel db...

Re: QT4 & file di testo [RISOLTO]
Inviato: ven 30 mag 2008, 12:43
da alessiodf
int QByteArray::count ( char ch ) const
con questa, risparmi un ciclo.. e credo che se lo fai fa a qt, e' sicuramente piu' performante! quindi passagli '\n' ad esempio e prova ad aumentare il buffer size
edit: qt 4.4 fa questo per contare i caratteri in un qbyte array:
Codice: Seleziona tutto
int QByteArray::count(char ch) const
{
int num = 0;
const char *i = d->data + d->size;
const char *b = d->data;
while (i != b)
if (*--i == ch)
++num;
return num;
}

Re: QT4 & file di testo [RISOLTO]
Inviato: ven 30 mag 2008, 14:08
da tgmx
alessiodf ha scritto:int QByteArray::count ( char ch ) const
con questa, risparmi un ciclo.. e credo che se lo fai fa a qt, e' sicuramente piu' performante! quindi passagli '\n' ad esempio e prova ad aumentare il buffer size
edit: qt 4.4 fa questo per contare i caratteri in un qbyte array:
Codice: Seleziona tutto
int QByteArray::count(char ch) const
{
int num = 0;
const char *i = d->data + d->size;
const char *b = d->data;
while (i != b)
if (*--i == ch)
++num;
return num;
}

QByteArray::count mi era sfuggito... l'ho appena provata e forse guadagno mezzo secondo ma a parte la velocità resta comunque più pulito il codice del programma...
Se adesso troviamo un metodo di QFile che conta da solo le righe di un file di testo....

Re: QT4 & file di testo [RISOLTO]
Inviato: ven 30 mag 2008, 17:22
da mcosta
Se adesso troviamo un metodo di QFile che conta da solo le righe di un file di testo....

Ma allora dillo che non hai voglia di lavorare
Comunque butto lì una soluzione moooooolto "grezza"
Visto che ogni stringa ha lunghezza fissa potresti fare così
Codice: Seleziona tutto
const int LINE_SIZE = 100; // esempio 100 caratteri
QFile file(nomeFile);
int linesCount = file.size() / (LINE_SIZE + 1); // il +1 e' per considerare il ritorno a capo
Re: QT4 & file di testo [RISOLTO]
Inviato: ven 30 mag 2008, 17:34
da tgmx