Parsing large files
none5-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
darkblue5-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
DideC11-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.


Powered by RebelBB and REBOL 2.7.8.4.2