Java:使用Scanner的子进程抛出NoSuchElementException

时间:2016-02-24 08:28:53

标签: java subprocess outputstream stdio nosuchelementexception

抱歉笨拙的英语;这不是我的母语。

我正在开发在线评判,以便在下学期使用。

这将从学生那里收到一个.java文件并进行编译,

并运行.class并由教授用预定义的测试用例进行测试。

但是当我在下面提交一个java文件时,Enter.java,出现了执行错误,并且.java文件被判为ExecutionError。

import java.util.Scanner;

public class Enter {

    public static void main(String[] args) {
    // TODO Auto-generated method stub

        int i=0;
        int max=0;
        int min=10000000;

        while(true)
        {
            System.out.print("Enter integer :");

            Scanner input = new Scanner(System.in);
            i = input.nextInt();

            if(i==-1)
                break;

            else if(i>max)
            {
                max=i;
            }
            else if(i<min)
            {
                min=i;
            }

        }
        System.out.printf("Smallest Integer is : %d",min);
        System.out.println();
        System.out.printf("Largest Integer is : %d", max);
    }

}

当然,这不是一个正确的源代码,但是我觉得系统将其判断为ExecutionError(这意味着系统运行.class时会发生异常,以便用testcases对其进行测试)。 并且在Input.nextInt()中也会出现NoSuchElementException; 但它应该被判断为失败(运行和结束,但产生错误的输出)。

这是JudgeModule.java的来源

private Judgement judge() {

    // some works before compile & test //

    // phase 1. compile //
    CompileResult compileResult = tester.doCompile(compiler, fd);

    if( !compileResult.isSuccess() )    // compile fail
    {
        // some works
        Judgement judgement = new Judgement(compileResult.getResult());
        return judgement;
    }

    // pahse 2. execute
    ExecuteResult executeResult = tester.doTest(compiler, fd, testcases);

    if( executeResult.getException() != null )
    {
        // some works
        Judgement judgement = new Judgement(executeResult.getResult());
        return judgement;
    }

    // some works after compile & test//

    Judgement judgement = new Judgement(executeResult.getResult());

    return judgement;
}

tester只是SourcecodeTester的一个实例,没有成员变量,只是持有doCompile()和doTest()。

以下是SourcecodeTester的来源。我省略了doCompile()的事情。

public class SourcecodeTester {

    static long executeTimeout = 1000;
    public class ExecuteResult {
        JudgeResult result;
        Exception exception;
        ArrayList<TestResult> testResults;
    }
    public class TestResult {
        JudgeResult result;
        Exception exception;
        String output;
    }


    public ExecuteResult doTest(Compiler compiler, FileDescription fd, Testcase[] testcases )
    {
        // pahse 2. execute
        JudgeResult result = JudgeResult.Pass;
        Exception exception = null;
        ArrayList<TestResult> testResults = new ArrayList<>();

        try {
            for( Testcase testcase : testcases )
            {
                testResults.add( execute(compiler, testcase, fd ) );
            }

        } catch( Exception e ) {
            e.printStackTrace();
            result = JudgeResult.SystemError;
            exception = e;
        }
        // do some works

        return new ExecuteResult(result, exception, testResults );
    }


    private TestResult execute(Compiler compiler, Testcase testcase, FileDescription fd ) 
    {
        Runtime runTime = Runtime.getRuntime();

        String executeCommand = assembleExecuteCommand(compiler, fd);

        JudgeResult executeResult = JudgeResult.Fail;
        Exception executeException = null;
        String executeOutput = "";
        try {
            boolean timeout = false;
            long startTime = System.currentTimeMillis();

            Process executeProcess = runTime.exec(executeCommand);
            writeToProcessInput(executeProcess, testcase.getInput());       // write to process input
            while( executeProcess.isAlive() && !timeout )
            {
                Thread.sleep(10);
                if((System.currentTimeMillis()-startTime) > executeTimeout )
                    timeout = true;
            }

            if( timeout )
            {
                executeProcess.destroy();
                throw new JudgeException("execution timeout!" + (System.currentTimeMillis()-startTime) + "ms", JudgeResult.ExecutionTimeout);
            }

            // exam exitValue
            int exitValue = executeProcess.exitValue();

            // read from process output
            char[] processOutput = readFromProcessOutput(executeProcess);

            // read from process error
            char[] processError = readFromProcessError(executeProcess);

            if( exitValue != 0 ) {
                throw new JudgeException("execution fail with exitvalue : " + exitValue + " >\n" + String.valueOf(processError), JudgeResult.ExecutionError);
            }
            else if( processError.length != 0 ) {
                throw new JudgeException("execution fail with error : " + String.valueOf(processError), JudgeResult.ExecutionError );
            }

            String output = String.valueOf(testcase.getOutput()).replaceAll("\r\n", "\n");
            executeOutput = String.valueOf(processOutput);

            if( Arrays.equals(processOutput, output.toCharArray()) ) {
                executeResult = JudgeResult.Pass;
            }
            else {
                executeResult = JudgeResult.Fail;
            }
        } 
        catch( JudgeException e ) {
            e.printStackTrace();
            executeResult = JudgeResult.ExecutionError;
            executeException = e;
        }
        catch( Exception e ) {
            e.printStackTrace();
            executeResult = JudgeResult.SystemError;
            executeException = e;
        }
        return new TestResult( testcase.getId(), executeResult, executeException, executeOutput );
    }


    private void writeToProcessInput(Process _process, char[] _dataToWrite ) throws IOException
    {
        OutputStreamWriter osw = new OutputStreamWriter(_process.getOutputStream() );
        BufferedWriter writer = new BufferedWriter( osw );
        writer.write( _dataToWrite );
//      osw.write(_dataToWrite);
        writer.close();
        osw.close();
    }

    private char[] readFromProcessOutput(Process _process) throws IOException
    {
        return readFromStream(  new InputStreamReader( _process.getInputStream() )  );
    }

    private char[] readFromProcessError(Process _process) throws IOException
    {
        return readFromStream(  new InputStreamReader( _process.getErrorStream() )  );
    }

    private char[] readFromStream(InputStreamReader isr) throws IOException {
        int numOfByteRead;
        char[] readBuffer = new char[1024];
        StringBuffer standardOutput = new StringBuffer();
        while ((numOfByteRead = isr.read(readBuffer)) > 0) {
            standardOutput.append(readBuffer, 0, numOfByteRead);
        }

        return standardOutput.toString().toCharArray();
    }

}

当我从命令行或Eclipse编译并执行Enter.java时, 它工作正常,我可以从控制台输入几个数字,没有异常发生。

但是我将它提交给OnlineJudge,然后发生NoSuchElementException。 用于测试的输入字符数组只包含由空格字符分隔的多个数字。

最后,我想问的是,

  1. 之间的差异以及它的工作方式有何不同
    • 运行Enter.class并从控制台输入几个输入。
    • 使用Process.exec()运行Enter.class并将char数组写为子进程输出流的输入。

    为什么Enter.java上的scanner.nextInt()会抛出NoSuchElementException?

  2. 如何将OnlineJudge修改为Enter.java的工作方式相同。

0 个答案:

没有答案