No artigo de hoje, irei mostrar para vocês como importar um arquivo csv ou txt via AdvPL.
Muitos alunos me perguntam como seria a lógica para importar registros em AdvPL com o conteúdo de um arquivo txt ou csv.
Então jovens, a lógica seria assim:
- Buscar o caminho do arquivo apontado pelo usuário (TFileDialog)
- Tentar realizar a abertura do arquivo (FWFileReader)
- Ler todas as linhas do arquivo (While com método HasLine)
- Na linha atual, transformar o texto em um array (StrTokArr ou Separa)
- Tentar posicionar no registro (DbSeek)
- Fazer a gravação dos dados (via MsExecAuto ou RecLock)
Com esse contexto acima, iremos montar um exemplo, onde no arquivo CSV, existam as seguintes colunas:
- Código do Fornecedor (A2_COD)
- Loja do Fornecedor (A2_LOJA)
- Razão Social (A2_NOME)
- Observações (A2_X_OBS) – campo customizado que será gravado
//Bibliotecas #Include "TOTVS.ch" #Include "TopConn.ch" //Posições do Array Static nPosCodigo := 1 //Coluna A no Excel Static nPosLojFor := 2 //Coluna B no Excel Static nPosRazSoc := 3 //Coluna C no Excel Static nPosObserv := 4 //Coluna D no Excel /*/{Protheus.doc} zImpCSV Função para importar informações do fornecedor via csv @author Atilio @since 07/06/2021 @version 1.0 @type function /*/ User Function zImpCSV() Local aArea := GetArea() Private cArqOri := "" //Mostra o Prompt para selecionar arquivos cArqOri := tFileDialog( "CSV files (*.csv) ", 'Seleção de Arquivos', , , .F., ) //Se tiver o arquivo de origem If ! Empty(cArqOri) //Somente se existir o arquivo e for com a extensão CSV If File(cArqOri) .And. Upper(SubStr(cArqOri, RAt('.', cArqOri) + 1, 3)) == 'CSV' Processa({|| fImporta() }, "Importando...") Else MsgStop("Arquivo e/ou extensão inválida!", "Atenção") EndIf EndIf RestArea(aArea) Return /*-------------------------------------------------------------------------------* | Func: fImporta | | Desc: Função que importa os dados | *-------------------------------------------------------------------------------*/ Static Function fImporta() Local aArea := GetArea() Local cArqLog := "zImpCSV_" + dToS(Date()) + "_" + StrTran(Time(), ':', '-') + ".log" Local nTotLinhas := 0 Local cLinAtu := "" Local nLinhaAtu := 0 Local aLinha := {} Local oArquivo Local aLinhas Local cCodForn := "" Local cLojForn := "" Local cObserv := "" Local cRazaoSoc := "" Private cDirLog := GetTempPath() + "x_importacao\" Private cLog := "" //Se a pasta de log não existir, cria ela If ! ExistDir(cDirLog) MakeDir(cDirLog) EndIf //Definindo o arquivo a ser lido oArquivo := FWFileReader():New(cArqOri) //Se o arquivo pode ser aberto If (oArquivo:Open()) //Se não for fim do arquivo If ! (oArquivo:EoF()) //Definindo o tamanho da régua aLinhas := oArquivo:GetAllLines() nTotLinhas := Len(aLinhas) ProcRegua(nTotLinhas) //Método GoTop não funciona (dependendo da versão da LIB), deve fechar e abrir novamente o arquivo oArquivo:Close() oArquivo := FWFileReader():New(cArqOri) oArquivo:Open() //Enquanto tiver linhas While (oArquivo:HasLine()) //Incrementa na tela a mensagem nLinhaAtu++ IncProc("Analisando linha " + cValToChar(nLinhaAtu) + " de " + cValToChar(nTotLinhas) + "...") //Pegando a linha atual e transformando em array cLinAtu := oArquivo:GetLine() aLinha := StrTokArr(cLinAtu, ";") //Se não for o cabeçalho (encontrar o texto "Código" na linha atual) If ! "código" $ Lower(cLinAtu) //Zera as variaveis cCodForn := aLinha[nPosCodigo] cLojForn := aLinha[nPosLojFor] cRazaoSoc := aLinha[nPosRazSoc] cObserv := aLinha[nPosObserv] DbSelectArea('SA2') SA2->(DbSetOrder(1)) // Filial + Código + Loja //Se conseguir posicionar no fornecedor If SA2->(DbSeek(FWxFilial('SA2') + cCodForn + cLojForn)) cLog += "+ Lin" + cValToChar(nLinhaAtu) + ", fornecedor [" + cCodForn + cLojForn + " - " + Upper(SA2->A2_NREDUZ) + "] " +; "a observação foi alterada, antes: [" + Alltrim(SA2->A2_X_OBS) + "], agora: [" + Alltrim(cObserv) + "];" + CRLF //Realiza a alteração do fornecedor RecLock('SA2', .F.) SA2->A2_X_OBS := cObserv SA2->(MsUnlock()) Else cLog += "- Lin" + cValToChar(nLinhaAtu) + ", fornecedor e loja [" + cCodForn + cLojForn + "] não encontrados no Protheus;" + CRLF EndIf Else cLog += "- Lin" + cValToChar(nLinhaAtu) + ", linha não processada - cabeçalho;" + CRLF EndIf EndDo //Se tiver log, mostra ele If ! Empty(cLog) cLog := "Processamento finalizado, abaixo as mensagens de log: " + CRLF + cLog MemoWrite(cDirLog + cArqLog, cLog) ShellExecute("OPEN", cArqLog, "", cDirLog, 1) EndIf Else MsgStop("Arquivo não tem conteúdo!", "Atenção") EndIf //Fecha o arquivo oArquivo:Close() Else MsgStop("Arquivo não pode ser aberto!", "Atenção") EndIf RestArea(aArea) Return
Obs.: No nosso exemplo, fizemos um RecLock, pois iremos gravar um campo customizado na SA1, o A1_X_OBS. Se no seu caso for uma inclusão em tabela padrão ou alteração de campos padrões, tente utilizar o ExecAuto por boas práticas.
Bom pessoal, por hoje é só.
Abraços e até a próxima.
Olá Atilio,
Fiz a alteração no fonte para tabela CC2, o campo que você chama A2_X_OBS alterei para CC2_PRZENT , esse campo está em branco na tabela mais no CSV ele está preenchido com dois caracteres e precisa preencher somente ele na tabela que é referente ao prazo de entrega mais o log informar que linha não foi processada.
//Posições do Array
Static nPosEstMun := 1 //Coluna A no Excel
Static nPosCodMun := 2 //Coluna B no Excel
Static nPosMun := 3 //Coluna C no Excel
Static nPosPrzEnt := 4 //Coluna D no Excel
User Function zImpCSV()
Local aArea := GetArea()
Private cArqOri := “”
//Mostra o Prompt para selecionar arquivos
cArqOri := tFileDialog( “CSV files (*.csv) “, ‘Seleção de Arquivos’, , , .F., )
//Se tiver o arquivo de origem
If ! Empty(cArqOri)
//Somente se existir o arquivo e for com a extensão CSV
If File(cArqOri) .And. Upper(SubStr(cArqOri, RAt(‘.’, cArqOri) + 1, 3)) == ‘CSV’
Processa({|| fImporta() }, “Importando…”)
Else
MsgStop(“Arquivo e/ou extensão inválida!”, “Atenção”)
EndIf
EndIf
RestArea(aArea)
Return
Static Function fImporta()
Local aArea := GetArea()
Local cArqLog := “zImpCSV_” + dToS(Date()) + “_” + StrTran(Time(), ‘:’, ‘-‘) + “.log”
Local nTotLinhas := 0
Local cLinAtu := “”
Local nLinhaAtu := 0
Local aLinha := {}
Local oArquivo
Local aLinhas
Local cEstMun := “”
Local cCodmun := “”
Local cPrzEnt := “”
Local cMun := “”
Private cDirLog := GetTempPath() + “x_importacao\”
Private cLog := “”
//Se a pasta de log não existir, cria ela
If ! ExistDir(cDirLog)
MakeDir(cDirLog)
EndIf
//Definindo o arquivo a ser lido
oArquivo := FWFileReader():New(cArqOri)
//Se o arquivo pode ser aberto
If (oArquivo:Open())
//Se não for fim do arquivo
If ! (oArquivo:EoF())
//Definindo o tamanho da régua
aLinhas := oArquivo:GetAllLines()
nTotLinhas := Len(aLinhas)
ProcRegua(nTotLinhas)
//Método GoTop não funciona (dependendo da versão da LIB), deve fechar e abrir novamente o arquivo
oArquivo:Close()
oArquivo := FWFileReader():New(cArqOri)
oArquivo:Open()
//Enquanto tiver linhas
While (oArquivo:HasLine())
//Incrementa na tela a mensagem
nLinhaAtu++
IncProc(“Analisando linha ” + cValToChar(nLinhaAtu) + ” de ” + cValToChar(nTotLinhas) + “…”)
//Pegando a linha atual e transformando em array
cLinAtu := oArquivo:GetLine()
aLinha := StrTokArr(cLinAtu, “;”)
//Se não for o cabeçalho (encontrar o texto “Código” na linha atual)
If “código” $ Lower(cLinAtu)
//Zera as variaveis
cEstMun := aLinha[nPosEstMun]
cCodmun := aLinha[nPosCodMun]
cMun := aLinha[nPosMun]
cPrzEnt := aLinha[nPosPrzEnt]
DbSelectArea(‘CC2’)
CC2->(DbSetOrder(1)) // Filial + Código + Loja
//Se conseguir posicionar no fornecedor
If CC2->(DbSeek(FWxFilial(‘CC2’) + cEstMun + cCodmun))
cLog += “+ Lin” + cValToChar(nLinhaAtu) + “, fornecedor [” + cEstMun + cCodmun + ” – ” + Upper(CC2->CC2_MUN) + “] ” +;
“a observação foi alterada, antes: [” + Alltrim(CC2->CC2_PRZENT) + “], agora: [” + Alltrim(cPrzEnt) + “];” + CRLF
//Realiza a alteração do fornecedor
RecLock(‘CC2’, .F.)
CC2->CC2_PRZENT := cPrzEnt
CC2->(MsUnlock())
Else
cLog += “- Lin” + cValToChar(nLinhaAtu) + “, fornecedor e loja [” + cEstMun + cCodmun + “] não encontrados no Protheus;” + CRLF
EndIf
Else
cLog += “- Lin” + cValToChar(nLinhaAtu) + “, linha não processada – cabeçalho;” + CRLF
EndIf
EndDo
//Se tiver log, mostra ele
If ! Empty(cLog)
cLog := “Processamento finalizado, abaixo as mensagens de log: ” + CRLF + cLog
MemoWrite(cDirLog + cArqLog, cLog)
ShellExecute(“OPEN”, cArqLog, “”, cDirLog, 1)
EndIf
Else
MsgStop(“Arquivo não tem conteúdo!”, “Atenção”)
EndIf
//Fecha o arquivo
oArquivo:Close()
Else
MsgStop(“Arquivo não pode ser aberto!”, “Atenção”)
EndIf
RestArea(aArea)
Return
Boa tarde Edson, tudo joia?
Opa, vimos aqui, faltou uma exclamação no if do exemplo. Então ao invés disso:
Tem que ser assim:
Já corrigimos no artigo, obrigado pelo feedback.
Um grande abraço.