作者:chenjieb520(两片森林)
相信很多做过ACM竞赛题目的人都知道:你提交了代码之后,系统就会对的代码进行编译,然后给出代码的编译的信息还有执行结果。很多人都不太明白如何使用C#进行开发类似的功能。笔者在大学的时期,写过如下一个类,这个类可以解决这个问题。现在自己开了CSDN博客,就将这些自己认为好东西分享给大家,希望对那些需要这些资源的同学有所帮助。
///////////Core.cs 简易的ACM评判黑盒的core类。这个类比较简单,但是大部分的ACM评判思想已经包含进去了。
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Diagnostics;
using System.IO;
/// <summary>
/// Core 的摘要说明
/// </summary>
/// 这是ACM竞赛网评判系统的内核,编写时间2009-03-24
/// 编写:chenjieb520
public class Core
{
private String CodeStr=null;//所提交的代码
private String ProgramName = null;//文件名
private String BasePathName = null;//放所有用户的代码的路径
private String PathName = null;//用户名所建的文件夹名
private String PathNameCode = null;//绝对路径下的用户代码
private String PathNameExe = null;//编译生成的可执行文件
private String PathNameObj = null;//编译生成的obj文件
private String StandardInPutStr = null;//从数据中读出的input的内容
private String InputTxt = null;//将StandardInPut内容写到文件的文件名
private String OutputTxt = null;
private String StandardOutPutStr = null;//从数据库中读出的output内容
private String CodeExe = null;//生成的exe的名字
private int flage;//编译的类型
private String javaclassName=null;//用户提交的代码java的文件名
public Core(String LoginName,String TitleID,String CodeStr,String StandardInPut,String StandardOutPut,int flage)
{
this.CodeStr = CodeStr;
this.flage =flage;
if (flage==1)//C语言
{
this.ProgramName = TitleID + ".cpp";
}else if (flage==2)//C++
{
this.ProgramName = TitleID + ".cpp";
}
else if (flage == 3)//java
{
javaclassName = GetJavaCodeClass(CodeStr);
if (javaclassName=="0")
{
this.ProgramName = null;
}
this.ProgramName = javaclassName + ".java";
}else if (flage==4)//c#
{
this.ProgramName = TitleID + ".cs";
}
this.BasePathName = "J://JmuACM//DugProgram//";
this.PathName = BasePathName + LoginName;
this.PathNameCode = BasePathName + LoginName + "//" + ProgramName;
if (flage==3)//java部分的
{
this.CodeExe = javaclassName + ".class";
}else
{
this.CodeExe = TitleID + ".exe";
}
this.PathNameObj = BasePathName + LoginName + "//" + TitleID + ".obj";
this.PathNameExe = BasePathName + LoginName + "//" + this.CodeExe;
this.InputTxt = BasePathName + LoginName + "//" + "input.in";
this.OutputTxt = BasePathName + LoginName + "//" + "output.out";
this.StandardInPutStr = StandardInPut;
this.StandardOutPutStr = StandardOutPut;
if (Directory.Exists(PathName) == false)//如果不存在就创建file文件夹
{
Directory.CreateDirectory(PathName);
}
StreamWriter sw;
if (File.Exists(InputTxt))//判断input文件是否存在,为.in的后缀的
{
sw = File.AppendText(InputTxt);
}else
{
sw = File.CreateText(InputTxt);
}
sw.WriteLine(StandardInPutStr);
sw.Close();
}
/* 判断是否可以编译通过
* 返回-1说明有非法的打印字符
* 返回1编译通过 返回0编译失败
* 返回-2出现异常
* 返回-3,所提交的代码类型不是java,却选择了JAVA类型进行提交
*/
public int IsDug()
{
string cmd=null;
if (ProgramName==null)
{
return -3;
}
if (File.Exists(PathNameExe))
{
File.Delete(PathNameExe);//存在上一次的编译的生成的,就进行删除
if(flage==1||flage==2)
{
File.Delete(PathNameObj);
}
}
StreamWriter sw = new StreamWriter(this.PathNameCode);//创建该文件
sw.Write(CodeStr);
sw.Close();
try
{
Process myProcess = new Process();
myProcess.StartInfo.FileName = "cmd.exe";//DOS控制平台
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.CreateNoWindow = true;
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.StartInfo.RedirectStandardOutput = true;
myProcess.StartInfo.RedirectStandardError = true;
myProcess.StartInfo.WorkingDirectory = this.PathName;
myProcess.Start();
StreamWriter sIn = myProcess.StandardInput;//标准输入流
sIn.AutoFlush = true;
StreamReader sOut = myProcess.StandardOutput;//标准输入流
StreamReader sErr = myProcess.StandardError;//标准错误流
if (flage==1)
{
cmd = "cl "+this.PathNameCode;
}else if(flage==2)
{
cmd = "cl " + this.PathNameCode;
}else if (flage==3)
{
cmd = "javac " + this.PathNameCode;
}else if (flage==4)
{
cmd = "csc " + this.PathNameCode;
}
sIn.Write(cmd + System.Environment.NewLine);
sIn.Write("exit" + System.Environment.NewLine);
string s = sOut.ReadToEnd();//读取执行DOS命令后输出信息
string er = sErr.ReadToEnd();//读取执行DOS命令后错误信息
if (myProcess.HasExited == false)
{
myProcess.Kill();
}
sIn.Close();
sOut.Close();
sErr.Close();
myProcess.Close();
if (File.Exists(PathNameExe))
{
return 1;
}
return 0;
}
catch
{
return -2;
}
}
//判断是否对了
//返回1表示该用户已经答对了该题了
public int ExecProgram()
{
int tmpflage=IsDug();
if (tmpflage==1)
{
if (File.Exists(OutputTxt))
{
File.Delete(OutputTxt);
}
try
{
String cmd=null;
Process myProcess = new Process();
myProcess.StartInfo.FileName = "cmd.exe";//DOS控制平台
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.CreateNoWindow = true;
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.StartInfo.RedirectStandardOutput = true;
myProcess.StartInfo.RedirectStandardError = true;
myProcess.StartInfo.WorkingDirectory = this.PathName;
myProcess.Start();
StreamWriter sIn = myProcess.StandardInput;//标准输入流
sIn.AutoFlush = true;
StreamReader sOut = myProcess.StandardOutput;//标准输入流
StreamReader sErr = myProcess.StandardError;//标准错误流
if (flage == 1)
{
cmd = PathNameExe+"<input.in "+">>output.out";
}
else if (flage == 2)
{
cmd = PathNameExe + "<input.in " + ">>output.out";
}
else if (flage == 3)//java
{
cmd = "java " + this.PathNameCode + "<input.in " + ">>output.out";
}else if (flage==4)
{
cmd = PathNameExe + "<input.in " + ">>output.out";
}
sIn.Write(cmd + System.Environment.NewLine);
sIn.Write("exit" + System.Environment.NewLine);
string s = sOut.ReadToEnd();//读取执行DOS命令后输出信息
string er = sErr.ReadToEnd();//读取执行DOS命令后错误信息
// HttpContext.Current.Response.Write(s + er);
if (myProcess.HasExited == false)
{
myProcess.Kill();
}
sIn.Close();
sOut.Close();
sErr.Close();
myProcess.Close();
//开始读取执行所生成的文件并且和标准的OutPut.out进行匹配
// HttpContext.Current.Response.Write(OutputTxt);
if (File.Exists(OutputTxt))//这次编译生成的.out文件
{
String tmpstr = File.ReadAllText(OutputTxt);
if (tmpstr.Trim().Equals(StandardOutPutStr.Trim()))
{
DeleteAllFile();//答对的话,就对所有的中间产生的信息进行全部删除
// HttpContext.Current.Response.Write("你答对了该题了");
return 1;//该用户答对了该题了
}else
{
DeleteAllFile();
return 2;//表示虽然编译通过了,但是和.out不匹配
}
}
// HttpContext.Current.Response.Write("编译已经成功,但是你所生成的.out文件没有和系统匹配,请将自己的代码的中的Output文件改为: 题目号.out ");
DeleteAllFile();
return 0;//执行程序后,没有生成指定的文件
}
catch
{
// HttpContext.Current.Response.Write("代码执行过程中出现了异常,请重新提交,或者稍后提交,报告Bug:[email protected]");
DeleteAllFile();
return -1;//执行的过程中抛出了异常
}
}else if (tmpflage==-2)
{
DeleteAllFile();
return -2;//编译过程,系统发生了异常
}
else if (tmpflage == 0)
{
// HttpContext.Current.Response.Write("编译没有通过,你所提交的代码含有错误");
DeleteAllFile();
return -4;//编译没有通过,代码有错误
}else if (tmpflage==-3)
{
// HttpContext.Current.Response.Write("你所提交的代码不是java类型,却选择了JAVA类型进行编译");
DeleteAllFile();
return -6;
}
else
{
// HttpContext.Current.Response.Write("编译过程出现了异常");
DeleteAllFile();
return -5;//编译过程出现了异常
}
}
//获取采用java编写提交的代码的中的类名,该类名用来给该文件命令,这是java的规则
private String GetJavaCodeClass(String JavaCode)
{
int tmpstart = JavaCode.IndexOf("class", 0);
int tmpend=JavaCode.IndexOf("{",0);
if (tmpstart==-1)
{
// HttpContext.Current.Response.Write("你所提交的代码不是JAVA类型的,请选择代码类型");
return "0";
}
String str=JavaCode.Substring(tmpstart+5,tmpend-tmpstart-5).Trim();
return str;
}
//清理垃圾文件,每一次提交完毕之后,将所有产生的垃圾文件进行删除,但是保留代码文件,用于以后让大家学习
private void DeleteAllFile()
{
if (File.Exists(PathNameExe))
{
File.Delete(PathNameExe);
}
if (File.Exists(PathNameObj))
{
File.Delete(PathNameObj);
}
if (File.Exists(InputTxt))
{
File.Delete(InputTxt);
}
if (File.Exists(OutputTxt))
{
File.Delete(OutputTxt);
}
}
public String GetError(int type)
{
String ErrorStr = null ;
switch (type)
{
case 0:
ErrorStr = "代码已经编译成功,但是系统在生成.out文件时,出现异常";
break;
case 1:
ErrorStr = "【提交成功】,恭喜你,已经答对了该题了,请再接再厉,加油";
break;
case 2:
ErrorStr = "代码已经编译成功,但是你的算法中存在逻辑错误。或者你数据变量的范围太小 ,尝试将int"+
"改为long。请仔细设计算法逻辑。";
break;
case -1:
ErrorStr = "代码执行的过程中,系统发生了异常。解决方案,尝试重新进行提 交。该错误是由系统引 "+
" 起的,如果多次出现同样错误,请报告错误给我:[email protected]";
break;
case -2:
ErrorStr = "代码已经编译成功,在执行的过程中系统出现异常,请稍候提交。";
break;
case -4:
ErrorStr = "编译没有通过,你所提交的代码含有错误。请好好查看一下代码是 否出现了错误或者所选" +
"择的编译语言的类型有错。";
break;
case -5:
ErrorStr = "编译过程中,系统出现了异常错误。请稍候进行提交。";
break;
case -6:
ErrorStr = "你所提交的代码不是java类型,却选择了JAVA类型进行编译。请重新 选择语言类型。";
break;
}
return ErrorStr;
}
}
//该类主要负责处理用户提交的程序使用的执行时间和内存的情况
//主要用于检测用户是否提交了死循环或者恶意大量开辟内存的情况
//由于考虑到一些都是程序设计的初学者,这里就先不进行限制
/*public class GetProcessRun
{
private string ProcessName=null;
private int Memory = 0;//使用内存情况
private int RunTime = 0;//运行所花费的时间
public Process[] MyProcess = Process.GetProcesses();
GetProcessRun(int Memory,int RunTime,String ProcessName)
{
this.Memory = Memory;
this.RunTime = RunTime;
this.ProcessName = ProcessName;
MyProcess = Process.GetProcessesByName(ProcessName);
}
private double GetMemory()
{
return (MyProcess[0].WorkingSet / 1024);
}
private double GetRunTime()
{
return MyProcess[0].TotalProcessorTime.TotalMinutes;
}
}*/
如果大家在使用这类的时候,有疑问,欢迎大家进行评论和交流。我讲尽自己的力量为大家答疑。