![]() |
| Parsing large files | |
| none | 5-Jul-2016/9:55:05+2:00 |
| Hello, Quelle est la méthode la plus efficace pour parser un très gros fichier (1 à 2 Go) structuré ainsi: chaque bloc de datas est séparé du bloc suivant par deux sauts de lignes (#{0A0A}), au sein d'un bloc chaque ligne est séparée de la suivante par un saut de ligne suivie d'une tabulation (#{0A09}). Les blocs peuvent contenir un nombre différents de lignes de datas (entre 4 et 8 environ). <code> Thu Jun 30 01:17:17 2016 key1 = value1 key2 = value2 ... key8 = value8 Thu Jun 30 01:17:18 2016 key1 = autrevalue1 key2 = autrevalue2 ... key5 = autrevalue5 </code> je voudrais obtenir en sortie un CSV du genre : Thu Jun 30 01:17:17 2016;key1=value1;key2=value2; ...;key8=value8; Thu Jun 30 01:17:18 2016;key1=autrevalue1;key2=autrevalue2; ...;key5=autrevalue5; Un peu rouillé là sur Rebol... Faut que je m'y remette ===Philippe | |
| darkblue | 5-Jul-2016/11:06:49+2:00 |
| Bonjour, je pense qu'il faudrait que tu ouvres le fichier via un port, puis que tu bufferises chaque ligne jusqu'à atteindre le double saut de lignes une fois obtenu le double saut de ligne ou fin de fichier tu traites ton buffer dès que j'ai 2mn de libre je te proposes un exemple de code | |
| DideC | 11-Jul-2016/17:24:20+2:00 |
J'ai un prog qui fait parse plusieurs méga en utilisant cette fonction qui découpe ligne par ligne (à adapter pour ton propre séparateur de ligne) :parse-big-file: func [
{Parse un fichier texte important en le lisant par morceau et le parsant ligne par ligne.}
file [file! url!] {Fichier à lire et parser.}
rules [block!] {Règles de parsing à appliquer à chaque ligne lue du fichier. La ligne en cours est dans 'line.}
/size {Permet de spécifier la taille du buffer de lecture.}
blk-size [integer!] {Taille du buffer.}
/progress {Permet de spécifier une fonction à appeler pour montrer la progression.}
progfunc [function!] {Fonction à appeler de la forme "Fonction position position-maxi".}
/local data line begin end
] [
blk-size: any [blk-size 32768] ; 32768 65536 131072
data: make string! blk-size * 2
; On bind les règles utilisateurs dans le contexte de la fonction.
bind rules 'blk-size
; ouverture du port sur le fichier
port: open/read/seek file
; parcours du contenu du fichier
forskip port blk-size [
; lecture d'un block de données
insert tail data copy/part port blk-size
; Affichage de la progression
if :progfunc [progfunc port/state/index port/size]
; découpage en lignes
parse data [
some [
begin: to newline end: (
line: copy/part begin end
remove/part data next end
end: head data
) :end
; exécution du code utilisateur
rules
]
pos: thru end end
]
]
close port
; s'il reste une ligne sans saut de ligne : on la traite
if not empty? data [parse data [line: rules]]
]Pour afficher la progression j'ai ce code qui gère une fenêtre avec une jauge : ;--- Gestion de l'affichage de la progression dans une fenêtre
context [
win: prog: tmr: none
prc: 0
tmu: none
set 'show-progress func [file] [
; masque la fenêtre si on passe -1 en valeur et maxi
if not win [
win: view/new layout [
origin 4 space 0x4
backdrop
apptitle
across
label "Lecture du fichier" labyel form file
labgray rejoin ["(" form-byte-size size? file ") ..."] return
across prog: progress tmr: label 200
]
tmu: now/time/precise
]
]
set 'update-progress func [val max /local t v] [
if prc <> prc: to-integer 100 * prog/data: val / max [
if prc > 5 [
t: pick now/time/precise - tmu 3
tmr/text: reform [1 + to-integer t * 100 / prc - t " secondes restantes"]
show tmr
]
show prog
]
]
set 'hide-progress does [
; masque la fenêtre si on passe -1 en valeur et maxi
if win [unview/only win exit]
]
]Le tout est utilisé par cette fonction dans laquelle tu doit mettre tes propres règles de parsing de la "ligne" extraite, qui affiche la progression et même le temps total d'exécution : fic-log: %/ton/fichier/a/lire.txt
form-byte-size: func [
{Formate une taille en octet ou multiple selon l'ordre de grandeur du nombre.}
v [number!]
/local div unit
] [
unit: case [
v > div: 1073741824 ["Go"]
v > div: 1048576 ["Mo"]
v > div: 1024 ["Ko"]
true [return join round/to to-decimal v 1 "o"]
]
rejoin [round/to to-decimal v / div 0.1 unit]
]
parse-log: has [t err et tes propres variables locales] [
; print ["Lecture du fichier" fic-log rejoin ["(" form-byte-size size? fic-log ") ..."]]
t: now/time/precise
show-progress fic-log
parse-big-file/progress fic-log [
(if error? err: try [
parse/all line [
; Mettre ici tes règles de parsing
]
] [print ["Erreur parsing:" line newline disarm err]])
] :update-progress
hide-progress
; print [newline "Durée : " now/time/precise - t]
]Il y a surement plus propre ou mieux fait, voir c'est pas parfait, mais en attendant, ça marche avec des fichiers de 200 Mo et plus. En espérant que ça t'aidera. | |
|
Login required to Post. | |