[RESOLVIDO] Dump PostgreSQL via java.lang.Runtime

10 respostas
douglasjunior

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

10 Respostas

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

douglasjunior

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

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

E

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", 
...
});
douglasjunior

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", ... });

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

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

douglasjunior

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

Opa, muito obrigado, fico no aguardo.

Abraço
Douglas Junior

andre_bento

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.

/*
 * 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;
        }
        
}

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.

douglasjunior

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.

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

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

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:

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;
    }

Abraços
Douglas Junior

douglasjunior

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:
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;
    }

Se conseguir algo diferente posto o resultado aqui.

Abraços
Douglas Junior

Criado 13 de março de 2012
Ultima resposta 26 de mar. de 2012
Respostas 10
Participantes 3