You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Delphi的JvCreateProcess1Terminate方法中获取PowerShell输出的JSON?

问题:如何在JvCreateProcess1Terminate事件中获取PowerShell输出的JSON

我正在开发一个测试程序,用来验证后续要加到主程序的功能,避免破坏主程序。我是Pascal新手,对很多机制还不熟悉。这个程序的目标是在应用内执行PowerShell命令,获取指定目录的JSON数据,以此检查目录中特定扩展名文件的存在或数据量大小。

我在Delphi里创建了三个组件:启动按钮、Timer和JvCreateProcess。Timer的Interval设为10ms,OnTimer绑定了Timer1Timer方法。


现有代码

Timer1Timer方法

procedure TUProbando.Timer1Timer(Sender: TObject);
var
  Comando: TStrings;
  ValorJSON: TStrings;
begin
  if ContadorDirectorios = Length(rutas) then
  begin
    Timer1.Enabled := false;
    exit;
  end;

  Timer1.Enabled := false;
  Lista.Clear;
  // spacer to improve visibilitys
  
  memo_Salida_Command_gci.Lines.Add('******* ' + rutas[ContadorDirectorios] +
    ' *******');
  Comando := TStringList.Create;

  try
    // Open Powershell
    Comando.Add('C:\Windows\System32\WindowsPowerShell\v1.0\PowerShell.exe "');


    // I add the command line to create a JSON with the contents of the specified directory
    Comando.Add('"gci ' + rutas[ContadorDirectorios] +
      ' -Recurse | ConvertTo-Json"');


    // I add the command line to the process
    JvCreateProcess1.CommandLine := Comando.Text;

    // I run the process
    JvCreateProcess1.run;
    ValorJSON := JvCreateProcess1.ConsoleOutput;

  finally
    begin
      Comando.Free;
    end;
  end;
end;

目录数组定义

rutas: array [0 .. 2] of String = ('C:\Users\operario43\Desktop',
    'C:\Users\operario43\Documents', 'C:\Users\operario43\Pictures');

JvCreateProcess1Terminate事件

procedure TUProbando.JvCreateProcess1Terminate(Sender: TObject;
  ExitCode: Cardinal);
begin
  // Calculate the size of the current directory

// I WANT GET JSON OF PREVIOUS POWER SHELL COMMAND HERE
  SizeDirectory := GetSizeFromJson('JSON HERE', Extensiones);
  

  if checkSizeDirectory(SizeDirectory, SizeControlDirectory) then
  begin
    ShowMessage('This Directory' + rutas[ContadorDirectorios] +
      ' has important files not protected by a backup');
  end;

  // +1 counter of directories traversed
    inc(ContadorDirectorios);
end;

辅助方法

function GetSizeFromJson(JSON: String; vExtensiones: array of string): integer;
var
  
  Contenedor: TJSONArray;
  Jfichero: TJSONObject;
  JNombre: TJSONValue;
  // value of the 'length' element of each element of the JSON
  JSizeFile: TJSONNumber; //
  
  I: integer;
  
  SizeDirectory: Int64;
begin
  SizeDirectory := 0;
  result := -1;
  try
    Contenedor := TJSONObject.ParseJSONValue(JSON) as TJSONArray;
    
    if Contenedor = nil then
    begin
      ShowMessage('Error al parsear el json' + JSON);
      exit;
    end;

    
    for I := 0 to Contenedor.Count - 1 do
    begin

      Jfichero := Contenedor.Items[I] as TJSONObject;
      if Jfichero <> nil then
      begin
        // I extract the name of the element
        JNombre := Jfichero.GetValue('Name');

        // If the extensions of the files in the directory are in the 'Extensions' array
        if MatchStr(ExtractFileExt(JNombre.Value), vExtensiones) then
        begin
          // get the value of the lenght element in bytes
          JSizeFile := Jfichero.GetValue('Length') as TJSONNumber;

          if JSizeFile <> nil then
          begin

            // I add the value of 'leght' of the element to the variable SizeDirectory
            inc(SizeDirectory, JSizeFile.AsInt);
          end; // if JSizeFile <> nil
        end; // if MatchStr(ExtractFileExt(JNombre.Value), vExtensiones)
      end; // if Jfichero <> nil
    end; // for I := 0 to Contenedor.Count - 1

    // I return the value of the size of the directory
    result := SizeDirectory;
  except
    on E: Exception do
      ShowMessage(E.Message);
  end;
end;

// method to find out if the size of the current directory exceeds the recommended size for directories in the variable called SizeControlDirectory
function checkSizeDirectory(vSizeDirectory, vSizeControlDirectory
  : Int64): Boolean;
var
  Contenedor: TJSONArray;
begin
  result := false;

  vSizeDirectory := GetSizeFromJson(Contenedor.ToString, Extensiones);

  if vSizeDirectory > vSizeControlDirectory then
  begin
    ShowMessage('Directory ' + rutas[ContadorDirectorios] +
      ' have files don''t protected by Backup');
  end;

end;

解决方案

你的代码存在几个核心问题,导致无法获取PowerShell输出的JSON,以下是修复步骤:

1. 修复PowerShell命令行格式

当前的命令引号转义错误,PowerShell无法正确解析执行。正确的调用格式应该是:

JvCreateProcess1.CommandLine := 'C:\Windows\System32\WindowsPowerShell\v1.0\PowerShell.exe -Command "Get-ChildItem ' + rutas[ContadorDirectorios] + ' -Recurse | ConvertTo-Json"';

直接用一行拼接命令,避免TStringList换行导致的格式错误。

2. 在进程终止事件中获取输出

进程启动后立刻读取ConsoleOutput是无效的,因为此时进程还在运行。必须在JvCreateProcess1Terminate事件中读取输出,同时确保JvCreateProcess的CaptureConsoleOutput属性已设为True。

修改Timer1Timer方法,移除提前获取输出的无效代码:

procedure TUProbando.Timer1Timer(Sender: TObject);
var
  Comando: TStrings;
begin
  if ContadorDirectorios = Length(rutas) then
  begin
    Timer1.Enabled := false;
    exit;
  end;

  Timer1.Enabled := false;
  Lista.Clear;
  
  memo_Salida_Command_gci.Lines.Add('******* ' + rutas[ContadorDirectorios] + ' *******');
  Comando := TStringList.Create;

  try
    // 修复后的PowerShell命令
    JvCreateProcess1.CommandLine := 'C:\Windows\System32\WindowsPowerShell\v1.0\PowerShell.exe -Command "Get-ChildItem ' + rutas[ContadorDirectorios] + ' -Recurse | ConvertTo-Json"';
    JvCreateProcess1.Run;
  finally
    Comando.Free;
  end;
end;

3. 终止事件中读取JSON并处理

直接在终止事件中读取ConsoleOutput的内容,传入后续方法处理:

procedure TUProbando.JvCreateProcess1Terminate(Sender: TObject;
  ExitCode: Cardinal);
var
  JSONOutput: String;
begin
  // 获取PowerShell输出的JSON
  JSONOutput := JvCreateProcess1.ConsoleOutput.Text;
  
  // 调试用:将输出写入Memo
  memo_Salida_Command_gci.Lines.Add(JSONOutput);

  // 计算目录目标文件总大小
  SizeDirectory := GetSizeFromJson(JSONOutput, Extensiones);
  
  if checkSizeDirectory(SizeDirectory, SizeControlDirectory) then
  begin
    ShowMessage('目录 ' + rutas[ContadorDirectorios] + ' 包含未备份的重要文件');
  end;

  inc(ContadorDirectorios);
  // 启动Timer处理下一个目录
  Timer1.Enabled := true;
end;

4. 修复辅助方法的错误

checkSizeDirectory方法存在未初始化变量的致命错误,修改如下:

function checkSizeDirectory(vSizeDirectory, vSizeControlDirectory: Int64): Boolean;
begin
  result := false;
  if vSizeDirectory > vSizeControlDirectory then
  begin
    ShowMessage('目录 ' + rutas[ContadorDirectorios] + ' 包含未备份的文件');
    result := true;
  end;
end;

同时将GetSizeFromJson的返回类型从integer改为Int64,避免大文件大小溢出:

function GetSizeFromJson(JSON: String; vExtensiones: array of string): Int64;

内容的提问来源于stack exchange,提问作者Yerón Barreiro Martínez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 02:30:39