Instead of trying to generate the path to the file using manual hard-coded String
, let's make a Path
and have it generate the file path for you. This is much less difficult to use, and it has the benefit of generating the correct file path no matter what the operating system or filesystem happen to be.
Replace the current exec command with this to implement that change:
Path parentDirectory = Paths.get("Users","Documents","Uni","Music Player","src","Common");
String sqlCommand = "sqlite3 database.db < database.sql";
Process process = runtime.exec(sqlCommand, null, parentDirectory.toFile());
This runs the "sqlite3 database.db < database.sql" command using the environmental variables inherited from the parent process (the JVM) and runs that command from within the directory specified by parentDirectory
, which happens to be the directory you gave in your question.
However, despite fixing the original problem, your code also contains another problem related to the use of file redirection. File redirection via <
or >
is a shell construct, and won't work outside of the shell. Using Runtime.exec()
is basically like using the Run...
GUI on Windows, and since file redirection doesn't work there it won't work here. You will need to fix the command used in order to address this problem. Luckily, there is a StackOverflow question addressing this exact problem here.
Here is the code with both issues fixed:
Path parentDirectory = Paths.get("Users","Documents","Uni","Music Player","src","Common");
String sqlCommand = "sqlite3 database.db";
File inputSqlFile = new File("database.sql");
Process process = new ProcessBuilder()
.directory(parentDirectory.toFile())
.command(sqlCommand)
.redirectInput(Redirect.from(inputSqlFile))
.start();
This code uses ProcessBuilder
to set the directory to the same parent directory as before, but the command has been modified to remove the file redirection and instead the file redirection is achieved using the redirectinput()
method. This accomplishes the same things as "sqlite3 database.db < database.sql"
would if executed within a shell, but this code will work within Java.
Edit:
The above code is not working, so I have attempted to fix it and have also added debugging statements to help track down the problem:
Path databasePath = FileSystems.getDefault().getPath("Users", "Documents", "Uni", "Music Player", "src", "Common", "database.db");
Path sqlPath = FileSystems.getDefault().getPath("Users", "Documents", "Uni", "Music Player", "src", "Common", "database.sql");
File database = databasePath.toFile().getAbsoluteFile();
File sqlFile = sqlPath.toFile().getAbsoluteFile();
System.out.println("Database location:\n\t" + database.getCanonicalPath());
System.out.println("SQL file location:\n\t" + sqlFile.getCanonicalPath());
assert database.exists() && database.isFile() && database.canRead() && database.canWrite(): "No such database file!";
assert sqlFile.exists() && sqlFile.isFile() && database.canRead() : "No such SQL file!";
String[] sqlCommand = {"sqlite3", database.getCanonicalPath()};
Redirect sqlInput = Redirect.from(sqlFile);
File workingDirectory = database.getParentFile().getCanonicalFile();
System.out.println("Running this command:\n\t" +
sqlCommand[0] + sqlCommand[1] + "<" + sqlInput.file().getCanonicalPath());
Process process = new ProcessBuilder()
.directory(workingDirectory)
.command(sqlCommand)
.redirectInput(sqlInput)
.start();
And here is the same code with the debugging code removed and a slight cleanup:
File database = FileSystems.getDefault()
.getPath("Users", "Documents", "Uni","Music Player", "src", "Common", "database.db")
.toFile().getAbsoluteFile();
File sqlFile = FileSystems.getDefault()
.getPath("Users", "Documents", "Uni","Music Player", "src", "Common", "database.sql")
.toFile().getAbsoluteFile();
String[] sqlCommand = {"sqlite3", database.getCanonicalPath()};
Redirect sqlInput = Redirect.from(sqlFile);
File workingDirectory = database.getParentFile().getCanonicalFile();
Process process = new ProcessBuilder()
.directory(workingDirectory)
.command(sqlCommand)
.redirectInput(sqlInput)
.start();