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方法就可以了

  • 相关阅读:
    poj 2485 Highways 最小生成树
    hdu 3415 Max Sum of MaxKsubsequence
    poj 3026 Borg Maze
    poj 2823 Sliding Window 单调队列
    poj 1258 AgriNet
    hdu 1045 Fire Net (二分图匹配)
    poj 1789 Truck History MST(最小生成树)
    fafu 1181 割点
    减肥瘦身健康秘方
    人生的问题
  • 原文地址:https://www.cnblogs.com/Yintianhao/p/11082311.html
Copyright © 2011-2022 走看看