Importando um arquivo texto sem delimitadores


O processo de importação de um arquivo texto no Protheus não é lá um processo muito simples, mas não impossível de se fazer, o mais fácil é quando temos um arquivo com delimitadores, seja usando ponto e vírgula (;), ou usando o pipe (|), barra (/), entre outros caracteres. Agora importar um arquivo texto sem delimitadores, já torna o processo um pouco mais chato, mas também nada impossível de se fazer. Alguns colegas que estão começando sempre me perguntam, tem alguma forma mais fácil de se fazer? Digo que depende muito da lógica a ser usada, mas os comandos serão sempre os mesmo. Neste artigo, irei demonstrar um exemplo de importação de arquivo texto sem delimitadores para que você possa utilizá-lo no seu dia a dia, mas para aqueles que fazem isso e tiver um exemplo mais fácil, compartilhe conosco, toda dica é bem vinda. Primeiramente irei mostrar o formato do arquivo texto, neste exemplo será um bem simples. (Arquivo exemplo) exemploarquivotextoparaimportar Tela inicial: colocarei todos os campos contidos no meu arquivo texto. Utilizarei os componentes: Say() = Exibe textos em uma tela de interface com o usuário MsGet() = Permite que o usuário digite informações na tela, conforme a necessidade da aplicação. TCBrowse() = Cria um objeto do tipo grade. Button() = Criar um botão na tela para que o usuário interaja com a aplicação. Desenhei a tela utilizando o programa GAIA 2010. exemploarquivotextoparaimportartelainicial Para selecionar o arquivo, usarei a função cGetFile (Apresenta uma janela com os diretórios disponíveis, na estação e no servidor,  e retorna o nome do item.) , para saber mais sobre esta função consulte o TDN (http://tdn.totvs.com/display/tec/cGetFile). exemploarquivotextoparaimportarabrindoarquivo Após selecionar o arquivo e confirmá-lo, o arquivo é importado para a tela criada. Você poderia perfeitamente importar diretamente numa tabela. exemploarquivotextoparaimportartelainicialconteudo Visualizando assim, parece tudo simples não é mesmo?

#Include 'Protheus.ch'

User Function exemplo3()
	/*Declaração das variáveis locais*/
	Local oButton1
	Local oButton2
	Local oSim    := LoadBitmap(GetResources(), "ENABLE")
	Local oNao    := LoadBitmap(GetResources(), "DISABLE")
	Local oCEP
	Local oCidade
	Local oCNPJ
	Local oComplemento
	Local oContato
	Local oEmail
	Local oEmissao
	Local oEmpresa
	Local oEndereco
	Local oEntrega
	Local oMoeda
	Local oPagto
	Local oPedido
	Local oUF

	/*Declaração das variáveis privadas*/
	Private oPedidos
	Private cPedido 	:= Space(06)
	Private cCNPJ 		:= Space(14)
	Private cCEP 		:= Space(8)
	Private cEmpresa 	:= Space(30)
	Private cEndereco 	:= Space(100)
	Private cCidade 	:= Space(30)
	Private cUF 		:= Space(2)
	Private cContato 	:= Space(30)
	Private cEmail 		:= Space(200)
	Private dEmissao 	:= CTOD("//")
	Private dEntrega 	:= CTOD("//")
	Private cMoeda 		:= Space(30)
	Private cPagto 		:= Space(30)
	Private cComplemento:= Space(100)
	Private aPedidos    := {}
	
	/*Declaração das variáveis estáticas*/
	Static oDlg
	
	DEFINE MSDIALOG oDlg TITLE "Importando arquivo texto não delimitado" FROM 000, 000  TO 400, 500 PIXEL
	
	@ 003, 005 SAY oSay1 PROMPT "Pedido" SIZE 025, 007 OF oDlg PIXEL
	@ 011, 005 MSGET oPedido VAR cPedido SIZE 036, 010 OF oDlg PIXEL
	@ 003, 046 SAY oSay2 PROMPT "CNPJ" SIZE 025, 007 OF oDlg PIXEL
	@ 011, 046 MSGET oCNPJ VAR cCNPJ SIZE 061, 010 OF oDlg PIXEL
	@ 003, 112 SAY oSay3 PROMPT "Empresa" SIZE 025, 007 OF oDlg PIXEL
	@ 011, 112 MSGET oEmpresa VAR cEmpresa SIZE 131, 010 OF oDlg PIXEL
	@ 024, 005 SAY oSay4 PROMPT "Endereço" SIZE 025, 007 OF oDlg PIXEL
	@ 031, 005 MSGET oEndereco VAR cEndereco SIZE 101, 010 OF oDlg PIXEL
	@ 024, 112 SAY oSay5 PROMPT "Cidade" SIZE 025, 007 OF oDlg PIXEL
	@ 031, 112 MSGET oCidade VAR cCidade SIZE 110, 010 OF oDlg PIXEL
	@ 024, 227 SAY oSay6 PROMPT "UF" SIZE 014, 007 OF oDlg PIXEL
	@ 031, 227 MSGET oUF VAR cUF SIZE 016, 010 OF oDlg PIXEL
	@ 044, 005 SAY oSay7 PROMPT "CEP" SIZE 025, 007 OF oDlg PIXEL
	@ 051, 005 MSGET oCEP VAR cCEP SIZE 036, 010 OF oDlg PIXEL
	@ 044, 046 SAY oSay8 PROMPT "Contato" SIZE 025, 007 OF oDlg PIXEL
	@ 051, 046 MSGET oContato VAR cContato SIZE 061, 010 OF oDlg PIXEL
	@ 044, 112 SAY oSay9 PROMPT "E-mail" SIZE 025, 007 OF oDlg PIXEL
	@ 051, 112 MSGET oEmail VAR cEmail SIZE 131, 010 OF oDlg PIXEL
	
	//Usando o TCBrowse para gerenciar individualmente cada coluna
	oPedidos := TCBrowse():New(067, 005,238, 060,,,,oDlg,,,,,,,,,,,,.F.,,.T.,,.F.,,,)
	oPedidos:AddColumn(TCColumn():New(" "       		, {|| If(aPedidos[oPedidos:nAt,01],oSim,oNao) },,,,,,.T.,.F.,,,,.F., ) )
	oPedidos:AddColumn(TCColumn():New("Codigo"  		, {|| aPedidos[oPedidos:nAt,02]},"@!",,,"CENTER", 025,.F.,.F.,,{|| .F. },,.F., ) )
	oPedidos:AddColumn(TCColumn():New("Descrição"  	, {|| aPedidos[oPedidos:nAt,03]},"@!",,,"LEFT", 040,.F.,.F.,,{|| .F. },,.F., ) )
	oPedidos:AddColumn(TCColumn():New("No.Serie"  	, {|| aPedidos[oPedidos:nAt,04]},"@!",,,"LEFT", 080,.F.,.F.,,{|| .F. },,.F., ) )
	oPedidos:AddColumn(TCColumn():New("Qtde"  		, {|| aPedidos[oPedidos:nAt,05]},"@E 999,999,999.99",,,"RIGHT", 040,.F.,.F.,,{|| .F. },,.F., ) )
	oPedidos:AddColumn(TCColumn():New("Valor"  		, {|| aPedidos[oPedidos:nAt,06]},"@E 999,999,999.99",,,"RIGHT", 040,.F.,.F.,,{|| .F. },,.F., ) )
	oPedidos:AddColumn(TCColumn():New("Total"  		, {|| aPedidos[oPedidos:nAt,07]},"@E 999,999,999.99",,,"RIGHT", 040,.F.,.F.,,{|| .F. },,.F., ) )
	oPedidos:AddColumn(TCColumn():New("Observação"  	, {|| aPedidos[oPedidos:nAt,08]},"@!",,,"LEFT", 120,.F.,.F.,,{|| .F. },,.F., ) )
		
	oPedidos:SetArray(aPedidos)  //Define um array para o browse
	
	oPedidos:bWhen := { || Len(aPedidos) > 0 } //Se o array estiver vazio, o browse fica desabilitado
	oPedidos:Refresh()
	
	@ 130, 005 SAY oSay10 PROMPT "Cond.Pagto" SIZE 035, 007 OF oDlg PIXEL
	@ 138, 005 MSGET oPagto VAR cPagto SIZE 113, 010 OF oDlg PIXEL
	@ 130, 122 SAY oSay11 PROMPT "Emissão" SIZE 025, 007 OF oDlg PIXEL
	@ 138, 122 MSGET oEmissao VAR dEmissao SIZE 041, 010 OF oDlg PIXEL
	@ 130, 169 SAY oSay12 PROMPT "Entrega" SIZE 025, 007 OF oDlg PIXEL
	@ 138, 169 MSGET oEntrega VAR dEntrega SIZE 041, 010 OF oDlg PIXEL
	@ 130, 214 SAY oSay13 PROMPT "Moeda" SIZE 020, 007 OF oDlg PIXEL
	@ 138, 214 MSGET oMoeda VAR cMoeda SIZE 030, 010 OF oDlg PIXEL
	@ 153, 005 SAY oSay14 PROMPT "Complemento:" SIZE 038, 007 OF oDlg PIXEL
	@ 160, 005 MSGET oComplemento VAR cComplemento SIZE 238, 010 OF oDlg PIXEL
	
	//Para o processamento, utilizarei a função Processa()
	//A função Processa() exibe um diálogo onde a execução 
	//de um processo pode ser monitorada através da régua de progressão.
	@ 181, 155 BUTTON oButton1 PROMPT "Importar" SIZE 037, 012 OF oDlg ACTION Processa({|| Importar()},"Aguarde...") PIXEL
	@ 181, 207 BUTTON oButton2 PROMPT "Fechar" SIZE 037, 012 OF oDlg ACTION oDlg:End() PIXEL
	
	ACTIVATE MSDIALOG oDlg CENTERED
Return

//Função para importar o arquivo texto.

Static Function Importar()
	Local cArquivo := cGetFile("Arquivo TXT (*.TXT) |*.TXT|","Selecione o Arquivo...",2,,.T.,GETF_LOCALHARD+GETF_NETWORKDRIVE)
	Local aItens  := {}
	Local aFornece:= {}
	Local aRodape := {}
	Local nCont   := 0
	Local i       := 0
	Local nLinhas := 0
	Local _aStr   := {{"Texto","C",1000,0}}
	Local _cTmp   := CriaTrab(NIL,.F.)
	Local nQtde   := 0
	Local nValor  := 0
	Local nTotal  := 0	
	
	if !file(Alltrim(cArquivo))
		Alert("Arquivo "+Alltrim(cArquivo)+" não existe!"+CRLF+"Abortando importação!")
		Return
	Endif
	
	//Criarei uma tabela temporária para armazenar cada linha do meu txt, poderia usar um array
	//mas irei motrar tambem como criar uma tabela temporária
	
	//dbCreate = Define uma nova tabela ou um novo arquivo do tipo tabela e sua estrutura (campos)
	dbCreate(_cTmp,_aStr)
	
	//Verifico se a área de trabalho está aberta, se estiver irei fechar, isso evita que o sistema
	//dê um erro informando que a área ja está aberta
	IF SELECT("TRB") # 0
		TRB->(dbCloseArea())
	ENDIF
	
	//DBUseArea = Abre uma tabela de dados na área de trabalho atual ou na primeira área de trabalho disponível.
	DBUseArea(.T.,,_cTmp,"TRB",.F.,.F.)
	
	//GetSrvProfString = Recupera o conteúdo de uma chave de configuração, do ambiente em uso, no arquivo de 
	//configuração (.INI) do TOTVS Application Server.

	if AT(":\",cArquivo)>0
		CpyT2S( cArquivo, GetSrvProfString("Startpath","") )
	Else
		CpyT2S( cArquivo, GetSrvProfString("Startpath","") )
	endif
	

	//Append From = Utilização do comando 'APPEND FROM ... SDF', para importação de dados de um arquivo texto
	Append From &cArquivo SDF 
	
	//Vou para o inicio do arquivo
	TRB->(dbGoTop())
	
	//conto quantas linhas eu tenho
	nLinhas:=TRB->(RecCount())
	
	//Monto minha regua de processamento com a quantidade de linhas encontradas
	ProcRegua(nLinhas)

	//Limpo a variavel que irá receber os dados
	aPedidos:={}

	//Inicio a leitura da minha tabela, enquanto não for o final dela
	While TRB->(!Eof())
		nCont++
		
		If lEnd
			MsgInfo("Cancelado!","Fim")
			exit
		Endif
		
		IF nCont > nLinhas
			exit
		endif
		
		//IncProc = informa o texto que irá ser apresentado na tela de processamento
		IncProc("Lendo arquivo texto...Linha "+Alltrim(str(nCont)))
		
		//Recebo o conteudo do meu texto
		cLinha := ALLTRIM(UPPER(TRB->Texto))
		
		if !empty(cLinha)
			/*
			Neste exemplo, o meu arquivo texto possui um campo inicial que identifica o que ele é:
			Linha que começa com 1 = Cabeçalho
			Linha que começa com 2 = Itens
			Linha que começa com 3 = Rodapé
			*/
						
			if Substr(cLinha,1,1)=="1"
				//aFornece[1][1] = PEDIDO			//Tamanho:  6
				//aFornece[1][2] = CNPJ				//Tamanho: 11				
				//aFornece[1][3] = NOMEDAEMPRESA	//Tamanho: 35
				//aFornece[1][4] = ENDERECO			//Tamanho: 30
				//aFornece[1][5] = CIDADE			//Tamanho: 18
				//aFornece[1][6] = UF				//Tamanho:  2
				//aFornece[1][7] = CEP				//Tamanho:  8 
				//aFornece[1][8] = CONTATO			//Tamanho: 21
				//aFornece[1][9] = EMAIL				//Tamanho:100
				
				aadd(aFornece,{Substr(cLinha,  2,  6),;
			 	Substr(cLinha,  8, 11),;
			 	Substr(cLinha, 22, 35),;
			 	Substr(cLinha, 58, 30),;
			 	Substr(cLinha, 89, 18),;
			 	Substr(cLinha,108,  2),;
			 	Substr(cLinha,110,  8),;
			 	Substr(cLinha,118, 21),;
			 	Substr(cLinha,140,100)})
																 
			Elseif Substr(cLinha,1,1)=="2"
				//aItens[1][1] = CODIGO			//Tamanho:  6
				//aItens[1][2] = DESCRICAO		//Tamanho: 25
				//aItens[1][3] = NUMEROSERIE	//Tamanho: 22
				//aItens[1][4] = QTDE			//Tamanho: 10
				//aItens[1][5] = VALOR			//Tamanho: 10
				//aItens[1][6] = OBSERVACAO		//Tamanho:100
				
				aadd(aItens,{	Substr(cLinha, 2,  6),;
			  	Substr(cLinha, 8, 25),;
			  	Substr(cLinha,34, 22),;
			  	Substr(cLinha,57, 10),;
			  	Substr(cLinha,67, 10),;
			  	Substr(cLinha,77,100)})
				
			Elseif Substr(cLinha,1,1)=="3" 
				//aItens[1][1] = PAGTO			//Tamanho: 17
				//aItens[1][2] = EMISSAO			//Tamanho: 10
				//aItens[1][3] = ENTREGA			//Tamanho: 10
				//aItens[1][4] = COMPLEMENTO	//Tamanho: 75
				//aItens[1][5] = MOEDA			//Tamanho: 30
				
				aadd(aRodape,{Substr(cLinha,  2,17),;
			  	Substr(cLinha, 20,10),;
			  	Substr(cLinha, 30,10),;
			  	Substr(cLinha, 40,75),;
			  	Substr(cLinha,116,30)})

			Endif
			
			
		endif
		
		DbSkip()
	EndDo
	
	//Fecho a área aberta
	TRB->(dbCloseArea())
	
	//Apago o arquivo temporario gerado para que não fique lixo no sistema
	Ferase(_cTmp+".DBF")
	
	//Começo a popular os campos e o browse
	if len(aFornece) > 0
		M->cPedido		:= aFornece[1][1]
		M->cCNPJ 		:= aFornece[1][2]
		M->cEmpresa	:= aFornece[1][3]
		M->cEndereco 	:= aFornece[1][4]
		M->cCidade 	:= aFornece[1][5]
		M->cUF 		:= aFornece[1][6]
		M->cCEP 		:= aFornece[1][7]
		M->cContato 	:= aFornece[1][8]
		M->cEmail 		:= aFornece[1][9]
	Endif
	
	if len(aRodape) > 0
		M->cPagto			:= aRodape[1][1]
		M->cComplemento 	:= aRodape[1][4]
		M->cMoeda 			:= aRodape[1][5]
		
		//como o campo é do tipo data, irei transformar de 
		//caracter para data usando o comando CTOD
		M->dEmissao 		:= CTOD(aRodape[1][2]) 
		M->dEntrega		:= CTOD(aRodape[1][3])
	Endif
	
	//Inicio a leitura dos itens que irão popular o meu browse
	For i := 1 to len(aItens)
		IncProc("Inserindo item "+ Alltrim(aItens[i,1])+"...")	
		
		//Convertendo texto para valores, utilizo a função VAL()
		nQuant   	:= Val(Substr(aItens[i,4],1,8)+"."+ Substr(aItens[i,4],9,2))
		nValor  	:= Val(Substr(aItens[i,5],1,8)+"."+ Substr(aItens[i,5],9,2))
		nTotal		:= nQuant * nValor
				
		aadd(aPedidos,{	.T.,;							//01 - Legenda
		aItens[i][1],;				//02 - Codigo
		aItens[i][2],;				//03 - Descricao
		aItens[i][3],;				//04 - No.Serie
		nQuant,;						//05 - Quantidade
		nValor,;						//06 - Valor
		nTotal,;						//07 - Total
		aItens[i][6];					//08 - Observação
						})
		
	Next
	
	//Populo o browse com os dados do array
	oPedidos:SetArray(aPedidos)
	
	//Elimino o arquivo texto que importei
	Ferase(GetSrvProfString("Startpath","")+cArquivo)
Return