Executando verificação de segurança...
1

O comando java SeparaArquivos.java funciona somente a partir do Java 11.

A diferença é que ele roda o arquivo diretamente, sem gerar o respectivo .class.

Carregando publicação patrocinada...
1

A JDK instalada no meu PC é a versão 20.
Sim, com o arquivo presente na pasta, eu consegui rodar assim

java SeparaArquivos.java

Então pensei: Poxa, toda vez que eu precisar separar meus arquivos em pastas automaticamente, terei que colar o programa SeparaArquivos.java nela e rodá-lo.
Então aconteceu o que mencionei no post.
Apenas joguei ele no diretório de CLASSPATH e não deu certo.
Só funcionou após eu gerar o .class

2

Ah sim, agora entendi o que não funcionou. Bom, quando vc roda java Arquivo.java, ele ainda vai ter que compilar o arquivo, então precisa passar o caminho completo dele (por isso só funciona se ele está na mesma pasta). Só que como ele não cria o .class (pois o bytecode fica só em memória), então não adianta setar o classpath.

Gerando o .class funciona porque o classpath indica onde procurá-lo, e aí ele sempre encontrará, independente de onde vc executar.


Aproveitando, umas sugestões de melhoria.

Vc não precisa compilar a regex toda hora. Pode deixar o Pattern como uma variável estática (só é carregada uma vez), assim a regex não será compilada toda vez que o método for chamado:

public class SeparaArquivos {
    // só compila a regex uma vez
    private static final Pattern EXTRAI_NUMERO = Pattern.compile("_(\\d+)_");

    public static String extrairNumero(String nomeArquivo) {
        Matcher matcher = EXTRAI_NUMERO.matcher(nomeArquivo);
        if (matcher.find()) {
            return matcher.group(1);
        }
        return null;
    }

    // demais métodos...
}

E para listar os arquivos, basta passar um java.io.FileFilter, que aí vc nem precisa verificar nada dentro do for, pois ele já trará somente os arquivos que vc quer:

public static void moverArquivos(String pastaOrigem, String pastaDestino) {
    File diretorioOrigem = new File(pastaOrigem);
    // listFiles já pode filtrar os arquivos diretamente
    for (File arquivo : diretorioOrigem.listFiles((f) -> f.isFile() && f.getName().toLowerCase().endsWith(".sql"))) {
        String nomeArquivo = arquivo.getName();
        String numero = extrairNumero(nomeArquivo);
        if (numero != null) {
            File novaPasta = new File(pastaDestino, numero);
            if (!novaPasta.exists()) {
                novaPasta.mkdirs();
            }

            try {
                Path origem = arquivo.toPath();
                Path destino = new File(novaPasta.getPath(), nomeArquivo).toPath();
                Files.move(origem, destino, StandardCopyOption.REPLACE_EXISTING);
                System.out.println("Arquivo " + nomeArquivo + " movido para a pasta " + numero);
            } catch (IOException e) {
                System.out.println("Erro ao mover o arquivo " + nomeArquivo);
            }
        }
    }
}

Repare também que o construtor de File pode receber o diretório pai e o nome do filho (seja um subdiretório, seja um arquivo), portanto mudei para new File(pastaDestino, numero) e new File(novaPasta.getPath(), nomeArquivo) (não precisa concatenar com o File.separator).


Mas já que vc está usando java.nio, por que não usar para tudo? No caso, só vai precisar desses import's:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.stream.Stream;

E o método moverArquivos fica assim:

public static void moverArquivos(String pastaOrigem, String pastaDestino) throws IOException {
    Path origem = Paths.get(pastaOrigem);
    Path destino = Paths.get(pastaDestino);
    try (Stream<Path> files = Files.list(origem)) {
        files // filtra os arquivos .sql
            .filter(p -> Files.isRegularFile(p) && p.toString().toLowerCase().endsWith(".sql"))
            // processa cada um
            .forEach(sqlFile -> {
                String nomeArquivo = sqlFile.getFileName().toString();
                String numero = extrairNumero(nomeArquivo);
                if (numero != null) {
                    try {
                        Path novaPasta = Paths.get(destino.toString(), numero);
                        Files.createDirectories(novaPasta); // só cria se não existir
                        Files.move(sqlFile, Paths.get(novaPasta.toString(), nomeArquivo), StandardCopyOption.REPLACE_EXISTING);
                        System.out.println("Arquivo " + nomeArquivo + " movido para a pasta " + numero);
                    } catch (IOException e) {
                        System.out.println("Erro ao mover o arquivo " + nomeArquivo);
                    }
                }
            });
    }
}

Outra diferença importante é que File.listFiles primeiro lê todas as entradas do diretório, e só depois retorna o array. Já Files.list retorna uma stream que é populada de maneira lazy (seria "sob demanda", apesar de não ser exatamente assim e ser dependente da implementação). Isso faz diferença se o diretório tiver muitos arquivos, por exemplo (o primeiro precisa ler tudo pra gerar o array, o segundo processa um de cada vez e em seguida descarta, não precisando gerar o array com tudo).

1

Sim, também dá para receber que tipo de arquivo você quer filtrar nos argumentos.
Parabéns, por revisar, como eu havia dito as possibilidades são infinitas.