No vídeo de hoje, vamos demonstrar em como importar um arquivo XLS (do Excel) via AdvPL.
Hoje, a dúvida foi feita por alguns alunos, se existia alguma forma de importar um Excel sem ter que salvar manualmente com a extensão CSV.
Então foi criado um batch com um script que converte automaticamente o arquivo selecionado de XLS para CSV e assim realiza a importação.
E abaixo o código fonte desenvolvido para exemplificar:
//Bibliotecas
#Include "TOTVS.ch"
/*/{Protheus.doc} User Function zVid0040
Função que realiza a leitura de um XLS convertendo ele para CSV para importar os dados (como se fosse um CSV)
@type Function
@author Atilio
@since 01/09/2022
@obs Pessoal, essa função é um paliativo de exemplo, para ler um XLS transformando ele em CSV
Caso você queira se aprofundar, ou ver uma classe que vai além, com opção de leitura e
escrita, eu recomendo que você conheça a YExcel, que é um projeto excelente do Saulo Martins
+ Link para download: https://github.com/saulogm/advpl-excel/blob/master/src/YEXCEL.prw
+ Link de exemplo: https://github.com/saulogm/advpl-excel/blob/master/exemplo/tstyexcel.prw
+ Documentação: https://github.com/saulogm/advpl-excel
/*/
User Function zVid0040()
Local aArea := FWGetArea()
Local cDirIni := GetTempPath()
Local cTipArq := 'Arquivos Excel (*.xlsx) | Arquivos Excel 97-2003 (*.xls)'
Local cTitulo := 'Seleção de Arquivos para Processamento'
Local lSalvar := .F.
Local cArqSel := ''
Private cArqCSV := ""
//Se não estiver sendo executado via job
If ! IsBlind()
//Chama a função para buscar arquivos
cArqSel := tFileDialog(;
cTipArq,; // Filtragem de tipos de arquivos que serão selecionados
cTitulo,; // Título da Janela para seleção dos arquivos
,; // Compatibilidade
cDirIni,; // Diretório inicial da busca de arquivos
lSalvar,; // Se for .T., será uma Save Dialog, senão será Open Dialog
; // Se não passar parâmetro, irá pegar apenas 1 arquivo; Se for informado GETF_MULTISELECT será possível pegar mais de 1 arquivo; Se for informado GETF_RETDIRECTORY será possível selecionar o diretório
)
//Se tiver o arquivo selecionado e ele existir
If ! Empty(cArqSel) .And. File(cArqSel)
//Faz a conversão de XLS para CSV
cArqCSV := fXLStoCSV(cArqSel)
//Se o arquivo XLS existir
If File(cArqCSV)
Processa({|| fImporta(cArqCSV) }, 'Importando...')
EndIf
EndIf
EndIf
FWRestArea(aArea)
Return
/*/{Protheus.doc} fImporta
Função que processa o arquivo e realiza a importação para o sistema
@author Daniel Atilio
@since 16/07/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/
Static Function fImporta(cArqSel)
Local cDirTmp := GetTempPath()
Local cArqLog := 'importacao_' + dToS(Date()) + '_' + StrTran(Time(), ':', '-') + '.log'
Local nTotLinhas := 0
Local cLinAtu := ''
Local nLinhaAtu := 0
Local aLinha := {}
Local oArquivo
Local cPastaErro := '\x_logs\'
Local cNomeErro := ''
Local cTextoErro := ''
Local aLogErro := {}
Local nLinhaErro := 0
Local cLog := ''
//Variáveis do ExecAuto
Private aDados := {}
Private lMSHelpAuto := .T.
Private lAutoErrNoFile := .T.
Private lMsErroAuto := .F.
//Variáveis da Importação
Private cAliasImp := 'SBM'
Private cSeparador := ','
//Abre as tabelas que serão usadas
DbSelectArea(cAliasImp)
(cAliasImp)->(DbSetOrder(1))
(cAliasImp)->(DbGoTop())
//Definindo o arquivo a ser lido
oArquivo := FWFileReader():New(cArqSel)
//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(cArqSel)
oArquivo:Open()
//Iniciando controle de transação
Begin Transaction
//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 := Separa(cLinAtu, cSeparador)
//Se houver posições no array
If Len(aLinha) > 0
aDados := {}
aAdd(aDados, {'BM_GRUPO', aLinha[1], Nil})
aAdd(aDados, {'BM_DESC', aLinha[2], Nil})
lMsErroAuto := .F.
MSExecAuto({|x, y| MATA035(x, y)}, aDados, 3)
//Se houve erro, gera o log
If lMsErroAuto
cPastaErro := '\x_logs\'
cNomeErro := 'erro_' + cAliasImp + '_' + dToS(Date()) + '_' + StrTran(Time(), ':', '-') + '.txt'
//Se a pasta de erro não existir, cria ela
If ! ExistDir(cPastaErro)
MakeDir(cPastaErro)
EndIf
//Pegando log do ExecAuto, percorrendo e incrementando o texto
aLogErro := GetAutoGRLog()
For nLinhaErro := 1 To Len(aLogErro)
cTextoErro += aLogErro[nLinhaErro] + CRLF
Next
//Criando o arquivo txt e incrementa o log
MemoWrite(cPastaErro + cNomeErro, cTextoErro)
cLog += '- Falha ao incluir registro, linha [' + cValToChar(nLinhaAtu) + '], arquivo de log em ' + cPastaErro + cNomeErro + CRLF
Else
cLog += '+ Sucesso no Execauto na linha ' + cValToChar(nLinhaAtu) + ';' + CRLF
EndIf
EndIf
EndDo
End Transaction
//Se tiver log, mostra ele
If ! Empty(cLog)
MemoWrite(cDirTmp + cArqLog, cLog)
ShellExecute('OPEN', cArqLog, '', cDirTmp, 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
Return
//Essa função foi baseada como referência no seguinte link: https://stackoverflow.com/questions/1858195/convert-xls-to-csv-on-command-line
Static Function fXLStoCSV(cArqXLS)
Local cArqCSV := ""
Local cDirTemp := GetTempPath()
Local cArqScript := cDirTemp + "XlsToCsv.vbs"
Local cScript := ""
Local cDrive := ""
Local cDiretorio := ""
Local cNome := ""
Local cExtensao := ""
//Monta o Script para converter
cScript := 'if WScript.Arguments.Count < 2 Then' + CRLF
cScript += ' WScript.Echo "Error! Please specify the source path and the destination. Usage: XlsToCsv SourcePath.xls Destination.csv"' + CRLF
cScript += ' Wscript.Quit' + CRLF
cScript += 'End If' + CRLF
cScript += 'Dim oExcel' + CRLF
cScript += 'Set oExcel = CreateObject("Excel.Application")' + CRLF
cScript += 'Dim oBook' + CRLF
cScript += 'Set oBook = oExcel.Workbooks.Open(Wscript.Arguments.Item(0))' + CRLF
cScript += 'oBook.SaveAs WScript.Arguments.Item(1), 6' + CRLF
cScript += 'oBook.Close False' + CRLF
cScript += 'oExcel.Quit' + CRLF
MemoWrite(cArqScript, cScript)
//Pega os detalhes do arquivo original em XLS
SplitPath(cArqXLS, @cDrive, @cDiretorio, @cNome, @cExtensao)
//Monta o nome do CSV, conforme os detalhes do XLS
cArqCSV := cDrive + cDiretorio + cNome + ".csv"
//Executa a conversão, exemplo:
// c:\totvs\Testes\XlsToCsv.vbs "C:\Users\danat\Downloads\tste2.xls" "C:\Users\danat\Downloads\tst2_csv.csv"
ShellExecute("OPEN", cArqScript, ' "' + cArqXLS + '" "' + cArqCSV + '"', cDirTemp, 0 )
Return cArqCSV
Observação:
Pessoal, essa função é um paliativo de exemplo, para ler um XLS transformando ele em CSV.
Caso você queira se aprofundar, ou ver uma classe que vai além, com opção de leitura e escrita, eu recomendo que você conheça a YExcel, que é um projeto excelente do Saulo Martins
- Link para download: https://github.com/saulogm/advpl-excel/blob/master/src/YEXCEL.prw
- Link de exemplo: https://github.com/saulogm/advpl-excel/blob/master/exemplo/tstyexcel.prw
- Documentação: https://github.com/saulogm/advpl-excel
Bom pessoal, por hoje é só.
Abraços e até a próxima.
Muito bom !!!
Opa, obrigado pelo comentário Marcos.
Forte abraço.