Zingerella
Zingerella

Reputation: 450

Executing external command line utility in java and packaging it into runnable jar

I'm trying to build a program that uses the sox command line utility to convert a .dat file to a .wav file.

My approach was to create a .bat script and run it. This works in eclipse but when exporting and packaging it in an executable jar file it fails. This is probably due to two problems.

The first would probably be accessing the sox.exe and even my own directory from inside the jar file.

The other would be packaging the sox12181 folder which includes the files sox needs to run and sox.exe itself inside the jar file. I've searched for how to package it and only found examples packaging images inside resources.

Here's my code:

package executableIII;

import java.awt.Desktop;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.LinkedList;
import java.util.Queue;

public class SoundManipulation {

    public static void main(String[] args) throws IOException {
        Queue<Double> queue1 = new LinkedList<>();
        Queue<Double> queue2 = new LinkedList<>();
        StringBuilder sb = new StringBuilder();
        double sampleRate = 44100;
        int m = (int) (sampleRate * 3);
        int n = 700;
        for (int i = 0; i < n; i++) {
            queue1.add((Math.random() * 2) - 1);
        }
        queue2.add(0.0);
        for (int i = 0; i < m; i++) {
            double a = queue1.remove();
            double b = queue2.remove();
            double c = 0.99 * (a + b) / 2;
            queue1.add(c);
            queue2.add(a);
            sb.append(i * (1 / sampleRate) + " " + c + "\n");
        }
        FileOutputStream fs = new FileOutputStream(System.getProperty("user.dir") + "\\sox12181\\generated.dat");
        OutputStreamWriter out = new OutputStreamWriter(fs);
        out.write("; Sample Rate 44100\n; Channels 1\n");
        out.write(sb.toString());
        out.close();
        fs.close();
        try {
            FileOutputStream fsExec = new FileOutputStream("converter.bat");
            OutputStreamWriter outExec = new OutputStreamWriter(fsExec);
            outExec.write("cd " + System.getProperty("user.dir") + "\\sox12181\nsox generated.dat generated.wav");
            outExec.close();
            fsExec.close();
        } catch (IOException e) {
            System.err.println(e);
        }
        File temp1 = new File("converter.bat");
        Desktop.getDesktop().open(temp1);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        File temp2 = new File("sox12181\\generated.wav");
        Desktop.getDesktop().open(temp2);
    }
}

Here's a screenshot of the paths in my program:

https://imgur.com/a/Is4Zb

I'm new to the stackoverflow platform so if there's anything I should change please do point it out. Thank you!

Upvotes: 1

Views: 68

Answers (1)

deFreitas
deFreitas

Reputation: 4448

Based on @zingerella and @howlger discussion I did some tests then no, is not possible to execute a executable inside a jar, anyway I did a workaround for that, you can see it working at this link. Basically it will copy the executable to a SO temp folder then execute it. My project is using gradle anyway you can do it using eclipse as well, the follow snippet will consider that your executable will be in the jar root structure

final InputStream in = Main.class.getResourceAsStream("/myprogram");
if (in == null) {
    throw new RuntimeException("program not found");
}

final File tmpProgram = Files.createTempFile("mypgrogram", ".tmp").toFile();
Files.copy(in, tmpProgram.toPath(), StandardCopyOption.REPLACE_EXISTING);
tmpProgram.deleteOnExit();
tmpProgram.setExecutable(true);

final Process p = Runtime.getRuntime().exec(tmpProgram.getAbsolutePath());
System.out.println(p.waitFor());

for (int c; (c = p.getInputStream().read()) != -1; ) {
    System.out.print((char) c);
}
System.out.println();

for (int c; (c = p.getErrorStream().read()) != -1; ) {
    System.out.print((char) c);
}
System.out.println();

Upvotes: 1

Related Questions