<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
你想的沒錯,Python 和 C# 其實都可以單獨實現我們要實現的功能,這裡筆者只是抱著實驗及學習的態度去解決問題。
我是一個 C# 程式設計師,目前在學習 Python,對於 Python 得天獨厚的膠水語言特性自然是必須要領略一番,於是就有了本文。
學會了 Python 呼叫 C# 的話,就能做很多想到和想不到的東西,這很有趣,不是嗎?
我很熟悉用 C# & WinForm 的方式開發介面,現在剛好學習了 Python 的網路程式設計的基礎庫 socket,於是我就想到寫一個程式,思路如下:
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 中分幾部分功能
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.0rnrn'.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"rnrn") 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#實現介面操作下載檔案功能的文章就介紹到這了,更多相關Python介面操作下載檔案內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45