QT4 & file di testo [RISOLTO]

Forum dedicato alla programmazione.

Moderatore: Staff

Regole del forum
1) Citare in modo preciso il linguaggio di programmazione usato.
2) Se possibile portare un esempio del risultato atteso.
3) Leggere attentamente le risposte ricevute.
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.
Rispondi
Avatar utente
tgmx
Linux 4.x
Linux 4.x
Messaggi: 1336
Iscritto il: ven 28 apr 2006, 14:40
Slackware: 14.1
Desktop: KDE 4
Località: Ancona

QT4 & file di testo [RISOLTO]

Messaggio 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:

Codice: Seleziona tutto

wc -l file.txt
Sapete consigliarmi un modo veloce per avere questo valore senza richiamare ws da programma e possibilmente usando funzioni di libreria delle QT4 ? :)

Grazie.
Ultima modifica di tgmx il ven 30 mag 2008, 11:50, modificato 1 volta in totale.

Avatar utente
mcosta
Linux 0.x
Linux 0.x
Messaggi: 54
Iscritto il: mar 15 giu 2004, 0:00
Nome Cognome: Massimo Costa
Slackware: 13.0
Kernel: 2.6.29.6
Desktop: KDE 4.2.4
Località: Marano (NA)

Re: QT4 & file di testo

Messaggio 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;
}

Avatar utente
tgmx
Linux 4.x
Linux 4.x
Messaggi: 1336
Iscritto il: ven 28 apr 2006, 14:40
Slackware: 14.1
Desktop: KDE 4
Località: Ancona

Re: QT4 & file di testo

Messaggio 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. :)

Avatar utente
tgmx
Linux 4.x
Linux 4.x
Messaggi: 1336
Iscritto il: ven 28 apr 2006, 14:40
Slackware: 14.1
Desktop: KDE 4
Località: Ancona

Re: QT4 & file di testo

Messaggio 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++ ?

Avatar utente
mcosta
Linux 0.x
Linux 0.x
Messaggi: 54
Iscritto il: mar 15 giu 2004, 0:00
Nome Cognome: Massimo Costa
Slackware: 13.0
Kernel: 2.6.29.6
Desktop: KDE 4.2.4
Località: Marano (NA)

Re: QT4 & file di testo

Messaggio 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).

Avatar utente
tgmx
Linux 4.x
Linux 4.x
Messaggi: 1336
Iscritto il: ven 28 apr 2006, 14:40
Slackware: 14.1
Desktop: KDE 4
Località: Ancona

Re: QT4 & file di testo

Messaggio 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... :cry:

In attesa di un'illuminazione mi trovo costretto ad usare questo altrimenti il programma ci mette più di un minuto.

Avatar utente
alessiodf
Linux 3.x
Linux 3.x
Messaggi: 823
Iscritto il: ven 14 ott 2005, 21:04
Slackware: current
Kernel: 2.6.26.4
Desktop: Kde 4.1
Località: Roma
Contatta:

Re: QT4 & file di testo

Messaggio 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 :>

Avatar utente
tgmx
Linux 4.x
Linux 4.x
Messaggi: 1336
Iscritto il: ven 28 apr 2006, 14:40
Slackware: 14.1
Desktop: KDE 4
Località: Ancona

Re: QT4 & file di testo

Messaggio 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 :roll: .

Continuo però a non caqpire come fa "wc" ad essere così veloce....

Avatar utente
alessiodf
Linux 3.x
Linux 3.x
Messaggi: 823
Iscritto il: ven 14 ott 2005, 21:04
Slackware: current
Kernel: 2.6.26.4
Desktop: Kde 4.1
Località: Roma
Contatta:

Re: QT4 & file di testo

Messaggio da alessiodf »

500 mega? umm.. allora io leggerei a pezzi di addirittura 100k :) comunque, basta fare un po di prove..

Avatar utente
tgmx
Linux 4.x
Linux 4.x
Messaggi: 1336
Iscritto il: ven 28 apr 2006, 14:40
Slackware: 14.1
Desktop: KDE 4
Località: Ancona

Re: QT4 & file di testo

Messaggio 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.... :D

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 :D , 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... :)

Avatar utente
alessiodf
Linux 3.x
Linux 3.x
Messaggi: 823
Iscritto il: ven 14 ott 2005, 21:04
Slackware: current
Kernel: 2.6.26.4
Desktop: Kde 4.1
Località: Roma
Contatta:

Re: QT4 & file di testo [RISOLTO]

Messaggio 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 :D

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;
}
:thumbright:

Avatar utente
tgmx
Linux 4.x
Linux 4.x
Messaggi: 1336
Iscritto il: ven 28 apr 2006, 14:40
Slackware: 14.1
Desktop: KDE 4
Località: Ancona

Re: QT4 & file di testo [RISOLTO]

Messaggio 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 :D

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;
}
:thumbright:
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.... :D

Avatar utente
mcosta
Linux 0.x
Linux 0.x
Messaggi: 54
Iscritto il: mar 15 giu 2004, 0:00
Nome Cognome: Massimo Costa
Slackware: 13.0
Kernel: 2.6.29.6
Desktop: KDE 4.2.4
Località: Marano (NA)

Re: QT4 & file di testo [RISOLTO]

Messaggio da mcosta »

Se adesso troviamo un metodo di QFile che conta da solo le righe di un file di testo.... :D
Ma allora dillo che non hai voglia di lavorare :D :D

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

Avatar utente
tgmx
Linux 4.x
Linux 4.x
Messaggi: 1336
Iscritto il: ven 28 apr 2006, 14:40
Slackware: 14.1
Desktop: KDE 4
Località: Ancona

Re: QT4 & file di testo [RISOLTO]

Messaggio da tgmx »

mcosta ha scritto: Ma allora dillo che non hai voglia di lavorare :D :D
Se avevo voglia di lavorare non mi appassionavo all'informatica... :lol: :lol:

Comunque la tua soluzione non è adatta al mio scopo per il fatto che non ho la garanzia assoluta che le righe siano tutte della stessa lunghezza anche se è molto probabile. Perferisco qualcosa di preciso. :)

Rispondi