Algumas funções úteis da biblioteca igdir para manipular arquivos e pastas

Iniciado por adalberto, Março 09, 2017, 10:36:39 AM

tópico anterior - próximo tópico

adalberto

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!

adalberto

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:


adalberto

                                                    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...







adalberto

                                                 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.