C#調(diào)用python.exe使用arcpy方式
背景
環(huán)境:ArcGis10.2.2。C#開(kāi)發(fā)程序一直以來(lái)以調(diào)用Desktop的python環(huán)境(32位)來(lái)做數(shù)據(jù)處理分析。但是數(shù)據(jù)量大時(shí),出現(xiàn)了內(nèi)存資源不夠的情況。因此決定換成使用64位python環(huán)境。
遇到問(wèn)題
C#通過(guò)Process.Start()去調(diào)用64位python.exe,在Debug模式下毫無(wú)問(wèn)題,但是直接運(yùn)行exe就報(bào)錯(cuò)Process finished with exit code -1073741819 (0xC0000005)。指向異常。
分析問(wèn)題
后來(lái)發(fā)現(xiàn)是由于arcpy模塊導(dǎo)致的,去掉這個(gè)模塊的內(nèi)容就能運(yùn)行,import arcpy就運(yùn)行不起來(lái)。既然使用arcpy做數(shù)據(jù)處理,如果連import arcpy都不行,那還做個(gè)屁啊。于是開(kāi)始尋找程序Debug模式下和Run模式下的區(qū)別。
程序中使用ProcessStartInfo類啟動(dòng)的python.exe的進(jìn)程,那問(wèn)題基本就出自這里了。附上檢測(cè)代碼:
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)) { var a = start.Environment; var b = a.Keys.ToList(); b.Sort(); var sss = ""; foreach (var it in b) { sss = $"{sss}\n{it}------->{a[it]}"; } sss = sss.Trim(); using (StreamReader reader = process.StandardOutput) { var sResult = ""; while (!reader.EndOfStream) { sResult = $"{sResult} \n {reader.ReadLine()}"; } sResult = sResult.Trim(); MessageBox.Show(sResult); } MessageBox.Show("ExitCode is " + process.ExitCode); }
于是就對(duì)比了Debug模式下與Run模式下的進(jìn)程環(huán)境變量。
明顯可見(jiàn)兩個(gè)環(huán)境的__COMPAT_LAYER值就是不一樣的。查了一下__COMPAT_LAYER是版本兼容相關(guān)參數(shù),由于我是32位程序調(diào)用64位python.exe,因此懷疑是這個(gè)參數(shù)導(dǎo)致的問(wèn)題。RunAsAdmin是以管理員運(yùn)行,而Installer的解釋是安裝工具。
解決問(wèn)題
上面分析出可能是__COMPAT_LAYER值不同才導(dǎo)致的問(wèn)題,那么就能對(duì)癥下藥了,現(xiàn)在把Run下的值也設(shè)置為RunAsAdmin。加上下例代碼:
start.EnvironmentVariables["__COMPAT_LAYER"] = "RunAsAdmin";
start.Environment["__COMPAT_LAYER"] = "RunAsAdmin";
再次運(yùn)行,居然成功了。
下面附上C#調(diào)用64為Python.exe處理腳本代碼:
/// <summary> /// 執(zhí)行Python腳本 /// </summary> /// <param name="sScriptPath">腳本路徑</param> /// <param name="lstParam">參數(shù)列表</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 = @"E:\ArcGIS\Python27\ArcGISx6410.2\python.exe"; var sParam = $"{sScriptPath}"; if (null != lstParam && 0 < lstParam.Count) { var sArgument = "\"" + string.Join("\" \"", lstParam) + "\""; sParam = $"\"{sParam}\" {sArgument}"; } var start = new ProcessStartInfo { WorkingDirectory = Environment.CurrentDirectory, FileName = sInterpreterPath, UseShellExecute = false, ErrorDialog = true, CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardInput = true, Arguments = sParam }; start.EnvironmentVariables["__COMPAT_LAYER"] = "RunAsAdmin"; start.Environment["__COMPAT_LAYER"] = "RunAsAdmin"; using (Process process = Process.Start(start)) { using (StreamReader reader = process.StandardOutput) { var sResult = ""; while (!reader.EndOfStream) { sResult = $"{sResult} \n {reader.ReadLine()}"; } sResult = sResult.Trim(); MessageBox.Show(sResult); } MessageBox.Show("ExitCode is " + process.ExitCode); } } catch (Exception ex) { MessageBox.Show(ex.ToString()); } return bResult; }
補(bǔ)充知識(shí):C#從注冊(cè)表中獲取ArcPy的python.exe安裝位置
為何要獲取該位置?
在C#中調(diào)用命令執(zhí)行Python腳本的時(shí)候,Python解釋器是必不可少的工具。ArcGIS 10.2.2安裝時(shí)默認(rèn)安裝Python,但不同用戶可能將Python安裝到不同位置,比如,本人就將其安裝到D盤而非默認(rèn)的C盤。
那么,當(dāng)我們的系統(tǒng)給其他用戶使用時(shí),勢(shì)必需要找到Python解釋器即python.exe文件位置,才能正常執(zhí)行工具調(diào)用。
當(dāng)然,你可以將文件位置寫入到環(huán)境變量,這位就無(wú)需獲取全路徑了。本文不考慮此種情形。
如何獲取該位置?
對(duì)比多臺(tái)電腦發(fā)現(xiàn),Python安裝后,會(huì)在注冊(cè)表中位置“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components”下自動(dòng)創(chuàng)建一個(gè)鍵“9A6767D28A88AEB44AD0AE3AA51002C0”。
該鍵下有一個(gè)值,對(duì)應(yīng)的數(shù)據(jù)即為python.exe的完整路徑。我們只需要讀到這個(gè)數(shù)據(jù),即可獲取python.exe位置。
C#代碼如下:
/// <summary> /// Python.exe路徑在注冊(cè)表中的安裝位置(安裝ArcGIS自帶Python環(huán)境時(shí)自動(dòng)創(chuàng)建) /// </summary> private static readonly string RegistryPythonDefaultKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\"; /// <summary> /// Python.exe路徑在注冊(cè)表中的鍵名(安裝ArcGIS自帶Python環(huán)境時(shí)自動(dòng)創(chuàng)建) /// </summary> private static readonly string RegistryPythonTargetKey = "9A6767D28A88AEB44AD0AE3AA51002C0"; /// <summary> /// 獲取Python.exe安裝路徑 /// </summary> /// <returns></returns> private static string GetPythonPath() { var sPythonPath = ""; try { var registryKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32); //判斷機(jī)器位數(shù) var targetSubKey = registryKey.OpenSubKey(Path.Combine(RegistryPythonDefaultKey, RegistryPythonTargetKey)); var lstName = targetSubKey.GetValueNames(); foreach (var sName in lstName) { var sValue = targetSubKey.GetValue(sName) + string.Empty; if (!sValue.EndsWith("python.exe", StringComparison.OrdinalIgnoreCase) || !File.Exists(sValue)) { continue; } sPythonPath = sValue; break; } } catch (Exception ex) { SysConfig.Model.LogServices.WriteExceptionLog(ex, "GetPythonPath"); } return sPythonPath; }
需要注意的地方?
打開(kāi)注冊(cè)表的時(shí)候,需要判斷機(jī)器位數(shù),32位與64位注冊(cè)表位置有所差異,如下:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components
以上這篇C#調(diào)用python.exe使用arcpy方式就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
C#使用Dynamic實(shí)現(xiàn)簡(jiǎn)化反射
這篇文章主要為大家詳細(xì)介紹了C#如何使用Dynamic來(lái)實(shí)現(xiàn)簡(jiǎn)化反射,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解一下2023-07-07c#實(shí)現(xiàn)網(wǎng)站監(jiān)控查看是否正常示例
這篇文章主要介紹了使用c#監(jiān)控網(wǎng)站是否正常的功能示例,大家參考使用吧2014-01-01C#中實(shí)現(xiàn)線程同步lock關(guān)鍵字的用法詳解
實(shí)現(xiàn)線程同步的第一種方式是我們經(jīng)常使用的lock關(guān)鍵字,它將包圍的語(yǔ)句塊標(biāo)記為臨界區(qū),這樣一次只有一個(gè)線程進(jìn)入臨界區(qū)并執(zhí)行代碼,接下來(lái)通過(guò)本文給大家介紹C#中實(shí)現(xiàn)線程同步lock關(guān)鍵字的用法詳解,一起看看吧2016-07-07C#使用StreamReader和StreamWriter類讀寫操作文件
這篇文章介紹了C#使用StreamReader和StreamWriter類讀寫操作文件的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05WinForm使用DecExpress控件中的ChartControl插件繪制圖表
這篇文章介紹了WinForm使用DecExpress控件中的ChartControl插件繪制圖表的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05C#實(shí)現(xiàn)字符串進(jìn)制轉(zhuǎn)換方法匯總
這篇文章主要介紹了C#實(shí)現(xiàn)字符串進(jìn)制轉(zhuǎn)換方法匯總,給大家羅列了十幾種機(jī)制轉(zhuǎn)換問(wèn)題,感興趣的朋友跟隨小編一起看看吧2022-11-11