Olá pessoal…
Você já precisou pegar vários arquivos de uma pasta e todas as suas sub pastas em AdvPL? Saiba como com a função zRecurDir.
Se por acaso você já precisou ir em uma pasta via AdvPL e retornar todos os arquivos txt ou xml dentro dela, você sabe que tanto a Directory() quanto a aDir() não funcionam com essa recursividade.
Pensando nisso, foi criado a zRecurDir, onde você passa qual é a pasta, qual é a máscara de arquivos (como *.xml) e se será considerado a partir de uma data os arquivos. Com isso é pego todas as subpastas, e depois todos os arquivos dentro de cada subpasta.
No fim, gera um pequeno log no console.log, conforme abaixo.
Abaixo o código fonte desenvolvido.
//Bibliotecas #Include "Protheus.ch" /*/{Protheus.doc} zRecurDir Função recursiva de diretórios, que traz arquivos dentro de uma pasta e suas subpastas @author Atilio @since 30/05/2018 @version 1.0 @param cPasta, characters, Qual é a pasta a ser verificada @param cMascara, characters, Qual é a máscara de pesquisa @param dAPartir, date, Data de corte dos arquivos (Opcional) @type function @obs Ao finalizar a rotina, é gerado uma mensagem no console.log com alguns dizeres: zRecurDir: Buscando arquivos '*.xml', Dentro da pasta 'Z:\Conhecimento Transportadoras XML\', Considerando a partir de '01/05/2018'! Inicio: 15:51:26 Término: 15:51:34 Diferença: 00:00:08 Arquivos encontrados: 40247 Arquivos filtrados: 1443 @example Basta declarar um array, e mandar os parâmetros para processamento. No exemplo abaixo, é buscado os arquivos xml, dentro do diretório especificado, pegando apenas o que consta com a data do dia 01/05/2018 em diante aArquivos := u_zRecurDir("Z:\Conhecimento Transportadoras XML\", "*.xml", sToD("20180501")) /*/ User Function zRecurDir(cPasta, cMascara, dAPartir) Local aArea := GetArea() Local cTempoIni := Time() Local cTempoFim := "" Local aArquivos := {} Local aPastas := {} Local aTemp := {} Local aArqOrig := {} Local nAtual := 0 Local nAux := 0 Local nTamanho := 0 Local nTamAux := 0 Default cPasta := "" Default cMascara := "" Default dAPartir := sToD("") //Se tiver pasta e máscara If ! Empty(cPasta) .And. ! Empty(cMascara) //Caso não tenha "\" no fim adiciona, por exemplo, "C:\TOTVS" -> "C:\TOTVS\" cPasta += Iif(SubStr(cPasta, Len(cPasta), 1) != "\", "\", "") //Pega as pastas da raíz aPastas := Directory(cPasta + "*.*", "D") //Percorre todas as pastas do Array (Conforme ele for sendo atualizado, volta pro laço) For nAtual := 1 To Len(aPastas) //Se não tiver ponto no nome, e for do tipo D (Diretório) If ! "." $ Alltrim(aPastas[nAtual][1]) .And. aPastas[nAtual][5] == "D" //Se não tiver a pasta raíz no nome, adiciona, por exemplo, "SubPasta" -> "C:\TOTVS\SubPasta" If ! cPasta $ aPastas[nAtual][1] aPastas[nAtual][1] := cPasta + aPastas[nAtual][1] EndIf //Caso não tenha "\" no fim adiciona, por exemplo, "C:\TOTVS" -> "C:\TOTVS\" aPastas[nAtual][1] += Iif(SubStr(aPastas[nAtual][1], Len(aPastas[nAtual][1]), 1) != "\", "\", "") //Pega todas as pastas dentro dessa aTemp := Directory(aPastas[nAtual][1] + "*.*", "D") //Percorre as subpastas dentro, e adiciona o texto a esquerda, por exemplo, "PastaX" -> "C:\TOTVS\SubPasta\PastaX" For nAux := 1 To Len(aTemp) aTemp[nAux][1] := aPastas[nAtual][1] + aTemp[nAux][1] Next //Pega o tamanho das subpastas, e o tamanho atual das pastas nTamanho := Len(aTemp) nTamAux := Len(aPastas) //Redimensiona o array das pastas, aumentando conforme o tamanho das subpastas aSize(aPastas, Len(aPastas) + nTamanho) //Copia as subpastas para dentro da pasta a partir da última posição aCopy(aTemp, aPastas, , , nTamAux + 1) EndIf Next //Pega o tamanho das pastas nTamanho := Len(aPastas) //Percorre todas as pastas For nAtual := 1 To nTamanho //Se tiver pasta a ser validada If nAtual <= Len(aPastas) //Se tiver ponto no nome, ou for diferente de D (Diretório) If "." $ Alltrim(aPastas[nAtual][1]) .Or. aPastas[nAtual][5] != "D" //Exclui aposição atual do Array aDel(aPastas, nAtual) //Redimensiona o Array, diminuindo 1 posição aSize(aPastas, Len(aPastas) - 1) //Altera variáveis de controle, diminuindo elas nTamanho-- nAtual-- EndIf EndIf Next //Ordena o Array por ordem alfabética aSort(aPastas) //Pega os arquivos da pasta raíz aArquivos := Directory(cPasta + cMascara) //Percorre todos os arquivos For nAtual := 1 To Len(aArquivos) //Se a pasta não tiver no nome do arquivo, adiciona, por exemplo, "arquivo.xml" -> "C:\TOTVS\arquivo.xml" If ! cPasta $ aArquivos[nAtual][1] aArquivos[nAtual][1] := cPasta + aArquivos[nAtual][1] EndIf Next //Percorre todas as pastas / subpastas encontradas For nAtual := 1 To Len(aPastas) //Se a pasta realmente existe If ExistDir(aPastas[nAtual][1]) //Caso não tenha "\" no fim adiciona, por exemplo, "C:\TOTVS" -> "C:\TOTVS\" aPastas[nAtual][1] += Iif(SubStr(aPastas[nAtual][1], Len(aPastas[nAtual][1]), 1) != "\", "\", "") //Pega todos os arquivos dessa subpasta filtrando a máscara aTemp := Directory(aPastas[nAtual][1] + cMascara) //Percorre todos os arquivos encontrados For nAux := 1 To Len(aTemp) //Adiciona o caminho completo da subpasta, por exemplo, "arquivo2.xml" -> "C:\TOTVS\SubPasta\arquivo2.xml" aTemp[nAux][1] := aPastas[nAtual][1] + aTemp[nAux][1] Next //Pega o tamanho do array dos arquivos encontrados, e o tamanho do array de arquivos que serão retornados nTamanho := Len(aTemp) nTamAux := Len(aArquivos) //Aumento o tamanho do array de Arquivos, com o tamanho dos encontrados aSize(aArquivos, Len(aArquivos) + nTamanho) //Copia o conteúdo dos enontrados para dentro do array de Arquivos aCopy(aTemp, aArquivos, , , nTamAux + 1) EndIf Next //Copia para um novo array de backup aArqOrig := aClone(aArquivos) //Se tiver data de filtragem If ! Empty(dAPartir) //Enquanto houver arquivos nAtual := 0 While nAtual <= Len(aArquivos) nAtual++ //Se existir arquivos válidos a serem processados If Len(aArquivos) >= nAtual //Se na pasta atual, a data do arquivo NÃO for maior que a data de corte If ! aArquivos[nAtual][3] >= dAPartir //Deleta a posição atual o array de Arquivos aDel(aArquivos, nAtual) //Redimensiona o Array, diminuindo uma posição aSize(aArquivos, Len(aArquivos) - 1) nAtual-- EndIf EndIf EndDo EndIf EndIf //Finaliza o tempo, e mostra uma saída no console.log cTempoFim := Time() ConOut("zRecurDir:" + CRLF +; "Buscando arquivos '" + cMascara + "', " +; "Dentro da pasta '" + cPasta + "', " +; "Considerando a partir de '" + dToC(dAPartir) + "'!" + CRLF + CRLF +; "Inicio: " + cTempoIni + CRLF +; "Término: " + cTempoFim + CRLF +; "Diferença: " + ElapTime(cTempoIni, cTempoFim) + CRLF +; "Arquivos encontrados: " + cValToChar(Len(aArqOrig)) + CRLF +; "Arquivos filtrados: " + cValToChar(Len(aArquivos))) RestArea(aArea) Return aArquivos
Bom pessoal, por hoje é só.
Abraços e até a próxima.
Boa Tarde,
Primeiramente parabéns pelo seu trabalho!!! Com relação a função, a mesma buscar os arquivos dentro de um diretório na maquina local ou o diretório deve estar dentro de “protheus_data” no servidor?
Boa noite Dayvid, tudo bem?
Você passa o diretório que deseja verificar, assim como demonstrado no exemplo dentro do Protheus.Doc, eu aponto para um diretório dentro de Z:\
Qualquer dúvida, fico à disposição.
Abraços.
Olá. Primeiro, grato por disponibilizar a função. Estou tentando utilizar a mesmo dentro de meu programa. Parece-me que a função zRecurDir le os arquivos apenas dentro da primeira sub-pasta. Se tiver pasta dentro de pasta, a função não não guarda os nomes dos arquivos.
Bom dia. Obrigado pelo feedback.
Em algumas versões do Protheus ou de sistemas operacionais, a função Directory() não funciona adequadamente.
Tente substituir pela função aDir().
Abraços.
O meu resolvi mudando o for da linha 54 por while.
Exemplo: Se o len(aPastas) fosse = 5, mesmo adicionando mais informações no array do aPasta o for só iria até 5, ou seja, não atualizava e só iria ler a primeira sub-Pasta.
Então o ajuste ficaria da seguinte forma.
Na linha 36 ficou Local nAtual := 1
Na linha 54 saiu o for e ficou While nAtual nAtual ++, tirei o Next do for e acrescentei o EndDo do While.
Ficando assim: nAtual ++
EndDo
Ficando assim:
//Bibliotecas
#Include “Protheus.ch”
/*/{Protheus.doc} zRecurDir
Função recursiva de diretórios, que traz arquivos dentro de uma pasta e suas subpastas
@author Atilio
@since 30/05/2018
@version 1.0
@param cPasta, characters, Qual é a pasta a ser verificada
@param cMascara, characters, Qual é a máscara de pesquisa
@param dAPartir, date, Data de corte dos arquivos (Opcional)
@type function
@obs Ao finalizar a rotina, é gerado uma mensagem no console.log com alguns dizeres:
zRecurDir:
Buscando arquivos ‘*.xml’, Dentro da pasta ‘Z:\Conhecimento Transportadoras XML\’, Considerando a partir de ’01/05/2018′!
Inicio: 15:51:26
Término: 15:51:34
Diferença: 00:00:08
Arquivos encontrados: 40247
Arquivos filtrados: 1443
@example Basta declarar um array, e mandar os parâmetros para processamento.
No exemplo abaixo, é buscado os arquivos xml, dentro do diretório especificado, pegando apenas o que consta com a data do dia 01/05/2018 em diante
aArquivos := u_zRecurDir(“Z:\Conhecimento Transportadoras XML\”, “*.xml”, sToD(“20180501”))
/*/
User Function zRecurDir(cPasta, cMascara, dAPartir)
Local aArea := GetArea()
Local cTempoIni := Time()
Local cTempoFim := “”
Local aArquivos := {}
Local aPastas := {}
Local aTemp := {}
Local aArqOrig := {}
Local nAtual := 1
Local nAux := 0
Local nTamanho := 0
Local nTamAux := 0
Default cPasta := “”
Default cMascara := “”
Default dAPartir := sToD(“”)
//Se tiver pasta e máscara
If ! Empty(cPasta) .And. ! Empty(cMascara)
//Caso não tenha “\” no fim adiciona, por exemplo, “C:\TOTVS” -> “C:\TOTVS\”
cPasta += Iif(SubStr(cPasta, Len(cPasta), 1) != “\”, “\”, “”)
//Pega as pastas da raíz
aPastas := Directory(cPasta + “*.*”, “D”)
//Percorre todas as pastas do Array (Conforme ele for sendo atualizado, volta pro laço)
While nAtual “C:\TOTVS\SubPasta”
If ! cPasta $ aPastas[nAtual][1]
aPastas[nAtual][1] := cPasta + aPastas[nAtual][1]
EndIf
//Caso não tenha “\” no fim adiciona, por exemplo, “C:\TOTVS” -> “C:\TOTVS\”
aPastas[nAtual][1] += Iif(SubStr(aPastas[nAtual][1], Len(aPastas[nAtual][1]), 1) != “\”, “\”, “”)
//Pega todas as pastas dentro dessa
aTemp := Directory(aPastas[nAtual][1] + “*.*”, “D”)
//Percorre as subpastas dentro, e adiciona o texto a esquerda, por exemplo, “PastaX” -> “C:\TOTVS\SubPasta\PastaX”
For nAux := 1 To Len(aTemp)
aTemp[nAux][1] := aPastas[nAtual][1] + aTemp[nAux][1]
Next
//Pega o tamanho das subpastas, e o tamanho atual das pastas
nTamanho := Len(aTemp)
nTamAux := Len(aPastas)
//Redimensiona o array das pastas, aumentando conforme o tamanho das subpastas
aSize(aPastas, Len(aPastas) + nTamanho)
//Copia as subpastas para dentro da pasta a partir da última posição
aCopy(aTemp, aPastas, , , nTamAux + 1)
EndIf
nAtual ++
EndDo
//Pega o tamanho das pastas
nTamanho := Len(aPastas)
//Percorre todas as pastas
For nAtual := 1 To nTamanho
//Se tiver pasta a ser validada
If nAtual “C:\TOTVS\arquivo.xml”
If ! cPasta $ aArquivos[nAtual][1]
aArquivos[nAtual][1] := cPasta + aArquivos[nAtual][1]
EndIf
Next
//Percorre todas as pastas / subpastas encontradas
For nAtual := 1 To Len(aPastas)
//Se a pasta realmente existe
If ExistDir(aPastas[nAtual][1])
//Caso não tenha “\” no fim adiciona, por exemplo, “C:\TOTVS” -> “C:\TOTVS\”
aPastas[nAtual][1] += Iif(SubStr(aPastas[nAtual][1], Len(aPastas[nAtual][1]), 1) != “\”, “\”, “”)
//Pega todos os arquivos dessa subpasta filtrando a máscara
aTemp := Directory(aPastas[nAtual][1] + cMascara)
//Percorre todos os arquivos encontrados
For nAux := 1 To Len(aTemp)
//Adiciona o caminho completo da subpasta, por exemplo, “arquivo2.xml” -> “C:\TOTVS\SubPasta\arquivo2.xml”
aTemp[nAux][1] := aPastas[nAtual][1] + aTemp[nAux][1]
Next
//Pega o tamanho do array dos arquivos encontrados, e o tamanho do array de arquivos que serão retornados
nTamanho := Len(aTemp)
nTamAux := Len(aArquivos)
//Aumento o tamanho do array de Arquivos, com o tamanho dos encontrados
aSize(aArquivos, Len(aArquivos) + nTamanho)
//Copia o conteúdo dos enontrados para dentro do array de Arquivos
aCopy(aTemp, aArquivos, , , nTamAux + 1)
EndIf
Next
//Copia para um novo array de backup
aArqOrig := aClone(aArquivos)
//Se tiver data de filtragem
If ! Empty(dAPartir)
//Enquanto houver arquivos
nAtual := 0
While nAtual = nAtual
//Se na pasta atual, a data do arquivo NÃO for maior que a data de corte
If ! aArquivos[nAtual][3] >= dAPartir
//Deleta a posição atual o array de Arquivos
aDel(aArquivos, nAtual)
//Redimensiona o Array, diminuindo uma posição
aSize(aArquivos, Len(aArquivos) – 1)
nAtual–
EndIf
EndIf
EndDo
EndIf
EndIf
//Finaliza o tempo, e mostra uma saída no console.log
cTempoFim := Time()
ConOut(“zRecurDir:” + CRLF +;
“Buscando arquivos ‘” + cMascara + “‘, ” +;
“Dentro da pasta ‘” + cPasta + “‘, ” +;
“Considerando a partir de ‘” + dToC(dAPartir) + “‘!” + CRLF + CRLF +;
“Inicio: ” + cTempoIni + CRLF +;
“Término: ” + cTempoFim + CRLF +;
“Diferença: ” + ElapTime(cTempoIni, cTempoFim) + CRLF +;
“Arquivos encontrados: ” + cValToChar(Len(aArqOrig)) + CRLF +;
“Arquivos filtrados: ” + cValToChar(Len(aArquivos)))
RestArea(aArea)
Return aArquivos
Bom dia Cristiano, tudo joia?
Opa, show de bola.
Obrigado pela contribuição e feedback.
Tenha uma ótima e abençoada segunda feira.
Um grande abraço.