C# Process调用Python脚本二次执行时savefig报PermissionError问题
C# Process调用Python脚本重复覆盖文件时PermissionError问题
问题描述
通过C#的Process调用Python脚本时,第二次使用相同参数执行脚本会触发权限拒绝错误,该错误与savefig()覆盖已存在的.png文件有关,但直接在终端运行脚本无此问题。
错误堆栈
Traceback (most recent call last):
File (full-path)..\net6.0-windows\MakeGraph.py"
\net6.0-windows\MakeGraph.py", line 26, in savefig\r\n plt.savefig(file)
\site-packages\PIL\Image.py", line 2428, in save
\r\n fp = builtins.open(filename, "w+b")\r\nPermissionError: [Errno 13] Permission denied:
已执行的排查操作
- 将目标文件夹改为Documents(已完成)
- 确认路径存在(路径有效)
- 确认目标路径指向文件(是文件)
- 重启C#项目后可成功覆盖一次,再次执行则报错
- 修改文件名(如"newname.png")可成功创建,但再次执行仍会报权限拒绝
相关代码片段
C# 调用代码
string fileName = csv_input.Text; string folderName = KgBox.Text; ProcessStartInfo PSI = new ProcessStartInfo(); PSI.FileName = @python_exe; PSI.Arguments = string.Format("{0} {1} {2}", sript_py, fileName, folderName); PSI.UseShellExecute = false; PSI.RedirectStandardOutput = true; PSI.RedirectStandardError = true; PSI.CreateNoWindow = true; try { using (Process? p = Process.Start(PSI)) { p.WaitForExit(); status_from_script += p.StandardOutput.ReadToEnd(); status_from_script += p.StandardError.ReadToEnd(); ErrorBox.Text += status_from_script; } }
Python 脚本核心代码
def savefig(dataframe, title): plt.plot(dataframe) plt.xlabel("data point") plt.ylabel("Acceleration (m/s^2)") plt.title(title) y = [1,-30,-60,-90,-120, -150, -180, -210, -240, -270, -300, -330] plt.yticks(y) file = save_path + "\\\\"+ csv_folder + ".png" print(file) plt.savefig(file) plt.close() print("DONE")
解决方案
问题根源是文件被未完全释放的进程或资源占用,以下是针对性解决步骤:
1. 彻底释放Python侧的matplotlib资源
仅调用plt.close()可能无法完全释放图形资源,需改为:
def savefig(dataframe, title): # ... 原有绘图代码 ... file = save_path + "\\\\"+ csv_folder + ".png" print(file) # 使用文件句柄模式保存,确保显式关闭 with open(file, 'wb') as f: plt.savefig(f) plt.close('all') # 关闭所有matplotlib图形实例 print("DONE")
plt.close('all')会清理所有关联的图形对象,避免隐式占用文件句柄。
2. 确保C#侧进程资源完全释放
虽然using块会自动释放进程,但可显式调用Close()和Dispose()确保资源回收:
using (Process? p = Process.Start(PSI)) { p.WaitForExit(); // 先读取输出,再清理进程 string output = p.StandardOutput.ReadToEnd(); string error = p.StandardError.ReadToEnd(); status_from_script += output + error; ErrorBox.Text += status_from_script; // 显式释放进程资源 p.Close(); p.Dispose(); }
同时检查C#项目中是否有其他组件(如图片预览控件)正在占用生成的.png文件,需先解除该引用。
3. 添加文件写入重试机制
针对临时占用的情况,在Python脚本中添加重试逻辑:
import time def savefig(dataframe, title): # ... 原有绘图代码 ... file = save_path + "\\\\"+ csv_folder + ".png" print(file) max_retries = 3 retry_delay = 1 # 等待1秒后重试 success = False for attempt in range(max_retries): try: with open(file, 'wb') as f: plt.savefig(f) success = True break except PermissionError: if attempt < max_retries - 1: time.sleep(retry_delay) else: raise if success: plt.close('all') print("DONE")
内容的提问来源于stack exchange,提问作者Kenneth Køpke
相关产品推荐
相关产品推荐

