引言
Python是处理数据的良好工具。在做ArcGIS Engine开发时,需要数据处理的情形挺多,在数据量相对较大时,在Python中先编写和测试好数据处理的代码,再到C++、C#、Java等开发语言环境中调用,是一种可行的解决方案。
那么,Python脚本到底如何被其他语言调用呢,或者说,两者是如何交互的呢?本文尝试以C#语言和ArcPy进行试验和说明。
编写Python脚本
调用约定
本文的开发背景是某数据质检项目实践。项目需求是按不同的质检规则去检查GIS数据。部分规则的检查过程中,需要进行数据的空间位置进行必要运算,生成中间图层与结果图层,通过一系列预处理过程,达到识别质检结果的目的。
- 每一条质检规则都有相应的编码,该编码是唯一的。因此,我们的Python脚本文件便以规则编码进行命名,统一放置在程序的指定目录下,以便识别和区分。如“…\Scripts\Rules\B006G001.py”。
- 脚本包含中文字符,约定使用GBK字符集。
- 规则正常执行结束时,输出一行文本,内容为数字“1”,表示成功,其他情况下可输出必要的过程信息,不作为判断成功依据。
代码编写
在PyCharm中编写数据处理代码,调试通过。
参数传递
通过字符串集合传递参数,将所有参数一一对应到Python脚本接收到的参数中即可。
脚本封装
添加必要的注释,使用main方法,捕捉异常等。具体的代码,不在本篇中给出。
编写C#调用方法
封装了三个方法,如下:
/// <summary>
/// 执行规则
/// </summary>
/// <param name="sRuleCode">规则编码(如:B002G026)</param>
/// <param name="lstParam">参数集合</param>
/// <returns>是否成功</returns>
public bool RunRule(string sRuleCode, List<string> lstParam) => RunScript(GetRulePathByCode(sRuleCode), lstParam);
/// <summary>
/// 通过规则编码找到规则文件(同名,不带扩展名)
/// </summary>
/// <param name="sRuleCode">规则编码(如:B002G026)</param>
/// <returns>全路径(不判断文件存在性)</returns>
private string GetRulePathByCode(string sRuleCode) => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Scripts", @"Rules", $"{sRuleCode}.py");
/// <summary>
/// 执行Python脚本
/// 约定:Python脚本中最后一行打印一个大于等于0的数字,表示成功
/// </summary>
/// <param name="sScriptPath">脚本路径</param>
/// <param name="lstParam">参数列表</param>
/// <returns>是否成功</returns>
public bool RunScript(string sScriptPath, List<string> lstParam)
{
var bResult = false;
try
{
if (!File.Exists(sScriptPath))
throw new Exception($"文件{sScriptPath}不存在!");
var sInterpreterPath= PythonConfigManager.ConfigValueOfInterpreter; //Python解释器路径
var sParam = $"{sScriptPath}";
if (null != lstParam && 0 < lstParam.Count)
{
var sArgument = "\"" + string.Join("\" \"", lstParam) + "\"";
sParam = $"\"{sParam}\" {sArgument}";
}
LogServices.WriteInfoLog(sParam);
var start = new ProcessStartInfo
{
WorkingDirectory = Environment.CurrentDirectory,
FileName = sInterpreterPath,
UseShellExecute = false,
ErrorDialog = true,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardInput = true,
Arguments = sParam
};
using (Process process = Process.Start(start))
{
using (StreamReader reader = process.StandardOutput)
{
var sResult = "";
while (!reader.EndOfStream)
{
sResult = reader.ReadLine();
if (!string.IsNullOrEmpty(sResult))
{
LogServices.WriteInfoLog(sResult);
}
}
sResult = sResult.Trim();
if (!string.IsNullOrEmpty(sResult) && int.TryParse(sResult, out int nCode) && nCode >= 0)
{
bResult = true;
}
}
}
}
catch (Exception ex)
{
LogServices.WriteExceptionLog(ex, "Python脚本执行异常");
}
return bResult;
}
优化
- 在Python出输出必要的进度信息,并约定好相应格式规范
- 在C#中不断获取Python脚本输出,判断进度
- 使用cmd.exe来执行python.exe