#java #file-io #processbuilder
Вопрос:
Я создал API, который будет принимать полезную нагрузку (code, language)
, которая, в свою очередь, генерирует случайное имя для сохранения файла(в зависимости от языка, на котором будут выбраны расширения) из java. полезная нагрузка из пользовательского интерфейса приведена ниже
{"code": "class Demo{ rn" " public static void main(String args[]){ rn" " System.out.println("Hello Java"); rn" " } rn" "}", "language": "java"}
Сохранение файлов работает должным образом , как и ожидалось, и я могу сохранить файл под C:\temp
, но проблема возникает, когда я пытаюсь выполнить эти сохраненные файлы с ProcessBuilder
помощью java, получая Error: Could not find or load main class BNkHZk
(так как случайно сгенерированное имя файла отличается от файла класса после выполнения приведенного ниже кода).
ProcessBuilder processBuilder = new ProcessBuilder(new String[] { "javac", fullPath }); //fullPath is C:tempBNkHZk.java Process process = processBuilder.start();
приведенное выше выполнение создаст новый Demo.class файл. После выполнения приведенной выше команды я выполняю приведенный ниже код
processBuilder = new ProcessBuilder(new String[] { "javac", fullPath }); Process process = processBuilder.start(); if (process.getErrorStream().read() != -1) { System.out.println("Compilation Errors" process.getErrorStream()); } BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line = ""; while ((line = reader.readLine()) != null) { System.out.Println(line); }
Я получаю следующую ошибку Error: Could not find or load main class BNkHZk
Полная функция приведена ниже, как показано ниже
private void ExecuteCode(String language, String code){ String tempFileName = RandomStringUtils.randomAlphanumeric(6); // Code to creating the file and save under "C:\temp\" String fullPath = "C:\temp\" tempFileName "." language; try { fileWriter = new FileWriter(new File(fullPath)); fileWriter.write(code); } catch (Exception e) { System.out.println("IO Exception while creating new file"); e.printStackTrace(); } finally { if (fileWriter != null) { fileWriter.close(); } } ProcessBuilder processBuilder = new ProcessBuilder(new String[] { "javac", fullPath }); ////fullPath is C:tempBNkHZk.java Process process = processBuilder.start(); if (process.getErrorStream().read() != -1) { BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream())); String line = ""; while ((line = reader.readLine()) != null) { System.out.println(line); } } //the above execution will create a new **Demo.class** file. int exitcode = -1; try { exitcode = process.waitFor(); } catch (InterruptedException e) { e.printStackTrace(); } if (exitcode == 0) { ( processBuilder = new ProcessBuilder(new String[] { "java","tempFileName"});//BNkHZk Process process1 = processBuilder.start(); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line = ""; while ((line = reader.readLine()) != null) { System.out.println(line "n"); } } }
Я получаю error Error: Could not find or load main class BNkHZk
Примечание: Поскольку я получу содержимое файла в виде строки, я не смогу сохранить имя файла так же, как .class
имя. Есть ли какой-либо обходной путь, чтобы сохранить имя файла таким же, как имя .class ?? Любые предложения по обходным путям приветствуются и приветствуются. Заранее спасибо.
Ответ №1:
Есть две разные проблемы. Первый из них-это имя файла класса. Имя класса должно совпадать с именем файла. class Demo -gt; Demo.java
, вот почему вы не можете использовать случайные имена файлов. Компиляция выполняется хорошо, но не запуск.
Второй — это обработка ProcessBuilder. Я предлагаю следующую схему:
ProcessBuilder pb = new ProcessBuilder("javac.exe", "Demo.java"); pb.directory(Paths.get("path_to_java_file").toFile()); pb.redirectErrorStream(true); Process process = pb.start(); try (var infoStream = process.getInputStream()) { infoStream.transferTo(System.out); } status = process.waitFor();
Теперь вы можете увидеть, правильно ли выполняется компиляция.
Используйте тот же шаблон для запуска скомпилированного класса.
Комментарии:
1. Привет @Thilo Schwarz, спасибо за быстрый ответ. Поскольку я получу содержимое файла в виде строки, я не смогу сохранить имя файла таким же, как имя .class.
2. @UllasSharma Вы получаете свой исходный код в виде текста, верно? Вы должны сохранить этот код в виде файла java,
Demo.java
. Следующий шаг-компиляция с помощью javac, верно? Результатом компиляции является файлDemo.class
. Или я неправильно понял рабочий процесс?3. @Ullas Sharma просто создайте временный каталог, а затем ожидаемый файл Java внутри него на этапе генерации —
Path fullPath = Path.of("C:/temp", tmpFileName, "Demo." language);
и тогда все вышесказанное будет работать внутри временного каталога4. @ Thilo Schwarz, я получаю содержимое только в виде текста, но я не получу точное имя класса файла, так как это динамическое содержимое. например, если вы видите JSON req ,я буду получать из пользовательского
{"code": "class Sample{ public static void main(String args[]){ System.out.println("Hello Java"); }", "language": "java"}
интерфейса, как должно быть в соответствии с вашим пониманием имениSample.java
файла, но я не могу получить само имя класса, так как это довольно сложно сделать из динамического текстового содержимого.5. @DuncG я ищу обходной путь с помощью processbuilder, чтобы получить вновь созданное
.class
имя, содержимое только в виде текста, но я не получу точное имя класса файла, так как это динамическое содержимое. например, если вы видите JSON req ,я буду получать из пользовательского{"code": "class Sample{ public static void main(String args[]){ System.out.println("Hello Java"); }", "language": "java"}
интерфейса, как должно быть в соответствии с вашим пониманием имениSample.java
файла, но я не могу получить само имя класса, так как это довольно сложно сделать из динамического текстового содержимого.
Ответ №2:
Вы можете справиться с этим двумя способами.
Если у вас есть последняя версия Java, вы можете просто пропустить шаг «javac» и запустить «java», и класс будет автоматически скомпилирован и автоматически запущен, даже если имя класса не совпадает с именем .java
файла.
Поэтому, если бы ваш временный java-файл был сгенерирован "\Temp\XYZ.java"
, он бы скомпилировался и запустился, распечатав Hello Java
:
Path fullPath = Path.of("/Temp", "XYZ.java").toAbsolutePath(); // wherever var pb = new ProcessBuilder(new String[] { "java", fullPath.toString() }); ...
Если у вас нет последней версии Java, выполните свой шаг «javac», но запишите файл во вновь созданный каталог, используемый только для этого одного сгенерированного файла Java:
Path fullPath = Path.of("/Temp", "wherever", "ANYNAME.java").toAbsolutePath(); var pb = new ProcessBuilder(new String[] { "javac", fullPath }); ...
Затем просмотрите содержимое fullPath.getParent()
и , чтобы найти файл с расширением .class
, выведите имя класса из имени файла перед расширением файла и используйте свой шаг «java» с этим производным именем класса и с каталогом пути к классу, установленным в fullPath.getParent()
. Например, второй этап будет выглядеть так:
String fn = Files.list(fullPath.getParent()).map(Path::getFileName).map(Path::toString).filter(s -gt; s.endsWith(".class")).findFirst().get(); String className = fn.substring(0, fn.lastIndexOf('.')); var pb = new ProcessBuilder(new String[] { "java", "-cp", fullPath.getParent().toString(), className }); ...
Комментарии:
1. спасибо за обходной путь… это временно решило мою проблему.