Olá!
Como desenvolvedores, nos deparamos com diversas situações onde precisamos armazenar dados temporariamente durante a execução de um determinado processo. Essa necessidade pode se apresentar quando estamos separando registros específicos enquanto trabalhamos com grandes volumes de dados, ou rotinas de importações de informações e validações de complexas de campos, rotinas de processamento de dados provenientes de múltiplas empresas, etc.
Em geral, sempre podemos pensar em outras formas de solucionar o mesmo problema porém, é bom saber como criar arquivos de dados temporários e trabalhar com eles. Outro grande benefício de utilizar esses trechos de código é a velocidade da busca dentro desses arquivos quando utilizamos índices 😉
Como criar um Arquivo de Dados Temporário no Protheus
No artigo de hoje vamos mostrar um exemplo de como criar e utilizar um arquivo de dados temporário. Existe uma série de funções e estruturas de código que são necessárias para que o procedimento funcione, portanto, é importante acompanhar com cuidado o código e a descrição das funções para entender como ele funciona.
Estruturas de Campos e Índices
Para criar a estrutura de uma tabela de dados, é necessário definir os seus campos. Essa definição é feita em um array, onde cada registro tem a seguinte estrutura (e representa um campo da tabela):
Primeira posição: nome do campo da tabela. Deve conter, no máximo, 10 caracteres.
Segunda posição: tipo do campo. C = Character/String, N = Numérico, D = Data, L = Lógico (Booleano)
Terceira posição: tamanho do campo.
Quarta posição: casas decimais (utilizado somente para campos numéricos)
Ex.:
aAdd(aCampos,{"CODIGO","C",06,0})
Outra forma de recuperar as especificações de um campo, é utilizar o dicionário de dados do Protheus e utilizar as informações de um campo parecido. Podemos fazer isso utilizando a função TAMSX3 (ela retorna um array com tipo e tamanho do campo informado):
aTamSX3 := TamSX3("A1_COD") aAdd(aCampos,{"A1_COD",aTamSX3[3],aTamSX3[1],aTamSX3[2]})
Para definir um índice, utilizamos também uma estrutura de array. Da mesma forma como os campos, cada registro no array irá representar um dos índices da tabela. Ex.:
aAdd(aInd,{CriaTrab(Nil,.F.),"CODIGO+A1_COD","Codigo+Codigo do Cliente"})
A estrutura desse array é a seguinte:
Primeira posição: nome do arquivo temporário para o índice. Mais a frente veremos o que é essa função CriaTrab…
Segunda posicao: nome dos campos que irão compôr o índice. Lembrando que esses nomes de campos tem que ser iguais ao existente na primeira posição dos registros do array aCampos;
Terceira posicao: descrição dos campos que forma o índice.
CriaTrab e IndRegua
Para criar efetivamente o arquivo temporário, utilizamos a função CriaTrab. Ela pode ser utilizada de duas formas: para recuperar um nome de arquivo disponível (ou seja, o nome será de um arquivo que não existe na pasta Protheus_DataSystem) ou para criar um arquivo de dados utilizando uma estrutura de campos fornecida.
Para recuperar somente um nome de arquivo disponível (como fizemos no array de índices), basta chamar a função, sem passar uma estrutura de campos e com o segundo parâmetro igual a falso (.F.). O segundo parâmetro da função é quem realmente determina se o arquivo será criado ou não.
Para criar um arquivo de dados, enviamos um array com a estrutura dos campos (conforme fizemos anteriormente) que queremos na tabela e passar o segundo parâmetro como verdadeiro (.T.)
cArqTrab := CriaTrab(aCampos,.T.) //Seleciona o arquivo temporário como uma área de trabalho válida e atribui o Alias "ARQTMP" dbUseArea(.T.,"DBFCDX",cArqTrab,"ARQTMP",.T.,.F.)
Agora, vamos criar o índice utilizando a função IndRegua:
dbSelectArea("ARQTMP") //Após selecionada a área do arquivo temporário... For nA := 1 to Len(aInd) //Cria os índices utiliando o comando IndRegua IndRegua("ARQTMP",aInd[nA,1],aInd[nA,2],,,OemToAnsi("Criando Índice Temporário...")) Next nA
Perceba como envolvemos a chamada da função em um laço (For..Next). Isso porquê queremos criar um índice para cada registro no array a aInd. Essa função ainda exibe para o usuário uma mensagem enquanto o sistema gera os índices para a tabela.
Fonte de Exemplo
Para deixar mais claro o funcionamento dessas rotinas, criei um fonte de exemplo com todos os passos explicados em comentários. Além de criar o arquivo, codifiquei também uma função de teste que insere registros nessa tabela e depois os imprime na tela para o usuário:
#include "protheus.ch" #include "topconn.ch" /* ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± ±±ÉÍÍÍÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍÍÍÍÍÍ»±± ±±ºPrograma ³XArqTmp ºAutor ³Vinícius Gregório º Data ³ 04/11/13 º±± ±±ÌÍÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÍÍÏÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÍÏÍÍÍÍÍÍÍÍÍÍÍÍ͹±± ±±ºDesc. ³ Gera a estrutura dos arquivos temporários º±± ±±ÌÍÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͹±± ±±ºUso ³ AcademiaERP º±± ±±ÈÍÍÍÍÍÍÍÍÍÍÏÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ±± ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß */ User Function XArqTmp() //ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ //³Declaração de variáveis³ //ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Local aArea := GetArea() Local lRetorno := .T. //ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ //³Nome do arquivo temporário³ //ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Local cArqTrab := "" //ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ //³Arrays utilizados para a criação da tabela³ //ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Local aInd := {} Local aTamSX3 := {} Local aCampos := {} //Nesse exemplo, o array aCampos terá a especificação de um campo da tabela em cada uma das suas posições //criando campo com tipo e tamanho definidos manualmente, onde: //primeira posição: nome do campo na tabela //segunda posição: tipo do campo (C = caracter, N = Numérico, D = Data, L = Lógico) aAdd(aCampos,{"CODIGO","C",06,0}) //criando campo com base em campo existente no dicionário de dados (SX3) //a função TamSX3 retorna um array com as especificações do dicionário para o campo passado como parâmetro aTamSX3 := TamSX3("A1_COD") //vc pode deixar o nome original do campo aAdd(aCampos,{"A1_COD",aTamSX3[3],aTamSX3[1],aTamSX3[2]}) aTamSX3 := TamSX3("A1_LOJA") //ou pode dar o outro nome, desde que tenha a quantidade máxima de 10 caracteres aAdd(aCampos,{"LOJA",aTamSX3[3],aTamSX3[1],aTamSX3[2]}) //Montando o array que irá definir o índice, onde cada registro no array irá representar um dos índices da tabela //primeira posição: nome do arquivo temporário para o índice. //segunda posicao: nome dos campos que irão compôr o índice Lembrando que esses nomes de campos tem que ser iguais //ao existente na primeira posição dos registros do array aCampos //terceira posicao: nome dos campos que formam o índice aAdd(aInd,{CriaTrab(Nil,.F.),"CODIGO+A1_COD","Codigo+Codigo do Cliente"}) //ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ //³VG - 2013.05.24 ³ //³Gera arquivo temporário para ³ //³armazenar os registros da ARQTMP³ //ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ //Cria o arquivo temporário, passando para o CriaTrab o array com a estrutura de campos da tabela a ser gerada //primeiro parâmetro: campos para criar o arquivo de trabalho //segundo parâmetro: caso verdadeiro (.T.), cria o arquivo. Caso falso (.F.), somente retorna o nome disponível para o arquivo. cArqTrab := CriaTrab(aCampos,.T.) //Seleciona o arquivo temporário como uma área de trabalho válida e atribui o Alias "ARQTMP" dbUseArea(.T.,"DBFCDX",cArqTrab,"ARQTMP",.T.,.F.) dbSelectArea("ARQTMP") //Após selecionada a área do arquivo temporário... For nA := 1 to Len(aInd) //Cria os índices utiliando o comando IndRegua IndRegua("ARQTMP",aInd[nA,1],aInd[nA,2],,,OemToAnsi("Criando Índice Temporário...")) Next nA //chama uma função genérica pra testar nosso arquivo temporário Teste() RestArea(aArea) Return lRetorno /* ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± ±±ÉÍÍÍÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍÍÍÍÍÍ»±± ±±ºPrograma ³XARQTMP ºAutor ³Vinícius Gregório º Data ³ 04/11/13 º±± ±±ÌÍÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÍÍÏÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÍÏÍÍÍÍÍÍÍÍÍÍÍÍ͹±± ±±ºDesc. ³ Função genérica para testar nosso arquivo temporário º±± ±±º ³ º±± ±±ÌÍÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͹±± ±±ºUso ³ AP º±± ±±ÈÍÍÍÍÍÍÍÍÍÍÏÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ±± ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß */ Static Function Teste() //ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ //³Declaração de variáveis³ //ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ dbSelectArea("ARQTMP") RecLock("ARQTMP",.T.) ARQTMP->CODIGO := "TESTE" ARQTMP->A1_COD := "000001" ARQTMP->LOJA := "01" ARQTMP->(MsUnlock()) //ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ //³Imprime todos os registros armazenados³ //ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ dbSelectArea("ARQTMP") dbGoTop() Do While !EOF() MsgInfo("CODIGO: "+ARQTMP->CODIGO+" ,A1_COD: "+ARQTMP->A1_COD+" ,LOJA: "+ARQTMP->LOJA) dbSelectArea("ARQTMP") ARQTMP->(dbSkip()) EndDo Return .T.
Para baixar o fonte de exemplo, clique aqui
Boa tarde a todos. Consegui seguir o exemplo, e gostaria de saber como conseguiria aplicar, uma especie de group by, na minha área de trabalho. Alguém pode me ajudar?
Virada de versão seria um bom tema.
Claro, vou colocar em nossa lista algumas dicas sobre virada de versão!
Muito obrigado pela publicação…Abraçoss
Opa, que bom que gostou!
Caso precise de publicações em outros assuntos, é só sugerir 🙂
Abraços