[RESOLVIDO] Dump PostgreSQL via java.lang.Runtime

Ola Pessoal

Já procurei aqui no fórum em vários tópicos e ninguém tem a solução ideal.

Estou tentando escrever um método Java que faça o Dump de um banco de dados em PostgreSQL no Windows, da seguinte forma:

    private boolean efetuarBackupPostgres() {
        String arquivoDump = "C:\\Program Files (x86)\\pgAdmin III\\1.12\\pg_dump.exe";
        String arquivoBkp = new File("dados/database" + Util.dateDataToString(new Date(), "-yyyy-MM-dd-HH-mm-ss") + ".backup").getAbsolutePath();
        String comando = "\"" + arquivoDump + "\" -h " + PersistenciaServices.host + " -p " + PersistenciaServices.porta + " -U " + PersistenciaServices.usuario + " -F plain -v -f \"" + arquivoBkp + "\" banco";
        try {
            Runtime.getRuntime().exec(comando); // ele passa por arqui, mas não termina o processo
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        } 
        return false;
    }

O método funciona, ele não gera erro nem exceções.

Se eu entrar na pasta DADOS onde estou gravando o arquivo de “.backup” está lá criado o arquivo com 0 kbytes, porém quando eu fecho minha aplicação JAVA ele “destrava” o processo de DUMP e preenchedo o arquivo de “.backup” com as informações.

Resumindo, ele só faz o comando que passei no método “.exec()” depois que fecho a minha aplicação.

Alguém sabe como posso solucionar?

att
Douglas Junior

Vc está matando o processo depois amigo?
Tive um erro parecido com minha aplicação, só que não usava esse código que vc está usando, tenho outro que fiz aqui para backup e envio por e-mail para os administradores do sistema.

Abraços

[quote=andre_bento]Vc está matando o processo depois amigo?
Tive um erro parecido com minha aplicação, só que não usava esse código que vc está usando, tenho outro que fiz aqui para backup e envio por e-mail para os administradores do sistema.

Abraços[/quote]

Não estou matando o processo não, o código de Bakcup que fiz é exatamente este acima, como seria forma que você fez?

att
Douglas Junior

Dica para todo mundo que quer usar Runtime.exec: evite, dentro da medida do possível, usar a versão do exec que recebe apenas uma string. É que quando você faz isso, você deixa a cargo do sistema operacional separar o comando em parâmetros.
O problema é que ele nem sempre separa do jeito que você quer.
No seu caso, ele separou nos seguintes parâmetros, por causa dos espaços no nome do arquivo executável:

C:\Program
Files
(x86)\pgAdmin
III\1.12\pg_dump.exe
“nome do arquivo de dump”
-h
host

e assim por diante. Ou seja, ele bagunçou o nome do executável por causa do espaço, e pode ter feito mais besteiras depois - não analisei o resto para ver se está faltando algum par de aspas, ou coisa parecida.

Como você já viu que ele fez besteira na hora de achar o nome do executável, você tem uma de duas opções:

  • Ou põe um monte de aspas nos lugares certos, o que é um porre e nem sempre dá certo,
  • Ou você separa manualmente os parâmetros, o que funciona bem melhor. No seu caso, algo parecido com:
... = Runtime.getRuntime().exec(new String[]{
"C:\\Program Files (x86)\\pgAdmin III\\1.12\\pg_dump.exe",
"nome do arquivo de dump", 
"-h",
"host", 
...
});

[quote=entanglement]Dica para todo mundo que quer usar Runtime.exec: evite, dentro da medida do possível, usar a versão do exec que recebe apenas uma string. É que quando você faz isso, você deixa a cargo do sistema operacional separar o comando em parâmetros.
O problema é que ele nem sempre separa do jeito que você quer.
No seu caso, ele separou nos seguintes parâmetros, por causa dos espaços no nome do arquivo executável:

C:\Program
Files
(x86)\pgAdmin
III\1.12\pg_dump.exe
“nome do arquivo de dump”
-h
host

e assim por diante. Ou seja, ele bagunçou o nome do executável por causa do espaço, e pode ter feito mais besteiras depois - não analisei o resto para ver se está faltando algum par de aspas, ou coisa parecida.

Como você já viu que ele fez besteira na hora de achar o nome do executável, você tem uma de duas opções:

  • Ou põe um monte de aspas nos lugares certos, o que é um porre e nem sempre dá certo,
  • Ou você separa manualmente os parâmetros, o que funciona bem melhor. No seu caso, algo parecido com:

... = Runtime.getRuntime().exec(new String[]{ "C:\\Program Files (x86)\\pgAdmin III\\1.12\\pg_dump.exe", "nome do arquivo de dump", "-h", "host", ... }); [/quote]

Não é este o problema, veja na linha onde declaro a variável "String comando = ", eu envolvo o diretório do executável com aspas por existir espaços ao longo do diretório.

Conforme ei citei acima, o comando funciona “normalmente”, porém ele só é executado totalmente quando finalizo a aplicação, ou seja, quando rodo o “.exec()” ele executa parcialmente e só conclui o processo quando eu fecho o sistema.

att
Douglas

Olá amigo.
Vou postar o código para vc amanhã pois agora não estou no meu pc… o código funciona perfeitamente… vou passar ele inteiro pra vc ae vc adápta de acordo com a sua necessidade.
Abraços

[quote=andre_bento]Olá amigo.
Vou postar o código para vc amanhã pois agora não estou no meu pc… o código funciona perfeitamente… vou passar ele inteiro pra vc ae vc adápta de acordo com a sua necessidade.
Abraços[/quote]

Opa, muito obrigado, fico no aguardo.

Abraço
Douglas Junior

Olá amigo.
Peço desculpas pela demora na resposta.
Mas ae vai o código, é só adaptar para a sua necessidade.
Abraços e espero que te ajude.

[code]
/*

  • To change this template, choose Tools | Templates
  • and open the template in the editor.
    */
    package Util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import javax.swing.JOptionPane;

/**
*

  • @author Andre
    */
    public class BDBackup {

    private static String directoryName = new String();
    private static File dirDestino = new File(“C:\IBV System\backups”);
    private static String caminhoNovaPasta;

     public static void backingUp() throws IOException, InterruptedException{      
        
         
         
         if(dateCalculation()){
         
         final List<String> comandos = new ArrayList<String>();      
    
          
       comandos.add("C:\\Program Files\\PostgresPlus\\8.4SS\\bin\\pg_dump.exe");    
    
        comandos.add("-i");      
        comandos.add("-h");      
        comandos.add("localhost");      
        comandos.add("-p");      
        comandos.add("5432");      
        comandos.add("-U");      
        comandos.add("postgres");      
        comandos.add("-F");      
        comandos.add("c");      
        comandos.add("-b");      
        comandos.add("-v");      
        comandos.add("-f");      
        
        makeDirectory();
        settingBackupDate();
        dateCalculation();
        String way = dirDestino+"\\"+directoryName;
       
        comandos.add(way+"\\"+"church-bkp"); 
        
        comandos.add("church");      
    
        ProcessBuilder pb = new ProcessBuilder(comandos);      
     
        pb.environment().put("PGPASSWORD", "post");              
    
        try {      
            final Process process = pb.start();      
    
            final BufferedReader r = new BufferedReader(      
                new InputStreamReader(process.getErrorStream()));      
            String line = r.readLine();      
            while (line != null) {      
            System.err.println(line);      
            line = r.readLine();      
            }      
            r.close();      
    
            process.waitFor();  
            System.out.println("backup realizado com sucesso."); 
            process.destroy();
    
        } catch (IOException e) {      
            JOptionPane.showMessageDialog(null,"ERRO durante o backup:"+e);e.printStackTrace();      
        } catch (InterruptedException ie) {      
           JOptionPane.showMessageDialog(null,"ERRO durante o backup:"+ie); ie.printStackTrace();      
        }         
    
    }   
     
     } 
    

public static void backingUpWithoutDateCalculation() throws IOException, InterruptedException{

        final List<String> comandos = new ArrayList<String>();      

       comandos.add("C:\\Program Files\\PostgresPlus\\8.4SS\\bin\\pg_dump.exe");    

       comandos.add("-i");      
       comandos.add("-h");      
       comandos.add("localhost");      
       comandos.add("-p");      
       comandos.add("5432");      
       comandos.add("-U");      
       comandos.add("postgres");      
       comandos.add("-F");      
       comandos.add("c");      
       comandos.add("-b");      
       comandos.add("-v");      
       comandos.add("-f");      
       
       makeDirectory();
       settingBackupDate();
       dateCalculation();
       String way = dirDestino+"\\"+directoryName;
       caminhoNovaPasta = way;
      
       comandos.add(way+"\\"+"church-bkp"); 
       
       comandos.add("church");      

       ProcessBuilder pb = new ProcessBuilder(comandos);      
    
       pb.environment().put("PGPASSWORD", "post");              

       try {      
           final Process process = pb.start();      

           final BufferedReader r = new BufferedReader(      
               new InputStreamReader(process.getErrorStream()));      
           String line = r.readLine();      
           while (line != null) {      
           System.err.println(line);      
           line = r.readLine();      
           }      
           r.close();      

           process.waitFor();  
           System.out.println("backup realizado com sucesso."); 
           process.destroy();

       } catch (IOException e) {      
           JOptionPane.showMessageDialog(null,"ERRO durante o backup:"+e);e.printStackTrace();      
       } catch (InterruptedException ie) {      
          JOptionPane.showMessageDialog(null,"ERRO durante o backup:"+ie); ie.printStackTrace();      
       }         

   }   
    
     
    

    
    public static void makeDirectory(){
        
        if(!dirDestino.exists()){
            dirDestino.mkdirs();
            Date data = new Date();
              String simpleDate = new SimpleDateFormat("dd/MM/yyyy").format(data);
              String [] temp = simpleDate.split("/");
              
              /**Abaixo, estou verificando se é a última parte da data(no caso o ano)
               * que ele está pegando, se for, eu mando ele não adicionar o traço no
               * final para ficar visivelmente melhor
               */
              for(int i=0;i<temp.length;i++){
                  if(temp.length-i==1){
                      directoryName += temp[i];
                  }else{
                  directoryName += temp[i]+"-";}
              }
              File newDir = new File(dirDestino,directoryName);  
              newDir.mkdirs();
        }
        else
        {
          Date data = new Date();
          String simpleDate = new SimpleDateFormat("dd/MM/yyyy").format(data);
          String [] temp = simpleDate.split("/");
          //String directoryName = new String();
          /**Abaixo, estou verificando se é a última parte da data(no caso o ano)
           * que ele está pegando, se for, eu mando ele não adicionar o traço no
           * final para ficar visivelmente melhor
           */
          for(int i=0;i<temp.length;i++){
              if(temp.length-i==1){
                  directoryName += temp[i];
              }else{
              directoryName += temp[i]+"-";}
          }
          String [] allDirectoryNames = dirDestino.list();
          String [] listDirectoryNames = new String[allDirectoryNames.length];
          for (int i=0;i<allDirectoryNames.length;i++){
              String nameTemp = allDirectoryNames[i];
              String [] nameTemp2 = nameTemp.split("-");
              /**O for roda apenas uma vez para poder pegar o conteúdo até o ano
               * no caso 20-12-2011... ele varre até a terceira posição 
               * e joga o conteúdo no listDirectoryNames
               */
              for(int p=0;p<1;p++){
                  listDirectoryNames[i] = nameTemp2[p]+"-";
                  listDirectoryNames[i] += nameTemp2[p+1]+"-";
                  listDirectoryNames[i] += nameTemp2[p+2];
                  
                  
              }
          }
          
      
          int repeatNamesCont=0;
          String nameTemp = "" ;
         
          //preciso passar como parâmetro também ao invés de allDirecotryNames
          //o valor antes do - número de repetições...
          for(int i=0;i<allDirectoryNames.length;i++){
              if(directoryName.equals(listDirectoryNames[i])){
                  repeatNamesCont += 1;
                  nameTemp =directoryName+"-"+repeatNamesCont;
                 // directoryName += "-"+repeatNamesCont;
              }
          }
          /**
           */
          if(!"".equals(nameTemp)){
            directoryName =nameTemp;
          }
         
          
          File newDir = new File(dirDestino,directoryName);  
          newDir.mkdirs();
        }
        
    }
    
    
    public static void settingBackupDate() throws IOException{
        File dirDestinoBackup = new File("C:\\IBV System");
        String way = dirDestinoBackup.getAbsolutePath();
        File backupDirectory = new File(way+"\\Backup Date");
       
        Date data = new Date();
        String simpleDate = new SimpleDateFormat("dd/MM/yyyy").format(data);
        
        
        if(!backupDirectory.exists()){
             backupDirectory.mkdirs();
             FileWriter backupFile = new FileWriter(backupDirectory+"\\"+"LastBackup.txt");
             PrintWriter pw = new PrintWriter(backupFile,true);
             pw.println("This is the last time that the IBV System did a backup of the database");
             pw.println("Complete date: "+data);
             pw.println("");
             pw.println(simpleDate);
             pw.close();
             backupFile.close();
        }
        else
        {
             FileWriter backupFile = new FileWriter(backupDirectory+"\\"+"LastBackup.txt");
             PrintWriter pw = new PrintWriter(backupFile,true);
             pw.println("This is the last time that the IBV System did a backup of the database");
             pw.println("Complete date: "+data);
             pw.println("");
             pw.println(simpleDate);
             pw.close();
             backupFile.close();
        }
    
    }
    
    
    
    public static boolean dateCalculation() throws FileNotFoundException, IOException{
        File dirDestinoBackup = new File("C:\\IBV System");
        String way = dirDestinoBackup.getAbsolutePath();
        File backupDirectory = new File(way+"\\Backup Date");
        if(!backupDirectory.exists()){
           settingBackupDate();
        }
        boolean validDate = false;
        BufferedReader reader =  new BufferedReader(new FileReader("C:\\IBV System\\Backup Date\\LastBackup.txt"));   
        String text = new String();
        int numLinha = 0;
        while(reader.ready()){
            text += reader.readLine()+";";
            numLinha ++;
        }
        String [] temp = text.split(";");
        String date = temp[3];
        String [] dateSplit = date.split("/");
        Calendar data = new GregorianCalendar();
        int systemDay = data.get(Calendar.DAY_OF_MONTH);
        int day;
        if(dateSplit[0].equals("")){
            day = 1;
        }
        else{
            day = Integer.parseInt(dateSplit[0]);
        }
        if(systemDay - day == 7){
            validDate = true;
        }
       return validDate;
       
    }

    
    public static boolean isDirectoryExist(){
         boolean temp = false;
         
        if (dirDestino.exists()){
          String [] list = dirDestino.list();
          if (list==null){

          }else
              temp = true;

      }
        return temp;
        }
 

    public static String getCaminhoNovaPasta(){
        return caminhoNovaPasta;
    }

}
[/code]

Só explicando… esse código eu faço o backup automático do banco a cada 15 dias ou quando o usuário quiser fazer.
Ele cria a pasta em um local específicado lá em cima e caso a pasta já exista, ele não fica naquela mensagem do windows se deseja substituir ou algo assim, ele calcula a quantidade de pastas que já existem com o mesmo nome e faz o padrão de cópia do windows (nome(1), nome(2),nome(3))…
Qualquer dúvida é só ppostar ae amigo.

[quote=andre_bento]
Só explicando… esse código eu faço o backup automático do banco a cada 15 dias ou quando o usuário quiser fazer.
Ele cria a pasta em um local específicado lá em cima e caso a pasta já exista, ele não fica naquela mensagem do windows se deseja substituir ou algo assim, ele calcula a quantidade de pastas que já existem com o mesmo nome e faz o padrão de cópia do windows (nome(1), nome(2),nome(3))…
Qualquer dúvida é só ppostar ae amigo.[/quote]

Pelo oque eu li no codigo, da linha 104 até a 157 vai resolver meu problema, não tinha conhecimento destas ferramentas em Java, muito bom mesmo.

Muito obrigado pelo código, vou testar na terça-feira (20/03) e posto o resultado aqui.

Abraços
Douglas Junior

[quote=andre_bento]
Só explicando… esse código eu faço o backup automático do banco a cada 15 dias ou quando o usuário quiser fazer.
Ele cria a pasta em um local específicado lá em cima e caso a pasta já exista, ele não fica naquela mensagem do windows se deseja substituir ou algo assim, ele calcula a quantidade de pastas que já existem com o mesmo nome e faz o padrão de cópia do windows (nome(1), nome(2),nome(3))…
Qualquer dúvida é só ppostar ae amigo.[/quote]

Cara, eu usei parte do seu método, mas ainda fico no mesmo problema.

Ele executa o código e trava a aplicação, quando eu finalizo a aplicação ele cria o arquivo de Backup certinho no lugar onde mandei.

Se eu rodar dentro de uma “Thread” ele não trava a aplicação, mas ele só cria o arquivo de backup quando a aplicação é finalizada também.

Veja o código como ficou:

[code] private boolean efetuarBackupPostgres() {
String arquivoDump = “C:\Program Files (x86)\pgAdmin III\1.12\pg_dump.exe”;
String arquivoBkp = new File(“dados/database” + Util.dateDataToString(new Date(), “-yyyy-MM-dd-HH-mm-ss”) + “.backup”).getAbsolutePath();

    try {
        List<String> comandos = new ArrayList<String>();

        comandos.add(arquivoDump);

        comandos.add("-i");
        comandos.add("-h");
        comandos.add(PersistenciaServices.host);
        comandos.add("-p");
        comandos.add(PersistenciaServices.porta);
        comandos.add("-U");
        comandos.add(PersistenciaServices.usuario);
        comandos.add("-F");
        comandos.add("c");
        comandos.add("-v");
        comandos.add("-f");
        comandos.add(arquivoBkp);
        comandos.add(PersistenciaServices.banco);

        for (String string : comandos) {
            System.out.print(string + " ");
        }

        ProcessBuilder pb = new ProcessBuilder(comandos);

        pb.environment().put("PGPASSWORD", PersistenciaServices.senha);

        Process process = pb.start();

        BufferedReader brOut = new BufferedReader(
                new InputStreamReader(process.getInputStream()));

        String lineOut = brOut.readLine();
        while (lineOut != null) {
            System.out.println(lineOut);
            lineOut = brOut.readLine();
        }

        BufferedReader brError = new BufferedReader(
                new InputStreamReader(process.getErrorStream()));

        String lineError = brError.readLine();
        while (lineError != null) {
            System.err.println(lineError);
            lineError = brError.readLine();
        }

        brError.close();
        process.waitFor();
        System.out.println("backup realizado com sucesso.");
        process.destroy();
        return true;
    } catch (Exception e) {
        JOptionPane.showMessageDialog(null, "ERRO durante o backup:" + e);
        e.printStackTrace();
    }
    return false;
}[/code]

Abraços
Douglas Junior

Resolvi o problema paliativamente.

Para resolver estou gravando o comando em um arquivo .bat e depois executando o arquivo “.bat”

Ainda não gostei da solução, pois eu tenho que me preocupar em apagar o arquivo “.bat” toda vez, caso contrário as informações do banco ficam expostas.

Código:

[code] private boolean efetuarBackupPostgres() {
String arquivoDump = “C:\Program Files (x86)\pgAdmin III\1.12\pg_dump.exe”;
String arquivoBkp = new File(“dados/database” + Util.dateDataToString(new Date(), “-yyyy-MM-dd-HH-mm-ss”) + “.backup”).getAbsolutePath();
File fileBat = new File(“runbakcup.bat”);
try {
// escrever arquivo .bat
PrintWriter pw = new PrintWriter(fileBat);
pw.println(“echo off”);
String comandos = “”" + arquivoDump + “” -i "
+ " -h " + PersistenciaServices.host
+ " -p " + PersistenciaServices.porta
+ " -U " + PersistenciaServices.usuario
+ " -F c -v "
+ " -f “” + arquivoBkp + “” "
+ PersistenciaServices.banco + “”;
System.out.println(comandos);
pw.println(comandos);
pw.println(“exit”);
pw.close();

        // executar arquivo .bat
        List<String> comandoBat = new ArrayList<String>();
        comandoBat.add("cmd.exe");
        comandoBat.add("/c");
        comandoBat.add(fileBat.getAbsolutePath());
        ProcessBuilder pb = new ProcessBuilder(comandoBat);
        Process process = pb.start();

        // escreve saida
        BufferedReader r = new BufferedReader(
                new InputStreamReader(process.getErrorStream()));
        String line = r.readLine();
        while (line != null) {
            System.err.println(line);
            line = r.readLine();
        }
        r.close();

        process.waitFor();
        System.out.println("backup realizado com sucesso.");
        process.destroy();

        return true;
    } catch (Exception e) {
        e.printStackTrace();
        JOptionPane.showMessageDialog(null, "ERRO durante o backup:" + e);
    }
    fileBat.delete();
    return false;
}[/code]

Se conseguir algo diferente posto o resultado aqui.

Abraços
Douglas Junior