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