Newsgroup: it.comp.lang.visual-basic
Titolo: [?] come velocizzare la lettura di file ascii di grandi dimensioni?

Salve,
mi trovo nella necessità di leggere file in formato testo di grandi
dimensioni (50/80mb)
in pratica il file ha questa struttura che si ripete per tutto il file:
linea1
linea2
linea3
    linea_utile1
    linea_utile2
    linea_utile3
linea4
linea5
linea6
a me interessa prelevare i dati  delle "linee utili"...
ora come ora uso una serie di line input.... se volessi leggere tutto il
file  in una stringa devo aprire il file in formato random e usare un get
con una variabile stringa?
e poi faccio la ricerca sul file in memoria ? questo rendrebbe il codice +
veloce (anche se + oneroso in termini di memoria) giusto?
oppure ci sono altri sistemi?
grazie
Davide

 wrote in message
news:9HDH9.30988$fa.10...@news1.tin.it...

Qualche tempo fa si era fatto un confronto tra le seguenti possibilità :
1) Comandi VBA (OPen, Line input ecc..)
2) FSO (Streamer)
3) API ...
rimango convinto che la terza sia sicuramente la soluzione più veloce e
prestante anche se più complicata
Saluti

 prestante anche se più complicata
puoi darmi qualche indicazione + pre3cisa sulle API?
 grazie
Davide

 Saluti
non so se fox si riferisce al codice che metto sotto, che serviva a
confrontare il numero di linee di un txt. se e' questo, dubito che ti
serva cosi' com'e'. a naso comunque userei anch'io il blocco con line
input, gestendo un paio di contatori dentro il ciclo, ovviamente senza
doevents.
ciao, j.
Option Explicit
Private Sub cmdFSO_Click() 'epoch
    Dim time1: time1 = Timer
    txtRisult = "": txtRisult.Refresh
    Dim Fso As FileSystemObject
    Dim FIn As TextStream
    Dim NumLine As Long
    Set Fso = CreateObject("Scripting.FileSystemObject")
    Set FIn = Fso.OpenTextFile(App.Path & "\list.txt", ForAppending,
False, TristateFalse)
    NumLine = FIn.Line - 1
    FIn.Close
    txtRisult = "righe: " & CStr(NumLine) & " -- tempo: " & _
        Format(Timer - time1, "###,##0.000")
End Sub
Private Sub cmdLineInput_Click() 'licantrop0
    Dim time1: time1 = Timer
    txtRisult = "": txtRisult.Refresh
    Dim s As String, j As Long, fNum As Long
    fNum = FreeFile
    Open App.Path & "\list.txt" For Input As #fNum
    's = Input(LOF(fNum), fNum)
    While Not EOF(fNum)
        Line Input #fNum, s
        j = j + 1
    Wend
    Close #fNum
    txtRisult = "righe: " & CStr(j) & " -- tempo: " & _
        Format(Timer - time1, "###,##0.000")
End Sub
Private Sub cmdReplace_Click() 'zanna
    Dim time1: time1 = Timer
    txtRisult = "": txtRisult.Refresh
    Dim s As String, j1 As Long, j2 As Long, fNum As Long
    Dim partenza As Long, t_righe As Long, fr As Long
    fNum = FreeFile
    Open App.Path & "\list.txt" For Input Shared As #fNum
        s = Input$(LOF(fNum), #fNum)
    Close fNum
    j1 = Len(s)
    s = Replace(s, vbCrLf, "")
    j2 = Len(s)
    ' conto anche l'ultima non terminante con CR [LF]
    ' divido per 2 perche vbcrlf=2 byte -- j
    txtRisult = "righe: " & CStr(((j1 - j2) / 2) + 1) & " -- tempo: "
& _
        Format(Timer - time1, "###,##0.000")
End Sub
Private Sub cmdSplit_Click() 'maurizio
    Dim time1: time1 = Timer
    txtRisult = "": txtRisult.Refresh
    Dim intNFile  As Integer
    Dim strFullFileName As String
    Dim lngRows As Long
    strFullFileName = App.Path & "\list.txt"
    intNFile = FreeFile(0)
    Open strFullFileName For Input As intNFile
    lngRows = 1 + UBound(Split(Input$(LOF(intNFile), intNFile),
vbCrLf))
    Close
    'Debug.Print "Righe: "; Format$(lngRows, "#,##0")
    txtRisult = "righe: " & CStr(lngRows) & " -- tempo: " & _
        Format(Timer - time1, "###,##0.000")
End Sub
Private Sub cmdVbCrLf_Click() 'lupo
    Dim time1: time1 = Timer
    txtRisult = "": txtRisult.Refresh
    Dim s As String, j As Long, fNum As Long
    Dim partenza As Long, t_righe As Long, fr As Long
    fNum = FreeFile
    Open App.Path & "\list.txt" For Input Shared As #fNum
        s = Input$(LOF(fNum), #fNum)
    Close fNum
    partenza = 1
    t_righe = 0
    Do
        fr = InStr(partenza, s, vbCrLf)
        If fr = 0 Then Exit Do
        t_righe = t_righe + 1
        partenza = fr + 2
    Loop
    txtRisult = "righe: " & CStr(t_righe) & " -- tempo: " & _
        Format(Timer - time1, "###,##0.000")
End Sub

 wrote in message
news:n1EH9.31035$fa.10...@news1.tin.it...

Non ne so nulla .. però dovresti guardarti le API ReadFile e WriteFile
di più non zo ... spiacente
Saluti

 doevents.
perdona l'ignoranza ma "FileSystemObject"  è parte del SO?
devo redistribuire qualche cosa con il mio exe (tieni presente che deve
girare anche su w95....)
grazie
Davide

Ma convertire il file di testo in un DB e usare ADO...no!?!?
Vedrai dopo come č veloce il tuo accesso ai dati...
--------------------------------
Inviato via 
http://usenet.libero.it

 ha scritto


 Vedrai dopo come č veloce il tuo accesso ai dati...
con dao, e' probabile.
con ado, mi sa dipenda dalle dimensioni del txt.
entro certi limiti, imho con line input hai finito mentre ado ancora
apre la connessione.
li' le prove le avevo fatte con stazze discrete, e non ci voleva
molto.
e comunque per metterlo nel db, se gli arriva come txt, deve prima
usare line input. quindi... :)

 --
ci starei volentieri solo che il file è da ~90 mega e io dovrei leggero in
diciamo max 1min... e ci metto +di 20min
considera che oltre a leggero devo fare degli split etc etc...
sto provando ad usare le api.. ma riesco a leggere solo 1/2 del testo (non
capisco perchè anche se uso il flag file_begin non parta dalla 1° riga
l alettura è velocissima... il problema sta poi nel ricostruire le stringhe
dall'array di byte....:(
la lettura binaria (con il get) è + rapida di quella con line input?
ciao
Davide

 Vedrai dopo come č veloce il tuo accesso ai dati...
ehm.. NON č un db....
ciao

 ciao
ho modificato il codice cosi' da poter creare un txt.
sotto c'e' la sub.
timing: laptop p3/700 / desktop athlon xp2000
tutti e due w2k sp3
creazione di un txt di 111 mb (1.5 mlinee): 41.8" / 13.1"
lettura line input: 12.8" / 5.0"
lettura fso: 7.1" / 2.4"
il portatile ovviamente ha un disco molto lento, quindi i tempi che ti
ritrovi mi sa che derivano dalle altre operazioni che devi fare.
prova a ottimizzare li'. togli tutti i refresh.
tieni presente che il test era orientato solo a sapere il numero di
linee del txt, quindi se guardi col fso ti trovi solo quello. con
lineinput il ciclo cmq lo fai. imho, anche col fso, se cominci a
ciclare sul contenuto del file...
a parte la compatibilita', ho avuto l'impressione che il fso sia utile
quando maneggi i file _dall'esterno_, come con explorer. quando ci vai
dentro...
passo sul get. forse migliori. ma ci prova qualcun altro :)
ciao, j.
Private Sub cmdCreate_Click()
    If Val(txtNLines) < 1 Then Exit Sub
    Dim s As String, i As Long, j As Long, fNum As Long
    s =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz0123456
789"
    i = Val(txtNLines) * 1000
    txtNLines = Format(i, "###,###,###,###,###,##0"):
txtNLines.Refresh
    txtRisult = "": txtRisult.Refresh
    Dim time1: time1 = Timer
    fNum = FreeFile
    Open App.Path & "\list.txt" For Output As #fNum
    For j = 1 To i
        Print #fNum, s
    Next
    Close #fNum
    txtRisult = "righe: " & CStr(j - 1) & " -- tempo: " & _


 prova a ottimizzare li'. togli tutti i refresh.
refresh non ce ne sono...
unica cosa è che per ogni linea "buona" c'è uno split ed un redim preserve
quindi ora proverò a far eun aprelettura per sapere il numero di righe,
da qui faccio un unico redim....
e poi lo split magari mi porta via troppo tempo...
ma ho già controllato e a farlo "manualmente" è comunque lento uguale
ciao
Davide

e poi lo split magari mi porta via troppo tempo...
questo invece penso non sia vero, comunque facci sapere come va dopo aver
eliminato i redim.
Salutoni
Sergio

 numero di righe, da qui faccio un unico redim....
Oppure fai la ReDim Preserve a "botte" di 1000, basta una variabile
contatore

 preserve quindi ora proverò a far eun aprelettura per sapere il
Ahem?!?
Fai una redim *PRESERVE* di un array di, diciamo, un migliaio di linee per,
diciamo, un migliaio di volte? Ci credo che hai tempi epocali! Si parla di
un numero di ridimensionamenti pari a, correggetemi, un mille fattoriale,
give or take... E di *stringhe, per di piu'!! :)
Le redim *preserve* si fanno o predeterminate (ovvero, so che il file ha
circa 2000 linee utili, predimensiono l'array a 4000 cosi' son tranquillo, e
se *proprio* capita che il file e' piu' del doppio di quanto dovrebbe essere
faccio *una* redim sola, di altre 4000 linee) o a blocchi (ovvero, aggiungi
costantemente un 20-30% alla dimensione dell'array, cosi' risparmi memoria
se sono array numerici, quindi dove la dimensione dell'array e'
effettivamente la dimensione del dato, non solo quella dei puntatori, e
gestisci file piu' o meno di qualunque dimensione con un overhead
ragionevolmente limitato).
Ovviamente se hai delle linee valide che sono vuote puo' esserti necessario
tenerti un contatore per tagliare l'array alla fine, altrimenti la prima
linea vuota e' il terminatore dell'array.
HTH, HAND.
*


non sono redim di stringhe ma dei valori che vado a leggere che sono interi,
e i redim non sono ad ogni riga...
sono a pacchetti.. ma modificherò il codice per fare 1 solo redim in
testa....
ciao


Consiglio: cambia strategia. Piazza un po' di QueryPerformanceCounter in
giro per il codice e cerca di capire quali operazioni mangiano piu' risorse:
se riesci a capire dove finiscono i tuoi preziosi cicli di clock hai trovato
dove ottimizzare.
HTH,
*

 diciamo, un migliaio di volte? Ci credo che hai tempi epocali!
ehm :)
era esattamente per questo che gli dicevo di ottimizzare il resto,
piu' che il line input :)


 dove ottimizzare.
guarda... sono 4 righe di codice :) escluso il do loop...
quindi c'è poco da piazzare queryperformancecounter :D
grazie lo stesso :D
Davide


C'e' qualcosa che non quadra... Un input da file, per quanto grosso, non
puo' portarti via cosi' tanto tempo. Altra cosa: hai detto che sono 4 righe
*escluso* il cislo, ma *incluso* il ciclo quante linee sono?
Magari posta il codice del ciclo, hai visto mai che c'e' un problema noto?
Ciaotutti,
*

 *escluso* il cislo, ma *incluso* il ciclo quante linee sono?
mah eccoti il ciclo...(+/-)
do
'
    line input #nf,appo$
    line input #nf,appo$
    line input #nf,appo$
'
    line input #nf,appo$
    if cl=100 then
        redim preserve vett(cl)
        cl=0
    else
        cl=cl+1
    end if
    ver=split(appo$,chr(32))
    if ver(3)=finedati$ or Eof(nf) then
        esci=true
    else
        vett(cl).val1=cint(ver(1))
        vett(cl).val2=cint(ver(2))
        vett(cl).val3=cint(ver(3))
        line input #nf,appo$
        line input #nf,appo$
        line input #nf,appo$
    end if
loop until esci=true
c'è l'if che può essere pesante, il redim.. lo split non cambia anche s elo
faccio in modo diverso (con mid e instr)
boh :)
adesso provo con la prelettura
Ciao
Davide


Ad ogni modo questo non mi pare il codice vero e proprio :)
Sicuro di non aver tralasciato nulla? Che so, un'operazioncina che"tanto
quanto vuoi che pesi"? :)
Ciaotutti,
*

 quanto vuoi che pesi"? :)
non ho trlasciato nulla...però ora ricontrollo bene perchè questo è il
codice che ho passato al mio "secondo"
ora vedo se per caso lui nonha fatto stranezze (ma credo di no...)
ciao e grazie
Davide

 ha scritto

--- +++ ---
non si riesce intanto a ridurre il blocco da considerare a
--- +++
?
poi
con fso sai subito quante linee hai.
usare il for 1 to numlines, con step 3 o step 6 ?
a naso dovresti poter evitare gli if
scusa, qui c'e' casino e non riesco a mettere meglio a fuoco.
pensaci solo un secondo.



Non ho capito il significato di questa frase: le linee inutili sono in
numero fisso o variabile?
Ciaotutti,
*

 ha scritto

molto a occhio
non capisco bene come puo' esistere una struttura
    3 inutili
    3 utili
    3 inutili
    ...
dovrebbe equivalere a
    3 inutili
    3 utili
    ...
o
    3 inutili iniziali
    3 utili
    6 inutili
    3 utili
    3 inutili finali
con fso puoi sapere subito quante linee ha il file. dividendo questo
valore per 2 per 3 o quello che e' (lo decidi sulla struttura delle
righe utili e inutili) sai di quanti elementi ha bisogno il tuo array.
quindi il redim lo fai tendenzialmente una volta sola.
se sei sicuro che le righe buone sono 3 consecutive, l'importazione
delle stringhe le puoi fare in un for 0-2, anziche' testare ogni volta
la stringa con un if.
in tutti e due i casi il codice si complica un po' ma di tempo
dovresti risparmiarne parecchio.
hth

 ha scritto nel messaggio
news:at4mdb$10ejce$1...@ID-68324.news.dfncis.de...

variabile... per questo devo controlalre con degli if se c'è quello che mi
serve..
:(
comunque ho risolto con una prelettura e togliendo del codice che il mio
collega aveva inserito...
Ciao