欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python集成C#實(shí)現(xiàn)界面操作下載文件功能的全過(guò)程

 更新時(shí)間:2022年03月22日 12:05:31   作者:程序園丁  
使用腳本進(jìn)行下載的需求很常見,下面這篇文章主要給大家介紹了關(guān)于Python集成C#實(shí)現(xiàn)界面操作下載文件功能的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下

〇、寫在前面

你想的沒錯(cuò),Python 和 C# 其實(shí)都可以單獨(dú)實(shí)現(xiàn)我們要實(shí)現(xiàn)的功能,這里筆者只是抱著實(shí)驗(yàn)及學(xué)習(xí)的態(tài)度去解決問(wèn)題。

我是一個(gè) C# 程序員,目前在學(xué)習(xí) Python,對(duì)于 Python 得天獨(dú)厚的膠水語(yǔ)言特性自然是必須要領(lǐng)略一番,于是就有了本文。

學(xué)會(huì)了 Python 調(diào)用 C# 的話,就能做很多想到和想不到的東西,這很有趣,不是嗎?

一、這個(gè)功能是怎么樣的

我很熟悉用 C# & WinForm 的方式開發(fā)界面,現(xiàn)在剛好學(xué)習(xí)了 Python 的網(wǎng)絡(luò)編程的基礎(chǔ)庫(kù) socket,于是我就想到寫一個(gè)程序,思路如下:

  • 程序運(yùn)行時(shí)會(huì)打開一個(gè) WinForm 窗體,窗體上有:
    • 輸入文件下載地址的地址欄
    • 選擇文件保存位置的文件開窗按鈕
    • 當(dāng)前下載狀態(tài)的狀態(tài)區(qū)域
    • 下載按鈕
  • 輸入下載地址,選擇一個(gè)文件保存位置
  • 點(diǎn)擊下載按鈕下載文件,狀態(tài)區(qū)域顯示文件下載狀態(tài),最好能顯示下載進(jìn)度
  • 界面放到 WinForm,下載功能放到 Python

二、WinForm 端功能實(shí)現(xiàn)

WinForm 分為幾部分功能

  • 界面設(shè)計(jì)
  • 提供下載地址的公共屬性
  • 提供文件存儲(chǔ)地址公共屬性
  • 提供用于委托下載事件的委托定義
  • 提供記錄狀態(tài)信息的公共方法
  • 提供更新進(jìn)度信息的公共方法

1. 界面設(shè)計(jì)

首先我們使用 VS 創(chuàng)建一個(gè)類庫(kù)項(xiàng)目

至于為什么沒有使用 .NET 5 或者 .net core,是因?yàn)椋?a href="http://www.dbjr.com.cn/article/241780.htm" target="_blank">Python 調(diào)用 C# 動(dòng)態(tài)鏈接庫(kù)

創(chuàng)建項(xiàng)目后新建窗體

本例中設(shè)計(jì)界面設(shè)計(jì)如下:

2. 方法定義

/// <summary>
/// 當(dāng)前地址
/// </summary>
public string ThisUrl
{
    get
    {
        return textUrl.Text;
    }
}

/// <summary>
/// 當(dāng)前保存路徑
/// </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("請(qǐng)先輸入要下載的文件地址!");
        this.textUrl.Focus();
        return;
    }
    if (string.IsNullOrEmpty(this.textSavePath.Text))
    {
        MessageBox.Show("請(qǐng)先選擇文件要保存的地址!");
        this.textSavePath.Focus();
        return;
    }
    
    // 調(diào)用委托事件
    if(this.DownloadEvent != null)
    {
        this.DownloadEvent.Invoke(this, e);
    }
}

打開選擇保存文件路徑時(shí)候由于會(huì)報(bào)錯(cuò)

在可以調(diào)用OLE之前,必須將當(dāng)前線程設(shè)置為單線程單元(STA)模式,請(qǐng)確保您的Main函數(shù)帶有STAThreadAttribute標(biāo)記

很無(wú)奈,因?yàn)槲覀兊恼{(diào)用方并不是 C# 的 Main 函數(shù),而我目前并不知道 Python 調(diào)用 C# 如何實(shí)現(xiàn)的,所以只能另外想方法,就是把選擇保存文件路徑的開窗單獨(dú)啟一個(gè)線程開發(fā),在子線程上再標(biāo)記 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("請(qǐng)先輸入要下載的文件地址!");
        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); //重點(diǎn)
    importThread.Start();
}

/// <summary>
/// 打開對(duì)話框
/// </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 端功能實(shí)現(xiàn)

Python 中分幾部分功能

  • 程序調(diào)用 .NET 類庫(kù)打開窗體
  • 程序中存在下載指定 URL 文件存儲(chǔ)到指定路徑的函數(shù)定義
  • 程序結(jié)束的函數(shù)定義
  • 把當(dāng)前程序封裝成可運(yùn)行程序(如:Windows 中為封裝成 exe)
import socket
import time
import re

mainapp = None

# 調(diào)用動(dòng)態(tài)鏈接庫(kù)的更新狀態(tài)信息
def LogInfo(text):
    # print(text)
    mainapp.LogInfo(text)
    
# 調(diào)用動(dòng)態(tài)鏈接庫(kù)的更新下載進(jìn)度
def downloadInfo(c, all):
    mainapp.SetProcess(c, all)
    if c == all:
        # LogInfo("下載進(jìn)度 {:.2f}".format(c / all * 100))
        LogInfo("下載完成。")
    # else:
        # LogInfo("下載進(jìn)度 {:.2f}%".format(c / all * 100))

# 監(jiān)聽下載委托事件
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("傳遞參數(shù): {}".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('下載失敗,地址格式存在問(wèn)題!')

# 使用 pythonnet 的方式引入動(dòng)態(tài)鏈接庫(kù)

import clr

# 此處保證動(dòng)態(tài)鏈接庫(kù)文件放在當(dāng)前文件夾中,如果不在應(yīng)該使用這種方式
# clr.AddReference('D:\\Path\\DotNetWithPython')
# clr.AddReference('D:\\Path\\DotNetWithPython.dll')
clr.AddReference('DotNetWithPython')
from DotNetWithPython import *
mainapp = MainForm()
mainapp.DownloadEvent += Download
mainapp.ShowDialog()

四、運(yùn)行效果

五、存在問(wèn)題

功能實(shí)現(xiàn)了,但是存在一個(gè)無(wú)法解決的問(wèn)題,就是當(dāng)文件開始下載后 WinForm 的界面會(huì)卡住,疑似是沒有用現(xiàn)線程打開主窗體的原因,但是不能解釋為什么下載開始的時(shí)候沒有卡頓,有哪位大白指導(dǎo)一下呢?不勝感激!

總結(jié)

到此這篇關(guān)于Python集成C#實(shí)現(xiàn)界面操作下載文件功能的文章就介紹到這了,更多相關(guān)Python界面操作下載文件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python爬蟲利用代理池更換IP的方法步驟

    python爬蟲利用代理池更換IP的方法步驟

    這篇文章主要介紹了python爬蟲利用代理池更換IP的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • python中進(jìn)程間通信詳細(xì)介紹

    python中進(jìn)程間通信詳細(xì)介紹

    大家好,本篇文章主要講的是python中進(jìn)程間通信詳細(xì)介紹,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • python實(shí)現(xiàn)K折交叉驗(yàn)證

    python實(shí)現(xiàn)K折交叉驗(yàn)證

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)K折交叉驗(yàn)證,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • pycharm導(dǎo)入第三方庫(kù)的兩種方法(永不報(bào)錯(cuò))

    pycharm導(dǎo)入第三方庫(kù)的兩種方法(永不報(bào)錯(cuò))

    這篇文章主要介紹了pycharm導(dǎo)入第三方庫(kù)的兩種方法(永不報(bào)錯(cuò)),本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-11-11
  • python paramiko模塊學(xué)習(xí)分享

    python paramiko模塊學(xué)習(xí)分享

    這篇文章主要為大家分享了python paramiko模塊的學(xué)習(xí)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • pytorch實(shí)現(xiàn)Tensor變量之間的轉(zhuǎn)換

    pytorch實(shí)現(xiàn)Tensor變量之間的轉(zhuǎn)換

    今天小編就為大家分享一篇pytorch實(shí)現(xiàn)Tensor變量之間的轉(zhuǎn)換,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-02-02
  • 在Python中輸入一個(gè)以空格為間隔的數(shù)組方法

    在Python中輸入一個(gè)以空格為間隔的數(shù)組方法

    今天小編就為大家分享一篇在Python中輸入一個(gè)以空格為間隔的數(shù)組方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-11-11
  • python實(shí)現(xiàn)旋轉(zhuǎn)和水平翻轉(zhuǎn)的方法

    python實(shí)現(xiàn)旋轉(zhuǎn)和水平翻轉(zhuǎn)的方法

    今天小編就為大家分享一篇python實(shí)現(xiàn)旋轉(zhuǎn)和水平翻轉(zhuǎn)的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-10-10
  • 一文搞懂python異常處理、模塊與包

    一文搞懂python異常處理、模塊與包

    異常就是系統(tǒng)中的錯(cuò)誤,程序是無(wú)法改變和處理的,文中有給大家提到異常處理機(jī)制,模塊與包的相關(guān)知識(shí),通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2021-06-06
  • Python可變參數(shù)*args和**kwargs用法實(shí)例小結(jié)

    Python可變參數(shù)*args和**kwargs用法實(shí)例小結(jié)

    這篇文章主要介紹了Python可變參數(shù)*args和**kwargs用法,結(jié)合實(shí)例形式總結(jié)分析了Python中可變參數(shù)*args和**kwargs的功能、區(qū)別與具體使用技巧,需要的朋友可以參考下
    2018-04-04

最新評(píng)論