中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python集成C#實現界面操作下載文件功能的示例分析

發布時間:2022-03-22 15:04:18 來源:億速云 閱讀:173 作者:小新 欄目:開發技術

這篇文章給大家分享的是有關Python集成C#實現界面操作下載文件功能的示例分析的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

一、這個功能是怎么樣的

我很熟悉用 C# & WinForm 的方式開發界面,現在剛好學習了 Python 的網絡編程的基礎庫 socket,于是我就想到寫一個程序,思路如下:

  • 程序運行時會打開一個 WinForm 窗體,窗體上有:

    • 輸入文件下載地址的地址欄

    • 選擇文件保存位置的文件開窗按鈕

    • 當前下載狀態的狀態區域

    • 下載按鈕

  • 輸入下載地址,選擇一個文件保存位置

  • 點擊下載按鈕下載文件,狀態區域顯示文件下載狀態,最好能顯示下載進度

  • 界面放到 WinForm,下載功能放到 Python

二、WinForm 端功能實現

WinForm 分為幾部分功能

  • 界面設計

  • 提供下載地址的公共屬性

  • 提供文件存儲地址公共屬性

  • 提供用于委托下載事件的委托定義

  • 提供記錄狀態信息的公共方法

  • 提供更新進度信息的公共方法

1. 界面設計

首先我們使用 VS 創建一個類庫項目

Python集成C#實現界面操作下載文件功能的示例分析

至于為什么沒有使用 .NET 5 或者 .net core,是因為:Python 調用 C# 動態鏈接庫

Python集成C#實現界面操作下載文件功能的示例分析

創建項目后新建窗體

Python集成C#實現界面操作下載文件功能的示例分析

本例中設計界面設計如下:

Python集成C#實現界面操作下載文件功能的示例分析

2. 方法定義

/// <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 端功能實現

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()

四、運行效果

Python集成C#實現界面操作下載文件功能的示例分析

Python集成C#實現界面操作下載文件功能的示例分析

五、存在問題

功能實現了,但是存在一個無法解決的問題,就是當文件開始下載后 WinForm 的界面會卡住,疑似是沒有用現線程打開主窗體的原因,但是不能解釋為什么下載開始的時候沒有卡頓,有哪位大白指導一下呢?不勝感激!

Python集成C#實現界面操作下載文件功能的示例分析

感謝各位的閱讀!關于“Python集成C#實現界面操作下載文件功能的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

金门县| 柳州市| 浦县| 疏附县| 杭州市| 南昌县| 东辽县| 枣强县| 紫阳县| 微山县| 汉川市| 吉林省| 无极县| 衡阳市| 锡林浩特市| 曲松县| 太谷县| 颍上县| 亳州市| 芮城县| 晋宁县| 日土县| 繁峙县| 喀喇沁旗| 缙云县| 武城县| 凤冈县| 理塘县| 新龙县| 沅江市| 高邮市| 孟州市| 赤峰市| 体育| 玛多县| 洪江市| 广东省| 昔阳县| 白河县| 丰台区| 柘荣县|