PS.: Não esqueçam de baixar Prisma mais atual - dia 09/03/2017 ou superior, pois fiz umas correções.
PS [13/08/2017] : em anexo está versão igdir.pris mais atual, com devidas correções, baixem.
A lib igdir é um conjunto de funções para manipulação de arquivos e pastas.
Vou listar aqui algumas funções, em breve farei um tutorial completo desta lib.
para usá-la basta incluí-la:
local dir = inclua'igdir' //dir de diretório, o mesmo que pasta
Vendo a versão:
imprima(dir._VERSAO);
// ----> igdir - bibioteca de Manipulacao de Arquivos em Prisma - 1.0.1
Listando os nomes de arquivos e pastas de um diretório:
local tab = dir.liste_arquivos('/home/User/documentos/'); //lista a pasta documentos e retorna uma tabela
para i,v em pares(tab) inicio //imprimindo os índices da tabela
imprima(i,v)
fim
Essa função acima lista todos os itens incluindo os "." e "..' , vou explicar esses pontos abaixo:
o ponto único "." indica a pasta atual.
os dois pontos seguidos ".." indica o diretório pai do diretório atual, ou seja, a pasta onde está a pasta atual.
Basta fazer uns testes condicionais se você quiser eliminar esses pontos.
Se você quiser ler somente os arquivos então use:
dir.liste_somente_arquivos();
no lugar de
dir.liste_arquivos();
OBS.: se você deixar sem argumento, o padrão é a pasta atual.
Caso você queira ler só pastas então use:
dir.liste_somente_pastas();
Listando todos os arquivos na pasta e em subpastas:
local tab = dir.liste_todos('/home/usuario/Documentos'); //pasta a ser listada;
para i, v em pares(tab) inicio
imprima(i,v);
fim
O resultado é uma lista completa incluindo arquivo e pastas dentro de subdiretórios, recursivamente. Semelhante a isso:
1 /home/usuario/Documentos/arquivo.odt
2 /home/usuario/Documentos/subpasta/img.png
3 /home/usuario/Documentos/subpasta/img.xcf
4 /home/usuario/Documentos/subpasta/produtos.odt
5 /home/usuario/Documentos/file.odt
6 /home/usuario/Documentos/ola.pdf
7 /home/usuario/Documentos/olamundo.pdf
Se houver muitos arquivos pode ser que demore um pouco dependendo a potência do computador.
Futuramente quero criar funções assíncronas para serem usadas em temporizadores assim evita um
programa de interface gráfica travar enquanto lista muitos arquivos.
Note que até mesmo arquivos de pastas que estão dentro de outra pasta são listados. Muito útil essa função.
Procurando arquivos em pastas e subpastas:
local tab = dir.procure("/home/usuario/Documentos", 'sozinhos');
para i,v em pares(tab) inicio
imprima(i,v)
fim
1 /home/usuario/Documentos/sozinhos.odt
Neste caso só teve um arquivo localizado, mas poderiam ser mais, qualquer um que tivesse sozinhos no nome seria
listado na pesquisa.
Verificando se um arquivo existe:
imprima( dir.arquivo_existe("af") )
// ---> falso
imprima( dir.arquivo_existe('/home/usuario/Documentos/sozinhos.odt') )
// ---> verdadeiro
Basta usar um bloco condicional para tirar proveito desta função.
se dir.arquivo_existe("arq") entao
imprima("arquivo existe");
senao
imprima("arquivo não existe");
fim
Verificando se uma pasta existe:
local ret, err_msg = dir.dir_existe('/usr/');
imprima(ret, err_msg);
//---> verdadeiro nulo
E se o diretório não existir? Veja:
sis.deflocal('pt_BR.UTF-8'); //a mensagem de erro sai em português.
imprima( dir.dir_existe('adf') );
//---> falso nao foi possivel obter informacao do arquivo 'adf': Arquivo ou diretório não encontrado
Verificando o diretório atual e mudando de diretório atual:
imprima(dir.localdir()) //retorna o diretório atual
//-----> /home/usuario
dir.mudedir('/home/usuario/Documentos') //muda o diretório atual
imprima(dir.localdir() );
// ----> /home/usuario/Documentos
Criando e removendo um diretório (pasta) :
imprima( dir.criedir('afaf') )
//----> verdadeiro
imprima( dir.removadir('afaf') )
//----> verdadeiro
O problema é que essa função só remove se a pasta estiver vazia. Mas não se preocupe, eu criei
uma função que remove todos os arquivos e pastas recursivamente. Veja:
dir.remova_dir_re ("nomePasta"); //apaga tudo
A função remova_dir_re pode demorar um pouco se houver muitos megas ou gigas para apagar.
Pegando os atributos de arquivos ou pastas:
atrib = dir.atributos("/home/usuario/"); //retorna uma tabela. Poderia ser um arquivo ao invés de pasta.
imprima(atrib.modo); //retorna se é diretório, pasta, link, hard drive, etc.
//---> diretorio
imprima( atrib.tamanho); //retorna o tamanho do arquivo em bytes
//---> 4096
imprima(atrib.permissoes); //apenas em linux, retorna as permissões
//----> rwxr-xr-x (leitura,escrita,execução para o proprietario, exec. e escrit. para grupo, outros: somente exec.);
tab = sis.data('*t', atrib.mudanca) //o '*t' força o retorno em tabela:
imprima(t.dia..'/'..t.mes .. '/'..t.ano, t.hora..':'..t.minuto..':'..t.segundo);
//----> 9/3/2017 9:33/48
tab = sis.data('*t', atrib.acesso) //o '*t' força o retorno em tabela:
imprima(t.dia..'/'..t.mes .. '/'..t.ano, t.hora..':'..t.minuto..':'..t.segundo);
//----> 9/3/2017 9:33/48
Esses são os principais atributos, há alguns que não mencionei, vou documentá-los brevemente em um manual de
referência do igdir.
Observe que o atributo modificacao e acesso, são numeros incompreensíveis, tendo que convertê-los em data e horário usando a função data();
Bom, por enquanto é isso.
Continua logo abaixo II parte!
PARTE II
imprima( dir.copie_arquivo( 'arq.jpg','arq_copia.jpg') );
//---> verdadeiro
Esta função faz uma cópia idêntica de arquivos, os parâmetros são: arquivo origem , arquivo destino.
O retorno pode ser verdadeiro ou falso. (sucesso / falha);
imprima( dir.divida('arq.jpg', 'Dividido/arq.jpg', 10) );//troque o numero de partes se preferir.
//-----> verdadeiro
Esta função divide um arquivo grande em partes menores. No caso acima, 10 partes.
Parâmetros: arquivo_original, arquivo_destino, numero_partes;
O resultado é que na pasta Dividido acima, haverá vários arquivos: arq.jpg1, arq.jpg2 ... arq.jpg10
Isso é muito útil quando se quer quebrar um arquivo muito grande para enviar em upload ou para algum fim
semelhante.
imprima( dir.junte( 'Dividido/arq.jpg', 'arq_juntado.jpg') );
//----> verdadeiro
A função acima reverte o processo de divisão, unindo o arquivo novamente.
Parâmetros: 'nome arquivo dividido sem o número', 'nome_arquivo_destino'
Retorno: verdadeiro ou falso.
imprima(dir.mova_arquivo('arq_orig.jpg','arq_dest.jpg') );
//---> verdadeiro
Move um arquivo, ou seja, faz uma cópia idêntica e depois apaga o original.
local a, err = dir.copie_assinc(orig,dest, func,'dado_extra');
ret = a:exec();
O conjunto de funções acima faz uma cópia idêntica de um arquivo, mas diferentemente das funções de cópia
anteriores, esta faz etapa por etapa (assíncrona).
Primeiramente, dir.copie_assinc() prepara o objeto de cópia, e depois, o objeto chama o método exec para iniciar a cópia, repetidamente até ret ser igual a nulo e assim finaliza a cópia.
Note que usei dois pontos para acessar o método do objeto de cópia.
Poderia ser também, ao seu gosto: a->exec(); //ao invés dos dois pontos.
Obs.: não criei uma função mova_arquivo_asssinc pois não há necessidade. Use esta (copie_assinc) e depois apague o original.
Vejamos um exemplo funcional completo:
/*
* imagine que você queira fazer uma copia com interface gráfica
* então não vai querer que ao usar a funcao dir.copie_arquivo()
* o programa fique travado ao copiar um arquivo grande,
* neste caso vamos usar uma funcao assíncrona.
* Na verdade é uma função que copia parte por parte.
*
* veja o exemplo abaixo.
*/
local dir = inclua'igdir';
orig = 'a.iso';
dest = 'a_copia.iso';
imprima(dir.tamanho_arquivo(orig) ); //==> 3 GB. por exemplo.
funcao progresso(tam_cp,tam_total,dado)
local porcentagem = (tam_cp*100/tam_total);
imprima( tam_cp,dado,tam_total, porcentagem,'%');
fim
local a, err = dir.copie_assinc(orig,dest,progresso,'bytes copiados de');
t1 = sis.tempo();
se a entao
enquanto 1 inicio
ret, err = a:exec();
se nao ret entao
imprima( err );
quebre;
fim
fim
poe'copia concluida';
senao imprima(err);
fim
imprima('fim. tempo gasto:' , sis.diftempo(sis.tempo(),t1) );
leia();
//----> fim . tempo gasto: 90 (seg) dependendo do tamanho do arquivo e da potência do pc);
Parâmetros:
1 - orig : arquivo a ser copiado
2 - dest: nome da cópia.
3 - progresso: uma função callback, ou nulo. Essa callback será útil se você quiser mostrar o progresso da cópia em um programa gráfico, ou mesmo em modo texto.
4 - dado extra: são dados (strings, tabela, numero, ponteiro) que você precisa acessar na callback.
Retorno:
1 - objeto de cópia( tabela) ou nulo
2 - mensagem de erro caso objeto seja nulo.
Método do objeto de cópia, só há um:
ret , err= obj->exec()
não há parâmetros.
retornos:
1 - ret : verdadeiro ou falso,
2 - err: mensagem de erro caso o retorno 1 seja falso.
Dica:
Caso eu fosse fazer um programa de cópia usando o ig, pessoalmente usaria um temporizador no lugar do enquanto e quando o retorno fosse falso removeria o temporizador para pará-lo.
E na função callback de cópia eu atualizaria a barra de progresso demonstrando a porcentagem da cópia.
Bom, por hoje é isso.
Até mais.
CONTINUA ABAIXO:
PARTE III
BAIXE VERSÃO PRISMA 1.0.102 OU MAIOR
Continuando com os exemplos dessa excelente biblioteca, fundamental para quem precisa manipular arquivos e pastas.
LISTANDO ARQUIVOS DE UMA PASTA ASSINC
local obj, ERRO = dir.liste_arquivos_assinc(pasta, func, dado);
arq = obj:exec();
O conjunto de funções acima lista arquivos dentro de um diretório etapa por etapa. Primeiramente, é criado um objeto de listagem "obj" e depois a cada repetição do método "obj:exec()" é listado um arquivo até que o retorno seja nulo.
Parâmetros:
pasta: o diretório onde os arquivos serão listados.
func : uma função de retorno (callback) que será executada automaticamente a cada listagem.
Esta função deve ser definida: funcao nome_func(arq,dado); em que arq é o arquivo e dado é o dado extra.
dado: é um dado extra para a função de retorno.
Obs.: func e dado podem ser omitidos, as vezes não é necessário ou você pode não querer usar uma callback.
Retorno:
obj: objeto de listagem contendo os métodos: obj:exec() e obj:obt_erro() , e dados: obj.arquivos (tabela dos arquivos listados)
ERRO: caso obj seja nulo, uma mensagem de erro é retornada (string);
-- Método exe(): --
Não tem parâmetros, o retorno é um arquivo listado ou nulo. Em caso de nulo é porque chegou ao fim ou há erro.
-- Método obt_erro() --
Não tem parâmetros, o retorno é uma string descrevendo um erro, ou nulo caso não haja erro.
-- Dado .arquivos{} --
É a tabela preenchida com a lista de arquivos lidos após as chamadas do método :exec();
---------------------------------------------
Vejamos um exemplo:
local dir = inclua'igdir';
funcao callback(arq, dado)
imprima(dado,arq);
fim
local list = dir.liste_arquivos_assinc(".",callback,"Callback:");
local arqs;
enquanto 1 inicio
arqs = list:exec();
se nao arqs entao quebre; fim
//imprima(arqs);
fim
poe'Enter para continuar...';
leia();
// Os arquivos ficam guardados em uma tabela do objeto após a repetição do método exec(): list.arquivos:
//Nesta tabela não há os: '.' e '..', eles são excluídos.
tabela.ordene(list.arquivos); //coloca em ordem alfabética.
para i, v em pares(list.arquivos) inicio
imprima(i,v);
fim
poe'Enter para continuar...';
leia();
LISTANDO TODOS OS ARQUIVOS RECURSIVAMENTE ASSINC
local obj, ERRO = dir.liste_todos_assinc(pasta, func, dado);
ret = obj:exec();
Praticamente igual a função anterior, a diferença é que esta lista arquivos recursivamente pasta dentro de pasta. E o método obj:exec() retorna verdadeiro ou falso.
Obs. func e dados podem ser omitidos.
Veja um exemplo de uso:
local dir = inclua'igdir';
funcao callback(arq,dado) //com uma função callback fica mais organizado:
imprima(dado, arq);
fim
local list = dir.liste_todos_assinc(".", callback, "Callback: ");//o ponto indica diretório atual
local ret;
poe'Aguarde, listando...'
enquanto 1 inicio
ret = list:exec(); //o retorno é verdadeiro ou falso. A cada execução, a callback é executada junto!
se nao ret entao quebre; fim
fim
poe'Processo terminado. Enter para continuar...';
leia();
// Os arquivos ficam guardados em uma tabela do objeto após a repetição do método exec(): list.arquivos:
//Nesta tabela não há os: '.' e '..', eles são excluídos.
tabela.ordene(list.arquivos); //coloca em ordem alfabética.
para i, v em pares(list.arquivos) inicio
imprima(i,v);
fim
poe'Enter para continuar...';
leia();
CRIANDO SUBDIRETÓRIOS RECURSIVAMENTE:
local ret, err = dir.crie_subdir(pastas);
Exemplo:
local dir = inclua'igdir';
local pastas = dir.convbarra("A/B/C/D/E"); //adequa as barras de acordo com o sistem.(Em Windows elas são: \\)
local ret, err = dir.crie_subdir(pastas);
se nao ret entao imprima(err); fim
poe"Enter para sair..."
leia();
CONVERTENDO A BARRA DE ENDEREÇO
ret, err = dir.convbarra("a\\b\\c\\d\\e\\")
Supondo que você faça um programa para Windows e vá usá-lo em Linux, o trecho acima será compatível pois a função dir.convbarra converte as barras para o tipo correto ao sistema operacional. Se ret for nulo, então err será uma mensagem de erro.
OBTENDO CAMINHO ABSOLUTO E RESOLVENDO OS '..' '.'
local caminho = dir.resolva_dir( "../../a/b/../c");
Esta função te dá o caminho absoluto, no caso acima o retorno poderá ser:
/home/user/programas/a/b/c
Obs.: a função acima não verifica se o caminho realmente existe, ela calcula baseado no diretório atual.
Obs.: a função acima detecta o tipo de barra correto automaticamente.
Dica.:
para pegar o caminho real embutido em um link use: sis.caminho_absoluto("nomeLink"); //Para win e linux.
FIM
CONTINUA EM BREVE...
PARTE IV
Atenção, baixe igdir versão 1.0.2 (13-08-2017) em anexo, pois fiz várias correções e adicionei mais funções.
COMO PESQUISAR POR ARQUIVOS EM MODO ASSINC
Antes de mais nada, não criei uma função de busca assíncrona pois não é necessária. A própria função liste_todos_assinc() cobre essa necessidade.
Basta criar uma função callback e usar string.procure() para busca.
Abaixo um exemplo completo:
local dir = inclua'igdir'; //incluindo a biblioteca de manipulação de pastas e arquivos.
local cont=0;
local total=0;
funcao callback(arqs,arq) //esta é a função de retorno, pode atualizar uma barra de progresso aqui.
local Dir,NomeArq,Ext = sis.nome_arquivo(arqs);//esta função quebra um caminho em diretorio, arq, extensão.
// ex.: Dir,Nome,Ext = sis.nome_arquivo("teste/ola.txt");
// Dir = "teste"; Nome = "ola", Ext = "txt";
Dir = Dir ou ""; NomeArq = NomeArq ou ""; Ext = Ext ou "";//evitar erro.
local alvo = NomeArq .. "." .. Ext;
se alvo:procure(arq) entao
cont = cont + 1;
imprimaf("\n[%02d] Encontrado: %q\n", cont, dir.resolva_dir(arqs) );//poderia guardar em uma tabela se quiser.
fim
total = total + 1;
//atualize_barra_status(total,cont);
fim
funcao principal(Args)
local arq_busca = "%.pdf"; //todos os arquivos terminados em .pdf serão encontrados.
local pasta_busca = "/home/adalberto/Documentos"; //pesquisa em um diretorio acima.
local t1 = sis.tempo();
local obj_busca, ERRO = dir.liste_todos_assinc(pasta_busca, callback, arq_busca);
se nao obj_busca entao
imprima('Erro:',ERRO, '\n\nEnter para sair...');
leia();
sis.saia(1);
fim //fim se
enquanto obj_busca:exec() inicio //enquanto obs_busca retornar verdadeiro ele continua a executar a callback.
//nao faz nada
se obj_busca.msg_erro entao //se houver erro (arquivo ou pasta não aberta, ou links quebrados.)
//imprima(obj_busca.msg_erro);
fim
fim
local tmp_gasto = sis.diftempo(sis.tempo(), t1);
imprimaf("\n\nNúmero de arquivos encontrados: %d.\nEm um total de %d arquivos.\nDuração: %d segundos\n\n", cont,total, tmp_gasto);
poe'Enter para continuar...';
leia();
retorne 0;
fim //fim principal
LISTANDO TODAS AS PASTAS RECURSIVAMENTE EM MODO ASSÍNCRONO
Talvez você queira listar todas as pastas e subpastas ao invés dos arquivos. Para isso criei uma outra função específica:
local obj, err = dir.liste_pastas_assinc('pasta', callback, dado);
ret = obj:exec();
Obs. callback e dado são opcionais, se não quiser usar uma callback deixe em branco.
Segue um exemplo completo:
local dir = inclua'igdir';
funcao callback(dir,dado)
imprima(dado,dir);
fim
local obj, err = dir.liste_pastas_assinc('/home/adalberto/Documentos', callback, '-->');
se nao obj entao imprima(err,'\n\nEnter para sair...\n'); leia(); sis.saia(1); fim
local t1 = sis.tempo();
enquanto obj:exec() inicio fim;
local t2 = sis.tempo();
imprimaf("\nNumero de pastas: %d\nTempo gasto: %d segundo(s)\n\nEnter para sair...",#obj.diretorios, sis.diftempo(t2,t1) );
leia();
Espero que tenha sido útil, até mais, qualquer dúvida poste uma resposta.