zoukankan      html  css  js  c++  java
  • Java后台调用gcc编译C语言代码

    想做一个能够在线编译代码运行的平台,Java和SQL已经支持了,因为是用Java写的后台,所以Java和SQL挺容易就实现了,做到支持C的时候就卡住了,网上搜了一下这种帖子好像很少。

    我采取的办法是就是刚开始学C语言的教的调用GCC来编译.C文件的文件,首先将前端传过来的C代码写入到特定的路径下,然后利用Java的API调用CMD来执行gcc命令编译这个文件,这好像有点MakeFile文件的意思。。编译之后继续调用CMD执行生成的exe,同时获取CMD的输出,至此整个过程完成,但是最后需要做好一项善后工作,那就是继续调用CMD将这个exe的进程杀掉,否则会出现问题,因为exe还没停止,继续编译写入会报权限问题。

    封装了整个编译运行的Servivce:

    package com.mine.ide.service.implement;
    
    import com.mine.ide.util.CLangUtil;
    import org.apache.log4j.Logger;
    import org.springframework.stereotype.Service;
    
    import java.io.*;
    import java.util.concurrent.*;
    
    /**
     * @author yintianhao
     * @createTime 20190625 11:14
     * @description ExecuteCLang
     */
    @Service
    public class ExecuteCLangService {
        private static final Logger log = Logger.getLogger(ExecuteCLangService.class);
    
        //代码存放路径
        public static final String CODE_PATH = "D:\springboot2\code\";
    
    
        /**
         * @param content C代码
         * */
        private boolean generateCFile(String content){
            BufferedWriter out = null;
            try{
                //写入
                out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(CODE_PATH+"test.c", false)));
                out.write(content);
            }catch (Exception e){
                log.error(e.getCause().getMessage());
                return false;
            }finally {
                try {
                    out.close();
                }catch (IOException e){
                    log.error(e.getCause().getMessage());
                    return false;
                }
            }
            return true;
        }
        /**
         * @param sourceCode 源代码
         * */
        public String runCLangCode(String sourceCode){
            //先生成文件
            generateCFile(sourceCode);
            Executor executor = Executors.newSingleThreadExecutor();
            FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>() {
                @Override
                public String call() throws Exception {
                    //编译C文件
                    String compileResult = execCmd("gcc -o "+CODE_PATH+"test "+CODE_PATH+"test.c",null);
                    if (compileResult.equals(""))
                        //编译不出错的情况,replaceAll将
    换成HTML的换行,空格换成HTML的空格
                        return execCmd(CODE_PATH+"test.exe",null).replaceAll("
    ","<br/>").replaceAll(" ","&nbsp;");
                    else {
                        //编译出错,找到error的位置,返回error及其后的信息
                        int errorIndex = compileResult.indexOf("error");
                        return compileResult.substring(errorIndex).replaceAll("
    ","<br/>").replaceAll(" ","&nbsp;");
                    }
                }
            });
            executor.execute(futureTask);
            try {
                //编译运行完毕将text.exe的进程kill
                execCmd("taskkill /f /im test.exe",null);
                log.info("killed test.exe");
            }catch (Exception e){
                e.printStackTrace();
            }
            String result = "";
            try{
                //设置超时时间
                result=futureTask.get(10, TimeUnit.SECONDS);
            }catch (InterruptedException e) {
                log.info("Interrupt");
                result = "程序中断,请检查是否有内存冲突等错误";
                // future.cancel(true);
            }catch (ExecutionException e) {
                result = "程序执行错误";
                futureTask.cancel(true);
            }catch (TimeoutException e) {
                result = "时间超限,请检查是否存在无限循环等程序无法自动结束的情况";
            }
            log.info("result - "+result);
            return result.equals("")?"没有输出":result;
        }
        /**
         * 执行系统命令, 返回执行结果
         * @param cmd 需要执行的命令
         * @param dir 执行命令的子进程的工作目录, null 表示和当前主进程工作目录相同
         */
        private String execCmd(String cmd, File dir) throws Exception {
            StringBuilder result = new StringBuilder();
    
            Process process = null;
            BufferedReader bufrIn = null;
            BufferedReader bufrError = null;
    
            try {
                // 执行命令, 返回一个子进程对象(命令在子进程中执行)
                process = Runtime.getRuntime().exec(cmd, null, dir);
    
                // 方法阻塞, 等待命令执行完成(成功会返回0)
                process.waitFor();
    
                // 获取命令执行结果, 有两个结果: 正常的输出 和 错误的输出(PS: 子进程的输出就是主进程的输入)
                bufrIn = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
                bufrError = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
    
                // 读取输出
                String line = null;
                while ((line = bufrIn.readLine()) != null) {
                    result.append(line).append('
    ');
                }
                while ((line = bufrError.readLine()) != null) {
                    result.append(line).append('
    ');
                }
    
            } finally {
                closeStream(bufrIn);
                closeStream(bufrError);
    
                // 销毁子进程
                if (process != null) {
                    process.destroy();
                }
            }
    
            // 返回执行结果
            return result.toString();
        }
    
        private void closeStream(Closeable stream) {
            if (stream != null) {
                try {
                    stream.close();
                } catch (Exception e) {
                    // nothing
                }
            }
        }
    }

    至此写完,之后只要调用runCLangCode方法就可以了

  • 相关阅读:
    【协议分析】Wireshark 过滤表达式实例
    学习Javascript闭包(Closure)
    如何解决 touchstart 事件与 click 事件的冲突
    JS实现控制HTML5背景音乐播放暂停
    $.ajax()方法详解
    js将汉字转为相应的拼音
    js 滚动到一定位置导航定位在页面最顶部
    javascript获取网页地址栏的id
    jquery 上传图片转为base64,ajax提交到后台
    jquery 图片转为base64
  • 原文地址:https://www.cnblogs.com/Yintianhao/p/11082311.html
Copyright © 2011-2022 走看看