sexta-feira, 18 de julho de 2008

Precisando exportar seus códigos?

Quando crio um artigo, a parte mais chata é acertar a formatação do código para exibir nas postagens. Há pouco tempo comecei a usar uma ferramenta que tem ajudado muito: É o CSharp Code Export.Você só precisa colar o código (ou abrir o arquivo .cs existente) e clicar em converter. Ele gera o html para você.

E além do html, exporta também para outros formatos, como PDF e JPG.

Aqui vai um screenshot:


Você também pode definir estilos e cores

Além de tudo, é free!

Uma verdadeira mão na roda! [;)]

Removendo subpastas. Parte 2 - uma forma mais "primitiva"


No artigo anterior mostrei como é fácil criar um programa que remove as subpastas de uma pasta indicada pelo usuário. No código, usamos os recursos disponibilizados pelo .Net Framework, que facilitam muito a nossa vida.

No presente artigo, mostro como obter o mesmo resultado, mas de uma forma um pouco mais "trabalhosa". Dispensaremos os recursos automáticos de busca por pastas e arquivos, e faremos nossas próprias comparações. Claro, ainda usaremos alguns recursos da linguagem, mas o "cerne" do problema será solucionado por nossa própria conta, usando um pouco de recursão.

Primeiro, crie um novo projeto, baseando-se no artigo anterior para a parte visual.

Agora, vamos às diferenças. O código do evento btRemover_Click deve ficar assim:

        private void btRemover_Click(object sender, DirectoryNotFoundException e)
        {
            if (txtCaminho.Text.Trim() == "")
            {
                MessageBox.Show("Por favor, digite ou selecione uma pasta para procurar.");
                txtCaminho.Focus();
                return;
            }
            else if (cmbCriterios.SelectedIndex == 0)
            {
                MessageBox.Show("Por favor, selecione um critério na lista.");
                cmbCriterios.Focus();
                return;
            }
            else if (txtCriterio.Text.Trim() == "")
            {
                MessageBox.Show("Por favor, digite um critério.");
                txtCriterio.Focus();
                return;
            }

            string criterio = txtCriterio.Text;

            switch (cmbCriterios.SelectedIndex)
            {
                case 2:
                    criterio += "*";
                    break;
                case 3:
                    criterio = "*" + criterio;
                    break;
                case 4:
                    criterio = "*" + criterio + "*";
                    break;
            }


            if (MessageBox.Show(
            "Deseja realmente procurar e remover as pastas onde os nomes "

                                               + cmbCriterios.Text + 
" \"" + txtCriterio.Text + "\"?",
                                                "Confirmar",MessageBoxButtons.YesNo) == DialogResult.No
                                              )
                return;


            this.Cursor = Cursors.WaitCursor;

            btRemover.Enabled = 
false;
            btRemover.Text = "Por favor, aguarde...";
            pgbRemovendo.Visible = true;


            int total = procurarPastas(txtCaminho.Text, criterio, chkSubpastas.Checked);


            pgbRemovendo.Visible = false;
            this.Cursor = Cursors.Default;

            if (total == 0)
                MessageBox.Show("Nenhuma pasta encontrada.");
            else
                MessageBox.Show(total.ToString() + " pasta(s) removida(s).");


            btRemover.Enabled = true;
            btRemover.Text = "&Procurar e remover";
        }


Agora, crie a função procurarPastas. Essa função recebe 3 parâmetros:

  1. o caminho da pasta principal, a partir de onde procuraremos as pastas a serem removidas
  2. uma máscara para sabermos os critérios selecionados para a procura
  3. opção de procurar ou não nas subpastas
Novamente, os comentários estão no próprio código:

        int procurarPastas(string pastaPai, string maskCriterio, bool recursivo)
        {
            int total = 0;
            DirectoryInfo pasta = new DirectoryInfo(pastaPai);

            bool remover = false;

            string criterio = maskCriterio.Replace("*","");


            try
            {
                DirectoryInfo[] subPastas = pasta.GetDirectories();


                //percorremos todas as subpastas
                foreach (DirectoryInfo subPasta in subPastas) 
                {
                    // procurar pastas que contenham o critério selecionado
                    if (maskCriterio.StartsWith("*") && maskCriterio.EndsWith("*")) 
                    {
                        if (subPasta.Name.IndexOf(criterio,
                                StringComparison.InvariantCultureIgnoreCase) >= 0 )

                            remover = true;
                    }

                     // procurar pastas que comecem com o critério selecionado
                    else if (maskCriterio.StartsWith("*"))
                    {
                        if (subPasta.Name.StartsWith(criterio, 
                                StringComparison.InvariantCultureIgnoreCase))
                            remover=true;
                    }


                    // procurar pastas que terminem com o critério selecionado
                    else if (maskCriterio.EndsWith("*")) 
                    {
                        if (subPasta.Name.EndsWith(criterio,
                                StringComparison.InvariantCultureIgnoreCase))

                            remover = true;
                    }
                    
                    // procurar pastas que tenham o nome
                    //exatamente igual ao critério selecionado

                   
else 
                    {
                        if (subPasta.Name.ToLower() == criterio.ToLower())
                            remover=true;
                    }


                    if (recursivo) // procura nas subpastas da subpasta atual
                        total += procurarPastas(subPasta.FullName, maskCriterio, recursivo);


                    if (remover) //removemos a subpasta com todo o seu conteúdo
                    {
                        removePasta(subPasta);
                        total += 1;
                    }


                    this.Refresh();
                    remover = false;
                }
            }

            catch (StringComparison)
            {
                MessageBox.Show("Pasta inválida.");
            }


            return total;
        }

Vamos então ao código da função removePasta. Ela é a responsável por fazer o "trabalho sujo" de eliminar as pastas encontradas. Repare que ela remove os arquivos e subpastas um a um:

       
void removePasta(DirectoryInfo pasta)
        {
            foreach (FileInfo arquivo in pasta.GetFiles()) //apaga os arquivos da pasta
            {
                arquivo.IsReadOnly = false;
                arquivo.Delete();
            }

             //apaga subpastas da pasta atual
            foreach (DirectoryInfo subPasta in pasta.GetDirectories()) 
            {
                removePasta(subPasta);
            }

            // e finalmente, apaga a pasta
            pasta.Delete();
        }

Como pode ver, é possível usar a mesma lógica em outras linguagens.

domingo, 13 de julho de 2008

Removendo subpastas. Parte 1 - usando recursos existentes.

Mostrarei, neste artigo e em um próximo, duas formas de percorrer e remover subpastas de uma pasta selecionada pelo usuário. Esse tipo de programa é muito útil quando queremos fazer uma limpeza em determinados lugares do disco.

Neste primeiro artigo, uso os recursos que o .Net Framework nos oferece, fazendo com que gastemos menos tempo com o problema.

Primeiramente, crie um novo projeto do tipo Windows Forms.

Acrescente:

  • 2 Botões:
    • no primeiro, defina as propriedades Name como "btSelecionarPasta" e Text  como "..."
    • no segundo, deixe o nome como "btRemover" e Text como "&Procurar e remover"
  • 2 TextBoxes:
    • a primeira com o nome "txtCaminho"
    • a segunda, "txtCriterio"
  • 1 ComboBox
    • nomeie como "cmbCriterios"
    • em Items, coloque, separados por uma linha, e sem aspas:  "--Selecione--", "São iguais a", "Começam com", "Terminam com", "Contém"
  • 1 CheckBox, nomeada como "chkSubpastas" e Checked = true
  • 1 ProgressBar, de nome "pgbRemovendo" e Style Marquee
  • 1 FolderBrowserDialog, com o nome "dlgSelecionarPasta"
A "cara" do programa deve ficar parecida com a próxima figura:

Agora, vamos ao código:

Acrescente a referência ao namespace System.IO:
 using System.IO;
 No evento Load do Form:
cmbCriterios.SelectedIndex = 0;
Agora, no evento Click do botão "btSelecionarPasta", acrescente:
dlgSelecionarPasta.ShowDialog();
txtCaminho.Text = dlgSelecionarPasta.SelectedPath;
E, no evento Click do botão "btRemover", o código principal (colocarei todo o código do evento, mas comentarei - no próprio código - apenas os trechos mais importantes):

private void btRemover_Click(object sender, EventArgs e)
{                     

    if (txtCaminho.Text.Trim() == "")
    {
        MessageBox.Show("Por favor, digite ou selecione uma pasta para procurar.");
        txtCaminho.Focus();
        return;
    }
    else if (cmbCriterios.SelectedIndex == 0)
    {
        MessageBox.Show("Por favor, selecione um critério na lista.");
        cmbCriterios.Focus();
        return;
    }
    else if (txtCriterio.Text.Trim() == "")
    {
        MessageBox.Show("Por favor, digite um critério.");
        txtCriterio.Focus();
        return;
    }

   /* Abaixo, verificamos se devemos apagar as pastas/arquivos que
        sejam exatamente iguais, 
        terminam, começam ou contenham  o critério selecionado.
        Repare que podemos usar caracteres curinga.  
    */
    string criterio = txtCriterio.Text;          
    switch (cmbCriterios.SelectedIndex)
    {              
        case 2:
            criterio += "*";                  
            break;
        case 3:
            criterio = "*" + criterio;                  
            break;
        case 4:
            criterio = "*" + criterio + "*";                  
            break;
    }

    if (MessageBox.Show("Deseja realmente procurar e remover as pastas onde os nomes " + cmbCriterios.Text + " \"" + txtCriterio.Text + "\"?","Confirmar", MessageBoxButtons.YesNo) == DialogResult.No)
        return;
  
    DirectoryInfo dir = new DirectoryInfo(txtCaminho.Text );

    SearchOption srcSubfolders = SearchOption.TopDirectoryOnly;

    // Se a checkbox está marcada, removeremos também as subpastas
    if (chkSubpastas.Checked)
        srcSubfolders = SearchOption.AllDirectories;        
  
    try
    {

        DirectoryInfo[] subDirs = dir.GetDirectories(criterio, srcSubfolders);
        int total = subDirs.Count();

        if (total == 0)
        {
            MessageBox.Show("Nenhuma pasta encontrada.");
            return;
        }

        this.Cursor = Cursors.WaitCursor;
        btRemover.Enabled = false;
        btRemover.Text = "Por favor, aguarde...";
        pgbRemovendo.Visible = true;

        foreach (DirectoryInfo subDir in subDirs)
        {
            try
            {
                subDir.Delete(true);
            }
            catch (UnauthorizedAccessException) //caso existam arquivos marcados como readonly, mudamos a permissão para que possamos apagá-los.
            {
                foreach(FileInfo file in subDir.GetFiles("*",SearchOption.AllDirectories))
                {
                    file.IsReadOnly = false;
                }
                subDir.Delete(true);
            }
            this.Refresh();
        }

        pgbRemovendo.Visible = false;
        this.Cursor = Cursors.Default;
        MessageBox.Show(total.Tostring() + " pasta(s) removida(s).");
      
        btRemover.Enabled = true;
        btRemover.Text = "&Procurar e remover";
      

    }
    catch (DirectoryNotFoundException)
    {
        MessageBox.Show("Pasta inválida.");
    }


}
No próximo artigo sobre este tema, espero postar algo, digamos, mais "primitivo". [:)]