梓彤 發表於 2025-5-12 09:37:28

powershell批处理io校验功能

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">powershell批处理&mdash;&mdash;io校验</a></li><li><a href="#_label1">使用</a></li><ul class="second_class_ul"><li><a href="#_lab2_1_0">测试.exe文件</a></li><li><a href="#_lab2_1_1">测试可执行.class文件</a></li></ul></ul></div><p class="maodian"><a name="_label0"></a></p><h2>powershell批处理&mdash;&mdash;io校验</h2>
<p>在刷题时,时常回想,OJ平台是如何校验竞赛队员提交的代码的,OJ平台并不看代码,而是使用&ldquo;黑盒测试&rdquo;,用测试数据来验证。对于每题,都事先设定了很多组输入数据(datain)和输出数据(dataout),OJ主要是看输入datain,看产生的输出是否与dataout一致。</p>
<p>如果需要一次性知道自己的所有测试输入数据是否能得到正确输出,一个一个测试就太慢了,批处理操作就能很好解决这个问题。刚好在学习powershell,本篇文章主要介绍一下这个ioCode项目。</p>
<p>项目目录结构</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202505/2025051209222122.png" /></p>
<ul><li>input目录:存放输入数据文件,以<code>.in</code>后缀结尾</li><li>output目录:存放输出数据文件,以<code>.out</code>后缀结尾,每个输出的文件名与对应的输入的文件名相同</li><li>start.ps1:编写的脚本文件</li></ul>
<p>start.ps1源代码:</p>
<div class="jb51code"><pre class="brush:ps;">function ioCheck{
    param(
      $content, #程序输出内容
      $answer #输出的答案内容
    )
    $cnt = $answer.length
    if($content.length -ne $cnt){
      return -1#行数不一致返回-1
    }
    for($i=0;$i -lt $cnt;$i++){
      if($answer[$i] -ne $content[$i]){
            return $i+1#内容不一致,返回第一个不同的行数
      }
    }
    return 0#相同返回0
}
function ioCode{
    param(
                $command,
      $inPath = './input',
      $outPath = './output'
    )
    $allStartTime = Get-Date
    $acList = New-Object System.Collections.ArrayList#创建正确输出的文件名集合
    $errList = New-Object System.Collections.ArrayList#创建错误输出的文件名集合
    $inFiles = Get-ChildItem -Path $inPath -Filter *.in#获取输入文件集
    $len = $inFiles.length
    $cnt = 0
    foreach($file in $inFiles){
      try {
            $startTime = Get-Date
            $fullOut = (cmd.exe /c "$command &lt; $($file.fullName)") -split "\r\n|\r|\n"#获取程序实际输出内容
            $endTime = Get-Date
            $duration = $endTime - $startTime#获取程序执行时间
            $answerPath = Join-Path -Path $outPath -ChildPath ($file.BaseName + '.out')
            $answer = Get-Content -Path $answerPath -ReadCount 0#获取该输入文件的对应输出文件的内容,-ReadCount 0指定返回一个字符串数组
            $res = ioCheck $fullOut $answer
            if($res -eq 0){
                $item = @{
                  fileName = $file.Name
                  exeTime = $duration
                }
                $acList.add($item) | Out-Null#Out-Null表示丢弃输出
                $cnt++
            }else{
                $item = @{
                  fileName = $file.Name
                  errLine = $res
                }
                $errList.add($item) | Out-Null
            }
      }
      catch {
            Write-Host "处理文件 $($file.Name) 时出现错误: $_"
      }
    }
    $allEndTime = Get-Date
    $allExeTime = $allEndTime-$allStartTime
    Write-Host "正确输出 $cnt/$len:,总耗时:$($allExeTime.Milliseconds)ms"
    foreach($item in $acList){
      Write-Host "Y: $($item.fileName) 耗时:$($item.exeTime.Milliseconds)ms"
    }
    foreach($item in $errList){
      Write-Host "N: $($item.fileName) errCode:$($item.errLine)"
    }
    return @{
      CorrectCount = $cnt
      TotalCount = $len
      acList = $acList
      errList = $errList
    }
}</pre></div>
<p>首先测试输入两个数,看能否成功输出两数之和</p>
<p>在input目录中创建三个文件分别为<code>001.in</code>,<code>002.in</code>,<code>003.in</code></p>
<p>内容分别为</p>
<blockquote><p>3 4</p></blockquote>
<blockquote><p>35749 47985</p></blockquote>
<blockquote><p>544 6755</p></blockquote>
<p>对应的在output目录创建三个同名的<code>.out</code>文件,分别为<code>001.out</code>,<code>002.out</code>,<code>003.out</code></p>
<p>内容就是对应<code>.in</code>文件中两个输入数据的相加的结果。</p>
<p class="maodian"><a name="_label1"></a></p><h2>使用</h2>
<p>编写好测试用例,就是可以测试我们写好的代码了,这里不仅可以测试C/C++生成的<code>.exe</code>可执行文件,还可以测试java生成的<code>.class</code>可执行字节码文件(前提是电脑具备java环境)。</p>
<p class="maodian"><a name="_lab2_1_0"></a></p><h3>测试.exe文件</h3>
<p>在当前目录下准备一个<code>test.cpp</code>文件,代码如下:</p>
<div class="jb51code"><pre class="brush:csharp;">#include&lt;iostream&gt;
using namespace std;
int main()
{
    int a, b;
    cin &gt;&gt; a &gt;&gt; b;
    cout&lt;&lt; 7;
    return 0;
}</pre></div>
<p>将其编译为可执行文件<code>test.exe</code>:</p>
<div class="jb51code"><pre class="brush:ps;">g++ -o test.exe test.cpp
</pre></div>
<p>在当前目录下打开powershell控制台</p>
<p>通过点加载start.ps1文件</p>
<div class="jb51code"><pre class="brush:ps;">. './start.ps1'</pre></div>
<p>输入命令<code>ioCode {command} {inPath} {outPath}</code>,command为可执行命令,inPath为输入文件目录(默认为当前目录的input目录),outPath为输出答案文件目录(默认为当前目录的output目录)</p>
<div class="jb51code"><pre class="brush:bash;">ioCode test.exe
</pre></div>
<p>示例:</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202505/2025051209222123.png" /></p>
<p>控制台输出显示我们的三个测试用例都通过了。</p>
<p class="maodian"><a name="_lab2_1_1"></a></p><h3>测试可执行.class文件</h3>
<p>在当前目录下准备一个<code>Main.java</code>文件,代码如下:</p>
<div class="jb51code"><pre class="brush:java;">import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
      Scanner scanner = new Scanner(System.in);
      int a = scanner.nextInt();
      int b = scanner.nextInt();
      System.out.println(a+b);
    }
}</pre></div>
<p>将其编译为可执行文件<code>Main.class</code>:</p>
<div class="jb51code"><pre class="brush:plain;">javac Main.java</pre></div>
<p>在当前目录下打开powershell控制台</p>
<p>通过点加载start.ps1文件</p>
<div class="jb51code"><pre class="brush:bash;">. './start.ps1'</pre></div>
<p>输入命令<code>ioCode {command} {inPath} {outPath}</code>,command为可执行命令,inPath为输入文件目录(默认为当前目录的input目录),outPath为输出答案文件目录(默认为当前目录的output目录)</p>
<div class="jb51code"><pre class="brush:bash;">ioCode 'java Main'#注意java Main是一个完整的命令,中间带有空格,需要用引号引起来</pre></div>
<p>示例:</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202505/2025051209222124.png" /></p>
<p>测试可执行<code>.py</code>文件</p>
<p>在当前目录下准备一个<code>Main.java</code>文件,代码如下:</p>
<div class="jb51code"><pre class="brush:java;">a,b=map(int,input().split())
print(a+b)</pre></div>
<p>在当前目录下打开powershell控制台</p>
<p>通过点加载start.ps1文件</p>
<div class="jb51code"><pre class="brush:ps;">. './start.ps1'</pre></div>
<p>输入命令<code>ioCode {command} {inPath} {outPath}</code>,command为可执行命令,inPath为输入文件目录(默认为当前目录的input目录),outPath为输出答案文件目录(默认为当前目录的output目录)</p>
<div class="jb51code"><pre class="brush:py;">ioCode 'python test.py'#注意python test.py是一个完整的命令,中间带有空格,需要用引号引起来</pre></div>
<p>示例:</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202505/2025051209222125.png" /></p>
<p>以上就是这个小项目的内容,通过<code>ioCode</code>可以批处理测试多个输入输出用例,并能清晰的看到哪些输入文件正确输出方便DeBug。</p>
頁: [1]
查看完整版本: powershell批处理io校验功能