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 ou en Red ? ===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. |