您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關Python集成C#實現界面操作下載文件功能的示例分析的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
我很熟悉用 C# & WinForm 的方式開發界面,現在剛好學習了 Python 的網絡編程的基礎庫 socket,于是我就想到寫一個程序,思路如下:
程序運行時會打開一個 WinForm 窗體,窗體上有:
輸入文件下載地址的地址欄
選擇文件保存位置的文件開窗按鈕
當前下載狀態的狀態區域
下載按鈕
輸入下載地址,選擇一個文件保存位置
點擊下載按鈕下載文件,狀態區域顯示文件下載狀態,最好能顯示下載進度
界面放到 WinForm,下載功能放到 Python
WinForm 分為幾部分功能
界面設計
提供下載地址的公共屬性
提供文件存儲地址公共屬性
提供用于委托下載事件的委托定義
提供記錄狀態信息的公共方法
提供更新進度信息的公共方法
首先我們使用 VS 創建一個類庫項目
至于為什么沒有使用 .NET 5 或者 .net core,是因為:Python 調用 C# 動態鏈接庫
創建項目后新建窗體
本例中設計界面設計如下:
/// <summary> /// 當前地址 /// </summary> public string ThisUrl { get { return textUrl.Text; } } /// <summary> /// 當前保存路徑 /// </summary> public string ThisSavePath { get { return textSavePath.Text; } }
/// <summary> /// 下載事件委托 /// </summary> public event EventHandler DownloadEvent; /// <summary> /// 下載按鈕事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void buttonDownload_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(this.textUrl.Text)) { MessageBox.Show("請先輸入要下載的文件地址!"); this.textUrl.Focus(); return; } if (string.IsNullOrEmpty(this.textSavePath.Text)) { MessageBox.Show("請先選擇文件要保存的地址!"); this.textSavePath.Focus(); return; } // 調用委托事件 if(this.DownloadEvent != null) { this.DownloadEvent.Invoke(this, e); } }
打開選擇保存文件路徑時候由于會報錯
在可以調用OLE之前,必須將當前線程設置為單線程單元(STA)模式,請確保您的Main函數帶有STAThreadAttribute標記
很無奈,因為我們的調用方并不是 C# 的 Main 函數,而我目前并不知道 Python 調用 C# 如何實現的,所以只能另外想方法,就是把選擇保存文件路徑的開窗單獨啟一個線程開發,在子線程上再標記 STA
/// 選擇按鈕事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void buttonSelect_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(this.textUrl.Text)) { MessageBox.Show("請先輸入要下載的文件地址!"); this.textUrl.Focus(); return; } var index = this.textUrl.Text.LastIndexOf("/"); var fileName = this.textUrl.Text.Substring(index + 1); Thread importThread = new Thread(() => { var text = OpenDialog(fileName); MessageEvent(text); }); importThread.SetApartmentState(ApartmentState.STA); //重點 importThread.Start(); } /// <summary> /// 打開對話框 /// </summary> private string OpenDialog(string fileName) { var saveFileDialog = new SaveFileDialog(); saveFileDialog.Filter = "所有文件 (*.*)|*.*"; saveFileDialog.FilterIndex = 0; if (!string.IsNullOrEmpty(fileName)) { saveFileDialog.FileName = Path.Combine(saveFileDialog.FileName, fileName); } DialogResult dialogResult = saveFileDialog.ShowDialog(); if (dialogResult == DialogResult.OK) { return saveFileDialog.FileName; } return String.Empty; }
Python 中分幾部分功能
程序調用 .NET 類庫打開窗體
程序中存在下載指定 URL 文件存儲到指定路徑的函數定義
程序結束的函數定義
把當前程序封裝成可運行程序(如:Windows 中為封裝成 exe)
import socket import time import re mainapp = None # 調用動態鏈接庫的更新狀態信息 def LogInfo(text): # print(text) mainapp.LogInfo(text) # 調用動態鏈接庫的更新下載進度 def downloadInfo(c, all): mainapp.SetProcess(c, all) if c == all: # LogInfo("下載進度 {:.2f}".format(c / all * 100)) LogInfo("下載完成。") # else: # LogInfo("下載進度 {:.2f}%".format(c / all * 100)) # 監聽下載委托事件 def Download(source, args): thisurl = source.ThisUrl.lower() thispath = source.ThisSavePath LogInfo("下載地址是: {}".format(thisurl)) LogInfo("保存路徑為: {}".format(thispath)) reobj = re.compile(r"""(?xi)\A [a-z][a-z0-9+\-.]*:// # Scheme ([a-z0-9\-._~%!$&'()*+,;=]+@)? # User ([a-z0-9\-._~%]+ # Named or IPv4 host |\[[a-z0-9\-._~%!$&'()*+,;=:]+\]) # IPv6+ host """) match = reobj.search(thisurl) if match: HOST = match.group(2) PORT = 443 if thisurl.startswith('https') else 80 mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) mysock.connect((HOST, PORT)) urlend = 'GET {} HTTP/1.0\r\n\r\n'.format(thisurl).encode() # LogInfo("傳遞參數: {}".format(urlend)) LogInfo("開始下載……") mysock.sendall(urlend) count = 0 picture = b"" hearlength = 0 filelength = 0 hearc = b"" while True: data = mysock.recv(5120) if (len(data) < 1): break time.sleep(0.1) count = count + len(data) picture = picture + data # print(len(data), count) if hearlength == 0: hearlength = picture.find(b"\r\n\r\n") if hearlength > 0: hearc = picture[:hearlength].decode() # print(hearc) sear = re.search('Content-Length: ([0-9]+)', hearc) if sear: filelength = int(sear.groups()[0]) downloadInfo(count - 4 - hearlength, filelength) else: downloadInfo(count - 4 - hearlength, filelength) mysock.close() # Skip past the header and save the picture data picture = picture[hearlength+4:] fhand = open(thispath, "wb") fhand.write(picture) fhand.close() # Code: http://www.py4e.com/code3/urljpeg.py # Or select Download from this trinket's left-hand menu else: LogInfo('下載失敗,地址格式存在問題!') # 使用 pythonnet 的方式引入動態鏈接庫 import clr # 此處保證動態鏈接庫文件放在當前文件夾中,如果不在應該使用這種方式 # clr.AddReference('D:\\Path\\DotNetWithPython') # clr.AddReference('D:\\Path\\DotNetWithPython.dll') clr.AddReference('DotNetWithPython') from DotNetWithPython import * mainapp = MainForm() mainapp.DownloadEvent += Download mainapp.ShowDialog()
功能實現了,但是存在一個無法解決的問題,就是當文件開始下載后 WinForm 的界面會卡住,疑似是沒有用現線程打開主窗體的原因,但是不能解釋為什么下載開始的時候沒有卡頓,有哪位大白指導一下呢?不勝感激!
感謝各位的閱讀!關于“Python集成C#實現界面操作下載文件功能的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。