如何在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
相关产品推荐
相关产品推荐

