Fichier données corrompu

Bonjour,
je souhaite savoir si vous avez déjà rencontré ce genre de problème.
Mon client a une base en client serveur mac, depuis plus de 10 ans.

Je découvre que le fichier de données est complètement corrompu, dans le genre :

  • des enregistrements disparaissent (je le sais par mon compteur d’id). Il y a des trous parfois de 1000 !
  • des enregistrement existent, ailleurs, avec les clefs étrangères qui pointent sur rien. Ce qui va avec le point précédent.
  • on dirait même que des enregistrements d’une table “passent” dans une autre.
  • j’ai une table de valeur, liée, avec 11 enregistrements. La table N comporte des clefs étrangères avec des valeurs sur 32 bits, genre 5462135466 alors que les ids ne vont que de 1 à 11…
  • si je teste le fichier par 4D, il me répond que tout est ok.
  • si j’applique la réparation profonde par marqueurs d’enregistrements, j’obtien un truc pire, complètement cassé et inutilisable, avec quasi toutes les clefs étrangères à 0 !

Un truc : la base, qui faisait 600 Mo et qui parait cohérent au vu de la complexité, est passée à 2,5 Go entre nov 2017 et mai 2018. On dirait qu’il y a eu un truc qui s’est passé, je ne le découvre que maintenant.

Donc :
Avez-vous déjà rencontré cela ?
Comment l’avez-vous réglé ?
Je me dis que je dois tout exporter et tout ré-importer, dans une base vierge, est-ce la bonne idée ?

Merci de vos réponse !

Bonjour,

Voici la (seule) bonne marche à suivre.
Restaurer les backups jusqu’à trouver un fichier de données qui semble correct, puis ré-intégrer les fichiers d’historiques depuis ce backup choisi.

Cordialement,

Quand la (seule) bonne démarche n’est pas possible (cas vécu du client sans backup), on peut aussi tout exporter/ré importer dans un data vierge. J’ai utilisé le SQL dans ce #&$* cas vécu.

Bonjour Olivier,
merci de ta réponse. Mais…

Ok, je dois retrouver le backup qui sera bon, ça remonte à un an et demi je crois…
Puis par contre, pour les fichiers d’historique, je fais comment ? Car 4D ne les sauve pas lors des backups, je n’ai donc que le dernier de ce jour…
J’ai loupé quelque chose ?

Arnaud,
j’ai les backups, mais je ne perds pas quelques jours, mais 1,5 année… la (seule) bonne démarche n’est pas possible !

Donc je vais faire ce export réimport. Ca tombe bien, j’ai un export de tout en générique (un fichier texte par table, et les images / blobs / objets sont sauvés avec un nom de fichier à numérotation incrémentielle).

Les imports, je les faisais toujours sur-mesure, car cela me servait pour mes nouveaux clients, et donc à re-structurer tout dans une base toute nouvelle.

Là, je n’ai plus que à faire l’import générique à l’envers, ça doit me prendre quelques heures.
Je vais déjà tester la taille de mon data après.

Tout ça pour ce #&$* cas que je vis ! Vivement qu’il devienne un vécu :slight_smile:

: Olivier GRIMBERT

Puis par contre, pour les fichiers d’historique, je fais comment ?
Car 4D ne les sauve pas lors des backups, je n’ai donc que le dernier
de ce jour…
J’ai loupé quelque chose ?
Bizarre, moi je les ai (à chaque 4bk son 4bl) , mais je réalise que je ne sais pas pourquoi. Tu as bien coché “utiliser le fichier d’historique” ?

: Olivier GRIMBERT

Ca tombe bien, j’ai un export de tout en générique (un fichier texte
par table, et les images / blobs / objets sont sauvés avec un nom de
fichier à numérotation incrémentielle).
J’avais utilisé SQL, ça structure de la même façon (texte + fichiers pour blobs et images) et ça ne m’avait pas coûté cher à écrire : une instruction pour exporter et pour importer il fallait juste écrire le “peignage” des dossiers/fichiers exportés. Je te mets le code que j’avais utilisé, au cas où.
C’est d’une part très rapide (appréciable quand on est obligé de faire ça à l’heure du hiboux), d’autre part passer par du texte réduit sans doute pas mal le risque de réimporter des enregistrements corrompus ; avec un mécanisme basé sur envoyer/recevoir enregistrement, je serais moins rassuré.
Si tu as des triggers et selon ce qu’ils font, il faut envisager de les shunter pendant l’import.

<code 4D>
//chemin du dossier créé avec SQL EXPORTER BASE
$root_t:=Convertir chemin POSIX vers systeme("/Users/arnaud/jeSuisMaaaaalaaaadeeeeuuu/SQLExport/")
Boucle ($table_l;1;Lire numero derniere table)
Si (Est un numero de table valide($table_l))
$table_p:=Table($table_l)
$tableFolder_t:=$root_t+Nom de la table($table_l)+Séparateur dossier
Si (Tester chemin acces($tableFolder_t)=Est un répertoire)
LISTE DES DOCUMENTS($tableFolder_t;$doc_at)
ASSERT(Compter dans tableau($doc_at;“Export.sql”)=1)
$script_t:=$tableFolder_t+“Export.sql”
ASSERT(Tester chemin acces($script_t)=Est un document)
xTrgOff ($table_p)
SQL EXECUTER SCRIPT($script_t;SQL Confirmer si erreur)
xTrgOn ($table_p)
Fin de si
Fin de si
Fin de boucle
</code 4D>

Merci Arnaud !
Mais ton code est la partie “évidente”. En fait, il me manque le sql…
Mais pas de soucis, car ma façon en fichier texte, avec échappement des CR et TAB, est rodée et fonctionne bien, pour l’avoir utilisée maintes fois.

Je viens de finaliser mon export (qui ignorait les objets), et qui gère d’ailleurs aussi les objets “Write Pro”, et j’ai tout exporté => j’obtiens un beau dossier de 730 Mo.
J’ai écrit l’import générique, qui est facile car il suffit de reprendre tout, mais j’ai géré quand même par les entêtes des noms de champs s’il y en a en trop (inconnus) ou en moins, et avec un ordre quelconque.

Import… 20 minutes et verdict : la base résultante fait maintenant 337 Mo au lieu de celle cassée qui fait 3,1 Go !!
Il y a bien donc un truc totalement cassé, que le CMS de 4D ne sait pas voir.

Je vais proposer à 4D de regarder pour améliorer le CMS.

T’avais testé un simple compactage :?:

: Olivier GRIMBERT

Mais ton code est la partie “évidente”. En fait, il me manque le sql…
Je ne pige pas, là, comment ça, il te manque ? J’avais utilisé SQL EXPORTER BASE, mais on peut aussi utiliser sql exporter selection. Je vois que tu as des champs qui ne seront pas “considérés” par SQL (objet, write pro), mais ça peut toujours être intéressant de voir si la récupération est meilleure. Ou recevoir/envoyer enregistrement…

: Olivier GRIMBERT

Mais pas de soucis, car ma façon en fichier texte, avec échappement
des CR et TAB, est rodée et fonctionne bien, pour l’avoir utilisée
maintes fois.
Partage de code (fit-il, intéressé) ?

Bon, tu as un sérieux souci, en effet :

j’obtiens un beau dossier de 730 Mo […] la base résultante fait
maintenant 337 Mo
je n’ai jamais jamais jamais vu un data 4d plus petit que le texte que j’y importais (sauf à tout stocker dans un blob compressé, ha ha ha), la perte est grande…

: Olivier GRIMBERT

Je vais proposer à 4D de regarder pour améliorer le CMS.
https://forums.4d.com/Post/FR/30119663/1/30119664#30119664J’en profite> pour battre le fer pendant qu’il est chaud, prévenir au lieu de guérir, un tiens vaut mieux que deux tu l’auras, etc.

Oui, bon, quelques explications…

: Arnaud DE MONTARD

Je ne pige pas, là, comment ça, il te manque ? J’avais utilisé SQL
EXPORTER BASE, mais on peut aussi utiliser sql exporter selection. Je
vois que tu as des champs qui ne seront pas “considérés” par SQL
(objet, write pro), mais ça peut toujours être intéressant de voir si
la récupération est meilleure. Ou recevoir/envoyer enregistrement…

Ben le “SQL EXPORTER BASE” n’est pas dans le code… mais bon, comme je veux TOUT récupérer…

: Arnaud DE MONTARD

Partage de code (fit-il, intéressé) ?

Oui bien sûr, quand il sera complètement débuggé… promis.

: Arnaud DE MONTARD

je n’ai jamais jamais jamais vu un data 4d plus petit que le texte
que j’y importais (sauf à tout stocker dans un blob compressé, ha ha
ha), la perte est grande…

Tu as raison, et cela m’a interpelé mais il y avait un bug où je n’importais pas la suite d’un champ supprimé, donc c’était partiel pour certaines bases. Mais c’est l’idée.
Là je suis en re-export, puis re-import et je donne le résultat dès que c’est fini.

: Manuel PIQUET

T’avais testé un simple compactage :?:

Bien sûr, rien ne bouge.
Réparation simple, ras.
Réparation par marqueurs d’enregistrements, ça casse tout. Toutes les clefs étrangères à 0, enfin j’ai pas creusé, mais c’est tout cassé.

Alors enfin, avec toutes les données, j’ai

451 Mo !!!

Donc oui, j’ai un GROS pb dans les données, Je vais faire un taow à 4D pour comprendre pourquoi le CSM ne voit rien, et pourquoi il ne peut pas réparer.

Quand le fer est chaud…

J’ai une interface avec des listbox tableau à sélection multiples, aussi je récupère un tableau des numéro de tables à exporter / importer que je passe aux chaque méthodes d’import ou d’export.

[]32670369;“Gestionnaire de liens…”[/]

L’export :

<code 4D>

C_POINTER($ptr_T_table_no)
$ptr_T_table_no:=$1

C_TEXT($RL;$FL)
$RL:=Char(Carriage return)
$FL:=Char(Tab)

ARRAY TEXT($T_field_name;0)
ARRAY LONGINT($T_field_no;0)

C_TEXT($path;$path_img;$path_blob;$path_object;$path_WParea)
C_LONGINT($no_img;$no_blob;$no_object;$no_WParea)
//$path:=“oleeku:Users:oleeku:Desktop:Orem Export:”
//OK:=1
$path:=Select folder(“Dossier de destination :”)
If (OK=1)

$path_img:=$path+"images"
$path_blob:=$path+"blobs"
$path_object:=$path+"objects"
$path_WParea:=$path+"WParea"
If (Test path name($path_img)<0)
	CREATE FOLDER($path_img)
End if 
If (Test path name($path_blob)<0)
	CREATE FOLDER($path_blob)
End if 
If (Test path name($path_object)<0)
	CREATE FOLDER($path_object)
End if 
If (Test path name($path_WParea)<0)
	CREATE FOLDER($path_WParea)
End if 

C_TEXT($table_name;$txt;$field_value;$field_name)
C_BOOLEAN($is_invisible;$is_first;$is_index;$is_unique)
C_LONGINT($no_table;$nb_fields;$no_field;$ch1;$field_type;$field_lenght;$k;$lno;$nb_records;$no_record)
C_POINTER($table;$ptr_field)
C_TIME($vRef)

C_LONGINT($tt_idx_table;$idx_table)
$tt_idx_table:=Size of array($ptr_T_table_no->)

C_LONGINT($progressId)
C_BOOLEAN($isStopProgress)
$progressId:=wog_progress_new ("Export...")
wog_progress_setButton ($progressId;True)
$isStopProgress:=False

For ($idx_table;1;$tt_idx_table)
	$no_table:=$ptr_T_table_no->{$idx_table}
	wog_progress_setCounts ($progressId;$idx_table;$tt_idx_table)
	If (Is table number valid($no_table))
		$table:=Table($no_table)
		GET TABLE PROPERTIES($no_table;$is_invisible)
		If (Not($is_invisible))
			ALL RECORDS($table->)
			$nb_records:=Records in selection($table->)
			If ($nb_records>0)
				
				$table_name:=Table name($no_table)
				wog_progress_setTitleRegular ($progressId;$table_name)
				
				$vRef:=Create document($path+$table_name+".txt";"TEXT")
				$nb_fields:=Get last field number($no_table)
				
				  //REORGANISE
				ARRAY LONGINT($T_field_no;0)
				ARRAY TEXT($T_field_name;0)
				
				For ($no_field;1;$nb_fields)
					If (Is field number valid($no_table;$no_field))
						GET FIELD PROPERTIES($no_table;$no_field;$field_type;$field_lenght;$is_index;$is_unique;$is_invisible)
						If (Not($is_invisible)) & ($field_type#7)  //Visible et non sous-tables
							APPEND TO ARRAY($T_field_name;Field name($no_table;$no_field))
							APPEND TO ARRAY($T_field_no;$no_field)
						End if 
					End if 
				End for 
				
				$ch1:=Find in array($T_field_name;"id")  //Mettre Code en premier
				If ($ch1>0)
					$ptr_field:=Field($no_table;$ch1)
					QUERY SELECTION($table->;$ptr_field->#0)
				End if 
				
				$nb_fields:=Size of array($T_field_no)
				  //Sortie titre des champs
				$txt:=""
				$is_first:=True
				For ($no_field;1;$nb_fields)
					$ch1:=$T_field_no{$no_field}
					If ($ch1#0)
						If ($is_first)
							$is_first:=False
						Else 
							$txt:=$txt+$FL
						End if 
						$txt:=$txt+Field name($no_table;$ch1)
					End if 
				End for 
				SEND PACKET($vRef;$txt+$RL)
				
				$no_img:=0
				$no_blob:=0
				$no_object:=0
				$no_WParea:=0
				
				  // Export Table
				C_LONGINT($progressSubId)
				C_BOOLEAN($isStopProgressSub)
				$progressSubId:=wog_progress_new ($table_name)
				wog_progress_setButton ($progressSubId;True)
				$isStopProgressSub:=False
				
				For ($no_record;1;$nb_records)
					wog_progress_setCounts ($progressSubId;$no_record;$nb_records)
					$txt:=""
					$is_first:=True
					For ($no_field;1;$nb_fields)
						$ch1:=$T_field_no{$no_field}
						If ($ch1#0)
							GET FIELD PROPERTIES($no_table;$ch1;$field_type;$field_lenght;$is_index;$is_unique;$is_invisible)
							$ptr_field:=Field($no_table;$ch1)
							$field_name:=Field name($ptr_field)
							$field_value:=""
							Case of 
								: ($field_type=Is alpha field)  //Alpha
									$field_value:=$ptr_field->
									$field_value:=Replace string($field_value;Char(Carriage return);"")
									$field_value:=Replace string($field_value;Char(Tab);"")
									
								: ($field_type=Is real)  //Numéric
									$field_value:=String($ptr_field->)
									
								: ($field_type=Is text)  //Text
									$field_value:=$ptr_field->
									$k:=Length($field_value)
									If ($k>=32000)
										$field_value:=Substring($field_value;1;31999)
									End if 
									$field_value:=Replace string($field_value;Char(Carriage return);Char(254))
									$field_value:=Replace string($field_value;Char(Tab);Char(253))
									
									
								: ($field_type=Is date)  //Date
									$field_value:=String($ptr_field->)
									
								: ($field_type=Is boolean)  //Booleen
									$field_value:="NO"[Num($ptr_field->)+1]
									
								: ($field_type=Is integer)  //Entier
									$field_value:=String($ptr_field->)
									
								: ($field_type=Is longint)  //Entier long
									$field_value:=String($ptr_field->)
									
								: ($field_type=Is time)  //Heure
									$field_value:=String($ptr_field->)
									
								: ($field_type=Is picture)  //Image
									If (Picture size($ptr_field->)#0)
										$no_img:=$no_img+1
										  //$NomIMG:="IMG"+Chaine($NoIMG)
										$field_value:=$table_name+String($no_img)
										WRITE PICTURE FILE($path_img+Folder separator+$field_value;$ptr_field->;"PICT")
									Else 
										$field_value:=""
									End if 
									
								: ($field_type=Is BLOB)  //Blob
									If (BLOB size($ptr_field->)#0)
										$no_blob:=$no_blob+1
										  //$NomBLOB:="BLOB"+Chaine($NoBLOB)
										$field_value:=$table_name+String($no_blob)
										BLOB TO DOCUMENT($path_blob+Folder separator+$field_value;$ptr_field->)
									Else 
										$field_value:=""
									End if 
									
								: ($field_type=Is object)  //Object
									If ($field_name="WParea")
										If ($ptr_field->#Null)
											$no_WParea:=$no_WParea+1
											$field_value:=$table_name+String($no_WParea)
											WP EXPORT DOCUMENT($ptr_field->;$path_WParea+Folder separator+$field_value;wk 4wp)
										End if 
									Else 
										$txt:=JSON Stringify($ptr_field->)
										$no_object:=$no_object+1
										$field_value:=$table_name+String($no_object)+".json"
										TEXT TO DOCUMENT($path_object+Folder separator+$field_value;$txt)
									End if 
							End case 
							If ($is_first)
								$is_first:=False
							Else 
								SEND PACKET($vRef;$FL)
							End if 
							SEND PACKET($vRef;$field_value)
						End if 
					End for 
					NEXT RECORD($table->)
					SEND PACKET($vRef;$RL)
					$isStopProgressSub:=wog_progress_isStopped ($progressSubId)
					If ($isStopProgressSub)
						$no_record:=$nb_records
					End if 
				End for 
				CLOSE DOCUMENT($vRef)
				wog_progress_quit ($progressSubId)
			End if 
		End if 
		If ($isStopProgress)
			$idx_table:=$tt_idx_table
		Else 
			$isStopProgress:=wog_progress_isStopped ($progressId)
		End if 
	End if 
End for 

wog_progress_quit ($progressId)

End if

</code 4D>

L’import :

<code 4D>

C_POINTER($ptr_T_table_no)
$ptr_T_table_no:=$1

C_TEXT($path;$path_img;$path_blob;$path_object;$path_WParea)
C_LONGINT($no_img;$no_blob;$no_object;$no_WParea)
//$path:=“oleeku:Users:oleeku:Desktop:Orem Export:”
//OK:=1
$path:=Select folder(“Dossier à importer :”)
If (OK=1)
//v_FiltreImport

$path_img:=$path+"images"
$path_blob:=$path+"blobs"
$path_object:=$path+"objects"
$path_WParea:=$path+"WParea"

  //$is_delete_tables:=(R0=1)
C_BOOLEAN($is_delete_tables)
$is_delete_tables:=True

C_TEXT(<>Simport)

C_TEXT($txt;$table_name;$field_value;$field_name)
C_BOOLEAN($is_invisible;$is_first;$is_index;$is_unique)
C_LONGINT($no_table;$nb_fields;$no_field;$ch1;$field_type;$field_lenght;$k;$lno;$nb_records;$no_record)
C_POINTER($table;$ptr_field)
C_BOOLEAN($is_run;$isOk)
C_TIME($DocRef)

 C_LONGINT($tt_idx_table;$idx_table)
$tt_idx_table:=Size of array($ptr_T_table_no->)

C_LONGINT($progressId)
C_BOOLEAN($isStopProgress)
$progressId:=wog_progress_new ("Import...")
wog_progress_setButton ($progressId;True)
$isStopProgress:=False

For ($idx_table;1;$tt_idx_table)
	$no_table:=$ptr_T_table_no->{$idx_table}
	wog_progress_setCounts ($progressId;$idx_table;$tt_idx_table)
	If (Is table number valid($no_table))
		$table:=Table($no_table)
		GET TABLE PROPERTIES($no_table;$is_invisible)
		If (Not($is_invisible))
			$table_name:=Table name($no_table)
			C_TEXT($path_file)
			C_BOOLEAN($is_exist)
			$path_file:=$path+$table_name+".txt"
			$is_exist:=(Test path name($path_file)=Is a document)
			If ($is_exist)
				$DocRef:=Open document($path_file;Read mode)
				If (OK=1)
					wog_progress_setTitleRegular ($progressId;$table_name)
					
					  // Import Table
					C_LONGINT($progressSubId)
					C_BOOLEAN($isStopProgressSub)
					$progressSubId:=wog_progress_new ($table_name)
					wog_progress_setButton ($progressSubId;True)
					$isStopProgressSub:=False
					
					RECEIVE PACKET($DocRef;<>Simport;Char(13))
					C_LONGINT($tt;$spThermometre)
					$tt:=Get document size($DocRef)
					$spThermometre:=Length(<>Simport)
					
					$nb_fields:=Get last field number($no_table)
					ARRAY LONGINT($T_field_no;0)
					ARRAY TEXT($T_field_name;0)
					For ($no_field;1;$nb_fields)
						If (Is field number valid($no_table;$no_field))
							GET FIELD PROPERTIES($no_table;$no_field;$field_type;$field_lenght;$is_index;$is_unique;$is_invisible)
							If (Not($is_invisible)) & ($field_type#7)  //Visible et non sous-tables
								APPEND TO ARRAY($T_field_name;Field name($no_table;$no_field))
								APPEND TO ARRAY($T_field_no;$no_field)
							End if 
						End if 
					End for 
					
					<>Posfield:=1
					ARRAY LONGINT($T_field_no1;0)
					ARRAY LONGINT($T_field_no1;$nb_fields)  // To manage inex fields in file
					ARRAY LONGINT($T_field_noImport;0)  // Vide
					ARRAY LONGINT($T_field_noImport;$nb_fields)
					$is_run:=True
					$no_field:=0
					While ($is_run)
						$no_field:=$no_field+1
						$txt:=v_imp_NextField 
						If ($txt#"")
							$k:=Find in array($T_field_name;$txt)
							If ($k>0)
								$T_field_noImport{$k}:=$no_field
								$T_field_no1{$no_field}:=$T_field_no{$no_field}
							End if 
						Else 
							$is_run:=False
						End if 
					End while 
					
					SORT ARRAY($T_field_noImport;$T_field_no1;$T_field_name)
					C_LONGINT($nb;$i)
					$nb:=0
					For ($i;1;$nb_fields)
						If ($T_field_noImport{$i}#0)
							$nb:=$i-1
							$i:=$nb_fields
						End if 
					End for 
					DELETE FROM ARRAY($T_field_noImport;1;$nb)
					
					DELETE FROM ARRAY($T_field_name;1;$nb)
					DELETE FROM ARRAY($T_field_no1;1;$nb)
					$nb_fields:=Size of array($T_field_no1)
					
					
					READ WRITE($table->)
					If ($is_delete_tables)
						wog_progress_setTitleRegular ($progressSubId;"Delete")
						ALL RECORDS($table->)
						DELETE SELECTION($table->)
					End if 
					
					wog_progress_setTitleRegular ($progressSubId;"Import")
					$is_run:=True
					While ($is_run) & Not($isStopProgressSub)
						RECEIVE PACKET($DocRef;<>Simport;Char(13))
						$spThermometre:=$spThermometre+Length(<>Simport)
						wog_progress_setCounts ($progressSubId;$spThermometre;$tt)
						If (<>Simport#"")
							CREATE RECORD($table->)
							<>Posfield:=1
							$isOk:=True
							For ($no_field;1;$nb_fields)
								$ch1:=$T_field_no1{$no_field}
								If ($ch1#0)
									GET FIELD PROPERTIES($no_table;$ch1;$field_type;$field_lenght;$is_index;$is_unique;$is_invisible)
									$ptr_field:=Field($no_table;$ch1)
									$field_name:=Field name($ptr_field)
									$field_value:=v_imp_NextField 
									If ($field_name="id")
										$isOk:=(Num($field_value)#0)
										If (Not($isOk))
											$no_field:=$nb_fields
										End if 
									End if 
									Case of 
										: ($field_type=Is alpha field)
											$ptr_field->:=$field_value
											
										: ($field_type=Is real)
											$ptr_field->:=Num($field_value)
											
										: ($field_type=Is text)
											$field_value:=Replace string($field_value;Char(254);Char(Carriage return))
											$field_value:=Replace string($field_value;Char(253);Char(Tab))
											$ptr_field->:=$field_value
											
										: ($field_type=Is date)
											$ptr_field->:=Date($field_value)
											
										: ($field_type=Is boolean)
											$ptr_field->:=($field_value="O")
											
										: ($field_type=Is integer)
											$ptr_field->:=Num($field_value)
											
										: ($field_type=Is longint)
											$ptr_field->:=Num($field_value)
											
										: ($field_type=Is time)
											$ptr_field->:=Time($field_value)
											
										: ($field_type=Is picture)
											If ($field_value#"")
												READ PICTURE FILE($path_img+Folder separator+$field_value;$ptr_field->)
											End if 
											
										: ($field_type=Is BLOB)
											If ($field_value#"")
												DOCUMENT TO BLOB($path_blob+Folder separator+$field_value;$ptr_field->)
											End if 
											
										: ($field_type=Is object)
											If ($field_value#"")
												If ($field_name="WParea")
													$ptr_field->:=WP Import document($path_WParea+Folder separator+$field_value+".4wp")
												Else 
													$txt:=Document to text($path_object+Folder separator+$field_value)
													If ($txt#"undefined")
														$ptr_field->:=JSON Parse($txt)
													End if 
												End if 
											End if 
									End case 
								End if 
							End for 
							If ($isOk)
								SAVE RECORD($table->)
							End if 
							
						Else 
							$is_run:=False
						End if 
						$isStopProgressSub:=wog_progress_isStopped ($progressSubId)
					End while 
					CLOSE DOCUMENT($DocRef)
					x_closeTable ($table)
					wog_progress_quit ($progressSubId)
					$isStopProgress:=$isStopProgressSub
				End if 
			End if 
		End if 
	End if 
	If ($isStopProgress)
		$idx_table:=$tt_idx_table
	Else 
		$isStopProgress:=wog_progress_isStopped ($progressId)
	End if 
End for 
wog_progress_quit ($progressId)
  //USE CHARACTER SET(*;1)

End if

</code 4D>

Et la méthode qui parse les lignes de texte, sur le TAB “v_imp_NextField” :

<code 4D>
C_LONGINT($i;$j)
C_TEXT($result)
$i:=Position(Char(Tab);Substring(<>Simport;<>Posfield))

Case of
: ($i=0)
$result:=Substring(<>Simport;<>Posfield)
<>Posfield:=Length(<>Simport)+1
: ($i=1)
$result:=""
Else
$result:=Substring(<>Simport;<>Posfield;$i-1)
End case
<>Posfield:=<>Posfield+$i

v_Rub_MSpaces (->$result)

$0:=$result

</code 4D>

Et la suppression des espaces :

<code 4D>

//—Procédure
//— enlève les espaces avant et après

C_POINTER($1) //— objet cible
C_LONGINT($i;$n)
C_TEXT($result)

$n:=Length($1->)
If ($n#0)
$result:=""
For ($i;1;$n)
If ($1->[$i]#" ")
$result:=Substring($1->;$i)
$i:=$n
End if
End for

$n:=Length($result)
While (Substring($result;$n;1)=" ") & ($n>0)
	$n:=$n-1
End while 
If ($n>0)
	$result:=Substring($result;1;$n)
End if   //$n>0
$1->:=$result

End if

</code 4D>

… et une précision, les méthodes “wog_progress…” sont celles de mon composant (payant !) ogTools, pour des progressbars. Vous pouvez facilement le changer pour un autre.

… et la clef primaire doit s’appeler “ID”.

Ce test permet juste d’enlever à l’export comme à l’import des enregistrements qui auraient l’id à zéro.