{"id":106965,"date":"2026-09-18T17:33:52","date_gmt":"2026-09-18T09:33:52","guid":{"rendered":"https:\/\/www.wsisp.com\/helps\/106965.html"},"modified":"2026-09-18T17:33:52","modified_gmt":"2026-09-18T09:33:52","slug":"pyqt-%e5%ae%9e%e7%8e%b0ftp%e5%ae%a2%e6%88%b7%e7%ab%af%e8%b0%83%e8%af%95%e5%8a%a9%e6%89%8b%e6%ba%90%e7%a0%81%e5%88%86%e4%ba%ab","status":"publish","type":"post","link":"https:\/\/www.wsisp.com\/helps\/106965.html","title":{"rendered":"PyQt \u5b9e\u73b0FTP\u5ba2\u6237\u7aef\u8c03\u8bd5\u52a9\u624b\u6e90\u7801\u5206\u4eab"},"content":{"rendered":"<p><img decoding=\"async\" src=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/09\/20260918093346-6aad057aa3dce.png\" alt=\"\u5728\u8fd9\u91cc\u63d2\u5165\u56fe\u7247\u63cf\u8ff0\" \/><\/p>\n<\/p>\n<h4>PyQt \u5b9e\u73b0FTP\u5ba2\u6237\u7aef\u8c03\u8bd5\u52a9\u624b\u6e90\u7801\u5206\u4eab<\/h4>\n<ul>\n<li>\u4e00\u3001\u6548\u679c\u5c55\u793a<\/li>\n<li>\u4e8c\u3001\u6e90\u7801\u5206\u4eab<\/li>\n<li>\n<ul>\n<li>1\u3001\u5de5\u7a0b\u7ed3\u6784<\/li>\n<li>2\u3001\u5e93\u5b89\u88c5<\/li>\n<li>3\u3001main.py<\/li>\n<li>4\u3001ftp_server_test.py&#xff08;\u6d4b\u8bd5\u4f7f\u7528&#xff09;<\/li>\n<\/ul>\n<\/li>\n<li>\u4e09\u3001\u5b9e\u73b0\u539f\u7406<\/li>\n<li>\n<ul>\n<li>1\u3001\u534f\u8bae\u62e6\u622a&#xff1a;\u7ee7\u627f FTP \u91cd\u5199 putline \/ getline<\/li>\n<li>2\u3001\u7ebf\u7a0b\u6a21\u578b&#xff1a;QThread &#043; \u4efb\u52a1\u961f\u5217<\/li>\n<li>\n<ul>\n<li>2.1 \u4efb\u52a1\u961f\u5217<\/li>\n<li>2.2 \u7ebf\u7a0b\u5b89\u5168<\/li>\n<\/ul>\n<\/li>\n<li>3\u3001\u4fe1\u53f7\u69fd\u901a\u4fe1&#xff1a;FtpSignals<\/li>\n<li>4\u3001\u76ee\u5f55\u5217\u8868\u89e3\u6790&#xff1a;MLSD \u4f18\u5148&#xff0c;LIST \u515c\u5e95<\/li>\n<li>5\u3001\u4e0a\u4f20\/\u4e0b\u8f7d\u8fdb\u5ea6\u8ddf\u8e2a<\/li>\n<li>\n<ul>\n<li>5.1 \u4e0a\u4f20&#xff1a;\u5305\u88c5\u6587\u4ef6\u5bf9\u8c61<\/li>\n<li>5.2 \u4e0b\u8f7d&#xff1a;\u56de\u8c03\u51fd\u6570<\/li>\n<\/ul>\n<\/li>\n<li>6\u3001\u539f\u59cb\u547d\u4ee4\u6267\u884c<\/li>\n<li>7\u3001\u6574\u4f53\u6570\u636e\u6d41<\/li>\n<li>8\u3001\u5c0f\u7ed3<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>\u4e00\u3001\u6548\u679c\u5c55\u793a<\/h2>\n<p><img decoding=\"async\" src=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/09\/20260918093349-6aad057dc6054.png\" alt=\"\u5728\u8fd9\u91cc\u63d2\u5165\u56fe\u7247\u63cf\u8ff0\" \/> <img decoding=\"async\" src=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/09\/20260918093350-6aad057e4918a.png\" alt=\"\u5728\u8fd9\u91cc\u63d2\u5165\u56fe\u7247\u63cf\u8ff0\" \/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/09\/20260918093350-6aad057ec0679.png\" alt=\"\u5728\u8fd9\u91cc\u63d2\u5165\u56fe\u7247\u63cf\u8ff0\" \/><\/p>\n<h2>\u4e8c\u3001\u6e90\u7801\u5206\u4eab<\/h2>\n<h3>1\u3001\u5de5\u7a0b\u7ed3\u6784<\/h3>\n<p><img decoding=\"async\" src=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/09\/20260918093351-6aad057f1388f.png\" alt=\"\u5728\u8fd9\u91cc\u63d2\u5165\u56fe\u7247\u63cf\u8ff0\" \/><\/p>\n<h3>2\u3001\u5e93\u5b89\u88c5<\/h3>\n<p><img decoding=\"async\" src=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/09\/20260918093351-6aad057f2dd83.png\" alt=\"\u5728\u8fd9\u91cc\u63d2\u5165\u56fe\u7247\u63cf\u8ff0\" \/><\/p>\n<h3>3\u3001main.py<\/h3>\n<p><span class=\"token triple-quoted-string string\">&#034;&#034;&#034;<br \/>\n\u529f\u80fd&#xff1a;<br \/>\n  &#8211; \u8fde\u63a5\/\u65ad\u5f00 FTP \u670d\u52a1\u5668<br \/>\n  &#8211; \u672c\u5730\/\u8fdc\u7a0b\u53cc\u680f\u6587\u4ef6\u6d4f\u89c8\u5668<br \/>\n  &#8211; \u6587\u4ef6\u4e0a\u4f20\/\u4e0b\u8f7d&#xff08;\u5e26\u8fdb\u5ea6&#xff09;<br \/>\n  &#8211; \u8c03\u8bd5\u63a7\u5236\u53f0&#xff1a;\u5b9e\u65f6 FTP \u547d\u4ee4\/\u54cd\u5e94\u65e5\u5fd7 &#043; \u624b\u52a8\u53d1\u9001\u539f\u59cb\u547d\u4ee4<br \/>\n&#034;&#034;&#034;<\/span><\/p>\n<p><span class=\"token keyword\">import<\/span> os<br \/>\n<span class=\"token keyword\">import<\/span> sys<br \/>\n<span class=\"token keyword\">import<\/span> threading<br \/>\n<span class=\"token keyword\">import<\/span> time<br \/>\n<span class=\"token keyword\">from<\/span> datetime <span class=\"token keyword\">import<\/span> datetime<br \/>\n<span class=\"token keyword\">from<\/span> ftplib <span class=\"token keyword\">import<\/span> FTP<span class=\"token punctuation\">,<\/span> error_perm<\/p>\n<p><span class=\"token keyword\">from<\/span> PyQt6<span class=\"token punctuation\">.<\/span>QtCore <span class=\"token keyword\">import<\/span> <span class=\"token punctuation\">(<\/span><br \/>\n    Qt<span class=\"token punctuation\">,<\/span> QThread<span class=\"token punctuation\">,<\/span> pyqtSignal<span class=\"token punctuation\">,<\/span> QObject<span class=\"token punctuation\">,<\/span> QSettings<br \/>\n<span class=\"token punctuation\">)<\/span><br \/>\n<span class=\"token keyword\">from<\/span> PyQt6<span class=\"token punctuation\">.<\/span>QtGui <span class=\"token keyword\">import<\/span> <span class=\"token punctuation\">(<\/span><br \/>\n    QFont<span class=\"token punctuation\">,<\/span> QColor<span class=\"token punctuation\">,<\/span> QPalette<br \/>\n<span class=\"token punctuation\">)<\/span><br \/>\n<span class=\"token keyword\">from<\/span> PyQt6<span class=\"token punctuation\">.<\/span>QtWidgets <span class=\"token keyword\">import<\/span> <span class=\"token punctuation\">(<\/span><br \/>\n    QApplication<span class=\"token punctuation\">,<\/span> QMainWindow<span class=\"token punctuation\">,<\/span> QWidget<span class=\"token punctuation\">,<\/span> QVBoxLayout<span class=\"token punctuation\">,<\/span> QHBoxLayout<span class=\"token punctuation\">,<\/span><br \/>\n    QGridLayout<span class=\"token punctuation\">,<\/span> QGroupBox<span class=\"token punctuation\">,<\/span> QLabel<span class=\"token punctuation\">,<\/span> QLineEdit<span class=\"token punctuation\">,<\/span> QPushButton<span class=\"token punctuation\">,<\/span><br \/>\n    QTreeWidget<span class=\"token punctuation\">,<\/span> QTreeWidgetItem<span class=\"token punctuation\">,<\/span> QHeaderView<span class=\"token punctuation\">,<\/span> QTextEdit<span class=\"token punctuation\">,<\/span><br \/>\n    QSplitter<span class=\"token punctuation\">,<\/span> QProgressBar<span class=\"token punctuation\">,<\/span> QFileDialog<span class=\"token punctuation\">,<\/span> QMessageBox<span class=\"token punctuation\">,<\/span><br \/>\n    QStatusBar<span class=\"token punctuation\">,<\/span> QToolBar<span class=\"token punctuation\">,<\/span> QMenu<span class=\"token punctuation\">,<\/span> QAbstractItemView<span class=\"token punctuation\">,<\/span> QComboBox<br \/>\n<span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token comment\"># &#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;<\/span><br \/>\n<span class=\"token comment\">#  \u8c03\u8bd5 FTP \u5ba2\u6237\u7aef &#8211; \u62e6\u622a\u6240\u6709\u547d\u4ee4\u548c\u54cd\u5e94<\/span><br \/>\n<span class=\"token comment\"># &#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;<\/span><br \/>\n<span class=\"token keyword\">class<\/span> <span class=\"token class-name\">DebugFTP<\/span><span class=\"token punctuation\">(<\/span>FTP<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u7ee7\u627f ftplib.FTP&#xff0c;\u91cd\u5199 putline\/getline \u4ee5\u6355\u83b7\u6240\u6709\u534f\u8bae\u4ea4\u4e92&#034;&#034;&#034;<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">__init__<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> <span class=\"token operator\">*<\/span>args<span class=\"token punctuation\">,<\/span> log_callback<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">None<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token operator\">**<\/span>kwargs<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_log_callback <span class=\"token operator\">&#061;<\/span> log_callback<br \/>\n        <span class=\"token builtin\">super<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>__init__<span class=\"token punctuation\">(<\/span><span class=\"token operator\">*<\/span>args<span class=\"token punctuation\">,<\/span> <span class=\"token operator\">**<\/span>kwargs<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">putline<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> line<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> self<span class=\"token punctuation\">.<\/span>_log_callback<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>_log_callback<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;cmd&#034;<\/span><span class=\"token punctuation\">,<\/span> line<span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token builtin\">super<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>putline<span class=\"token punctuation\">(<\/span>line<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">getline<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        line <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">super<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>getline<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> self<span class=\"token punctuation\">.<\/span>_log_callback<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>_log_callback<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;resp&#034;<\/span><span class=\"token punctuation\">,<\/span> line<span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">return<\/span> line<\/p>\n<p><span class=\"token comment\"># &#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;<\/span><br \/>\n<span class=\"token comment\">#  FTP \u4fe1\u53f7\u5b9a\u4e49<\/span><br \/>\n<span class=\"token comment\"># &#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;<\/span><br \/>\n<span class=\"token keyword\">class<\/span> <span class=\"token class-name\">FtpSignals<\/span><span class=\"token punctuation\">(<\/span>QObject<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    log_message <span class=\"token operator\">&#061;<\/span> pyqtSignal<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">str<\/span><span class=\"token punctuation\">)<\/span>           <span class=\"token comment\"># (\u7c7b\u522b, \u6d88\u606f) \u7c7b\u522b: cmd\/resp\/info\/error\/success<\/span><br \/>\n    file_list_received <span class=\"token operator\">&#061;<\/span> pyqtSignal<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">list<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">str<\/span><span class=\"token punctuation\">)<\/span>    <span class=\"token comment\"># (\u6587\u4ef6\u5217\u8868, \u5f53\u524d\u8def\u5f84)<\/span><br \/>\n    transfer_progress <span class=\"token operator\">&#061;<\/span> pyqtSignal<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">int<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">int<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token comment\"># (\u6587\u4ef6\u540d, \u5df2\u4f20\u8f93, \u603b\u5927\u5c0f)<\/span><br \/>\n    transfer_complete <span class=\"token operator\">&#061;<\/span> pyqtSignal<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">bool<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">str<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token comment\"># (\u6587\u4ef6\u540d, \u6210\u529f, \u6d88\u606f)<\/span><br \/>\n    connection_changed <span class=\"token operator\">&#061;<\/span> pyqtSignal<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">bool<\/span><span class=\"token punctuation\">)<\/span>         <span class=\"token comment\"># \u8fde\u63a5\u72b6\u6001<\/span><br \/>\n    raw_command_result <span class=\"token operator\">&#061;<\/span> pyqtSignal<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">)<\/span>          <span class=\"token comment\"># \u539f\u59cb\u547d\u4ee4\u6267\u884c\u7ed3\u679c<\/span><\/p>\n<p><span class=\"token comment\"># &#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;<\/span><br \/>\n<span class=\"token comment\">#  FTP \u5de5\u4f5c\u7ebf\u7a0b<\/span><br \/>\n<span class=\"token comment\"># &#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;<\/span><br \/>\n<span class=\"token keyword\">class<\/span> <span class=\"token class-name\">FtpWorkerThread<\/span><span class=\"token punctuation\">(<\/span>QThread<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u5728\u540e\u53f0\u7ebf\u7a0b\u6267\u884c\u6240\u6709 FTP \u64cd\u4f5c&#034;&#034;&#034;<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">__init__<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> parent<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">None<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token builtin\">super<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>__init__<span class=\"token punctuation\">(<\/span>parent<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>signals <span class=\"token operator\">&#061;<\/span> FtpSignals<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>ftp <span class=\"token operator\">&#061;<\/span> <span class=\"token boolean\">None<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_connected <span class=\"token operator\">&#061;<\/span> <span class=\"token boolean\">False<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_stop_flag <span class=\"token operator\">&#061;<\/span> <span class=\"token boolean\">False<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_task_queue <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_lock <span class=\"token operator\">&#061;<\/span> threading<span class=\"token punctuation\">.<\/span>Lock<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">connect_to_server<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> host<span class=\"token punctuation\">,<\/span> port<span class=\"token punctuation\">,<\/span> user<span class=\"token punctuation\">,<\/span> password<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u6dfb\u52a0\u8fde\u63a5\u4efb\u52a1&#034;&#034;&#034;<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_enqueue<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;connect&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n            <span class=\"token string\">&#034;host&#034;<\/span><span class=\"token punctuation\">:<\/span> host<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;port&#034;<\/span><span class=\"token punctuation\">:<\/span> port<span class=\"token punctuation\">,<\/span><br \/>\n            <span class=\"token string\">&#034;user&#034;<\/span><span class=\"token punctuation\">:<\/span> user<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;password&#034;<\/span><span class=\"token punctuation\">:<\/span> password<br \/>\n        <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">disconnect_from_server<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u6dfb\u52a0\u65ad\u5f00\u8fde\u63a5\u4efb\u52a1&#034;&#034;&#034;<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_enqueue<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;disconnect&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">list_directory<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> path<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u6dfb\u52a0\u5217\u76ee\u5f55\u4efb\u52a1&#034;&#034;&#034;<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_enqueue<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;list&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token string\">&#034;path&#034;<\/span><span class=\"token punctuation\">:<\/span> path<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">change_directory<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> path<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u6dfb\u52a0\u5207\u6362\u76ee\u5f55\u4efb\u52a1&#034;&#034;&#034;<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_enqueue<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;cwd&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token string\">&#034;path&#034;<\/span><span class=\"token punctuation\">:<\/span> path<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">upload_file<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> local_path<span class=\"token punctuation\">,<\/span> remote_name<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u6dfb\u52a0\u4e0a\u4f20\u4efb\u52a1&#034;&#034;&#034;<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_enqueue<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;upload&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n            <span class=\"token string\">&#034;local_path&#034;<\/span><span class=\"token punctuation\">:<\/span> local_path<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;remote_name&#034;<\/span><span class=\"token punctuation\">:<\/span> remote_name<br \/>\n        <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">download_file<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> remote_name<span class=\"token punctuation\">,<\/span> local_path<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u6dfb\u52a0\u4e0b\u8f7d\u4efb\u52a1&#034;&#034;&#034;<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_enqueue<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;download&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n            <span class=\"token string\">&#034;remote_name&#034;<\/span><span class=\"token punctuation\">:<\/span> remote_name<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;local_path&#034;<\/span><span class=\"token punctuation\">:<\/span> local_path<br \/>\n        <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">execute_raw_command<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> command<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u6dfb\u52a0\u539f\u59cb\u547d\u4ee4\u6267\u884c\u4efb\u52a1&#034;&#034;&#034;<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_enqueue<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;raw_cmd&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token string\">&#034;command&#034;<\/span><span class=\"token punctuation\">:<\/span> command<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">delete_file<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> name<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u6dfb\u52a0\u5220\u9664\u6587\u4ef6\u4efb\u52a1&#034;&#034;&#034;<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_enqueue<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;delete_file&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">:<\/span> name<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">delete_directory<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> name<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u6dfb\u52a0\u5220\u9664\u76ee\u5f55\u4efb\u52a1&#034;&#034;&#034;<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_enqueue<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;delete_dir&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">:<\/span> name<span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_enqueue<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> task_type<span class=\"token punctuation\">,<\/span> params<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">with<\/span> self<span class=\"token punctuation\">.<\/span>_lock<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>_task_queue<span class=\"token punctuation\">.<\/span>append<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">(<\/span>task_type<span class=\"token punctuation\">,<\/span> params<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">run<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">while<\/span> <span class=\"token keyword\">not<\/span> self<span class=\"token punctuation\">.<\/span>_stop_flag<span class=\"token punctuation\">:<\/span><br \/>\n            task <span class=\"token operator\">&#061;<\/span> <span class=\"token boolean\">None<\/span><br \/>\n            <span class=\"token keyword\">with<\/span> self<span class=\"token punctuation\">.<\/span>_lock<span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token keyword\">if<\/span> self<span class=\"token punctuation\">.<\/span>_task_queue<span class=\"token punctuation\">:<\/span><br \/>\n                    task <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>_task_queue<span class=\"token punctuation\">.<\/span>pop<span class=\"token punctuation\">(<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>            <span class=\"token keyword\">if<\/span> task <span class=\"token keyword\">is<\/span> <span class=\"token boolean\">None<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>msleep<span class=\"token punctuation\">(<\/span><span class=\"token number\">50<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">continue<\/span><\/p>\n<p>            task_type<span class=\"token punctuation\">,<\/span> params <span class=\"token operator\">&#061;<\/span> task<br \/>\n            <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token keyword\">if<\/span> task_type <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;connect&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    self<span class=\"token punctuation\">.<\/span>_do_connect<span class=\"token punctuation\">(<\/span><span class=\"token operator\">**<\/span>params<span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">elif<\/span> task_type <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;disconnect&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    self<span class=\"token punctuation\">.<\/span>_do_disconnect<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">elif<\/span> task_type <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;list&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    self<span class=\"token punctuation\">.<\/span>_do_list<span class=\"token punctuation\">(<\/span><span class=\"token operator\">**<\/span>params<span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">elif<\/span> task_type <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;cwd&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    self<span class=\"token punctuation\">.<\/span>_do_cwd<span class=\"token punctuation\">(<\/span><span class=\"token operator\">**<\/span>params<span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">elif<\/span> task_type <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;upload&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    self<span class=\"token punctuation\">.<\/span>_do_upload<span class=\"token punctuation\">(<\/span><span class=\"token operator\">**<\/span>params<span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">elif<\/span> task_type <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;download&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    self<span class=\"token punctuation\">.<\/span>_do_download<span class=\"token punctuation\">(<\/span><span class=\"token operator\">**<\/span>params<span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">elif<\/span> task_type <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;raw_cmd&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    self<span class=\"token punctuation\">.<\/span>_do_raw_command<span class=\"token punctuation\">(<\/span><span class=\"token operator\">**<\/span>params<span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">elif<\/span> task_type <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;delete_file&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    self<span class=\"token punctuation\">.<\/span>_do_delete_file<span class=\"token punctuation\">(<\/span><span class=\"token operator\">**<\/span>params<span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">elif<\/span> task_type <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;delete_dir&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    self<span class=\"token punctuation\">.<\/span>_do_delete_dir<span class=\"token punctuation\">(<\/span><span class=\"token operator\">**<\/span>params<span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">except<\/span> Exception <span class=\"token keyword\">as<\/span> e<span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u64cd\u4f5c\u5931\u8d25: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">stop<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_stop_flag <span class=\"token operator\">&#061;<\/span> <span class=\"token boolean\">True<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> self<span class=\"token punctuation\">.<\/span>ftp <span class=\"token keyword\">and<\/span> self<span class=\"token punctuation\">.<\/span>_connected<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>quit<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">except<\/span> Exception<span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token keyword\">pass<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>wait<span class=\"token punctuation\">(<\/span><span class=\"token number\">3000<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_do_connect<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> host<span class=\"token punctuation\">,<\/span> port<span class=\"token punctuation\">,<\/span> user<span class=\"token punctuation\">,<\/span> password<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;info&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u6b63\u5728\u8fde\u63a5 <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>host<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">:<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>port<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> &#8230;&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>ftp <span class=\"token operator\">&#061;<\/span> DebugFTP<span class=\"token punctuation\">(<\/span>log_callback<span class=\"token operator\">&#061;<\/span>self<span class=\"token punctuation\">.<\/span>_ftp_log<span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>host<span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">int<\/span><span class=\"token punctuation\">(<\/span>port<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> timeout<span class=\"token operator\">&#061;<\/span><span class=\"token number\">10<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>login<span class=\"token punctuation\">(<\/span>user<span class=\"token punctuation\">,<\/span> password<span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>_connected <span class=\"token operator\">&#061;<\/span> <span class=\"token boolean\">True<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;success&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u5df2\u8fde\u63a5\u5230 <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>host<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">:<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>port<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>connection_changed<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token boolean\">True<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token comment\"># \u8fde\u63a5\u6210\u529f\u540e\u5217\u51fa\u6839\u76ee\u5f55<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>_do_list<span class=\"token punctuation\">(<\/span>path<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">except<\/span> Exception <span class=\"token keyword\">as<\/span> e<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u8fde\u63a5\u5931\u8d25: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>connection_changed<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token boolean\">False<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>_connected <span class=\"token operator\">&#061;<\/span> <span class=\"token boolean\">False<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_do_disconnect<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>quit<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">except<\/span> Exception<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">pass<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_connected <span class=\"token operator\">&#061;<\/span> <span class=\"token boolean\">False<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>ftp <span class=\"token operator\">&#061;<\/span> <span class=\"token boolean\">None<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;info&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u5df2\u65ad\u5f00\u8fde\u63a5&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>connection_changed<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token boolean\">False<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_do_list<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> path<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> self<span class=\"token punctuation\">.<\/span>_connected <span class=\"token keyword\">or<\/span> <span class=\"token keyword\">not<\/span> self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">return<\/span><\/p>\n<p>        <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> path<span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>cwd<span class=\"token punctuation\">(<\/span>path<span class=\"token punctuation\">)<\/span><\/p>\n<p>            cwd <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>pwd<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;info&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u5f53\u524d\u76ee\u5f55: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>cwd<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>            items <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><br \/>\n            <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token comment\"># \u5c1d\u8bd5 MLSD&#xff08;\u7ed3\u6784\u5316\u76ee\u5f55\u5217\u8868&#xff09;<\/span><br \/>\n                <span class=\"token keyword\">for<\/span> name<span class=\"token punctuation\">,<\/span> facts <span class=\"token keyword\">in<\/span> self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>mlsd<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    <span class=\"token keyword\">if<\/span> name <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;.&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                        <span class=\"token keyword\">continue<\/span><br \/>\n                    <span class=\"token keyword\">if<\/span> name <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;..&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                        items<span class=\"token punctuation\">.<\/span>append<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;..&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token boolean\">True<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                        <span class=\"token keyword\">continue<\/span><br \/>\n                    is_dir <span class=\"token operator\">&#061;<\/span> facts<span class=\"token punctuation\">.<\/span>get<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;type&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;&#034;<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;dir&#034;<\/span><br \/>\n                    size <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">int<\/span><span class=\"token punctuation\">(<\/span>facts<span class=\"token punctuation\">.<\/span>get<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;size&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                    modify <span class=\"token operator\">&#061;<\/span> facts<span class=\"token punctuation\">.<\/span>get<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;modify&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                    items<span class=\"token punctuation\">.<\/span>append<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">(<\/span>name<span class=\"token punctuation\">,<\/span> size<span class=\"token punctuation\">,<\/span> is_dir<span class=\"token punctuation\">,<\/span> modify<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">except<\/span> error_perm<span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token comment\"># \u56de\u9000\u5230 LIST \u547d\u4ee4\u89e3\u6790<\/span><br \/>\n                lines <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>retrlines<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;LIST&#034;<\/span><span class=\"token punctuation\">,<\/span> lines<span class=\"token punctuation\">.<\/span>append<span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">for<\/span> line <span class=\"token keyword\">in<\/span> lines<span class=\"token punctuation\">:<\/span><br \/>\n                    parsed <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>_parse_list_line<span class=\"token punctuation\">(<\/span>line<span class=\"token punctuation\">)<\/span><br \/>\n                    <span class=\"token keyword\">if<\/span> parsed<span class=\"token punctuation\">:<\/span><br \/>\n                        items<span class=\"token punctuation\">.<\/span>append<span class=\"token punctuation\">(<\/span>parsed<span class=\"token punctuation\">)<\/span><\/p>\n<p>            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>file_list_received<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>items<span class=\"token punctuation\">,<\/span> cwd<span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token keyword\">except<\/span> Exception <span class=\"token keyword\">as<\/span> e<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u5217\u76ee\u5f55\u5931\u8d25: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_do_cwd<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> path<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> self<span class=\"token punctuation\">.<\/span>_connected <span class=\"token keyword\">or<\/span> <span class=\"token keyword\">not<\/span> self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">return<\/span><br \/>\n        <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>cwd<span class=\"token punctuation\">(<\/span>path<span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>_do_list<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">except<\/span> Exception <span class=\"token keyword\">as<\/span> e<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u5207\u6362\u76ee\u5f55\u5931\u8d25: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_do_upload<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> local_path<span class=\"token punctuation\">,<\/span> remote_name<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> self<span class=\"token punctuation\">.<\/span>_connected <span class=\"token keyword\">or<\/span> <span class=\"token keyword\">not<\/span> self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">return<\/span><br \/>\n        filename <span class=\"token operator\">&#061;<\/span> os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>basename<span class=\"token punctuation\">(<\/span>local_path<span class=\"token punctuation\">)<\/span><br \/>\n        file_size <span class=\"token operator\">&#061;<\/span> os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>getsize<span class=\"token punctuation\">(<\/span>local_path<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;info&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u5f00\u59cb\u4e0a\u4f20: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>filename<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> (<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>self<span class=\"token punctuation\">.<\/span>_format_size<span class=\"token punctuation\">(<\/span>file_size<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">)&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        transferred <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span><br \/>\n        last_emit <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span>time<span class=\"token punctuation\">.<\/span>time<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">]<\/span><\/p>\n<p>        <span class=\"token keyword\">class<\/span> <span class=\"token class-name\">TrackingFile<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u5305\u88c5\u6587\u4ef6\u5bf9\u8c61&#xff0c;\u5728\u6bcf\u6b21 read \u65f6\u8ddf\u8e2a\u4f20\u8f93\u8fdb\u5ea6&#034;&#034;&#034;<\/span><br \/>\n            <span class=\"token keyword\">def<\/span> <span class=\"token function\">__init__<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> fobj<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>_f <span class=\"token operator\">&#061;<\/span> fobj<br \/>\n            <span class=\"token keyword\">def<\/span> <span class=\"token function\">read<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> <span class=\"token operator\">*<\/span>args<span class=\"token punctuation\">,<\/span> <span class=\"token operator\">**<\/span>kwargs<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                data <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>_f<span class=\"token punctuation\">.<\/span>read<span class=\"token punctuation\">(<\/span><span class=\"token operator\">*<\/span>args<span class=\"token punctuation\">,<\/span> <span class=\"token operator\">**<\/span>kwargs<span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">if<\/span> data<span class=\"token punctuation\">:<\/span><br \/>\n                    transferred<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#043;&#061;<\/span> <span class=\"token builtin\">len<\/span><span class=\"token punctuation\">(<\/span>data<span class=\"token punctuation\">)<\/span><br \/>\n                    now <span class=\"token operator\">&#061;<\/span> time<span class=\"token punctuation\">.<\/span>time<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                    <span class=\"token keyword\">if<\/span> now <span class=\"token operator\">&#8211;<\/span> last_emit<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&gt;<\/span> <span class=\"token number\">0.1<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                        self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>transfer_progress<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><br \/>\n                            filename<span class=\"token punctuation\">,<\/span> transferred<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> file_size<br \/>\n                        <span class=\"token punctuation\">)<\/span><br \/>\n                        last_emit<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> now<br \/>\n                <span class=\"token keyword\">return<\/span> data<br \/>\n            <span class=\"token keyword\">def<\/span> <span class=\"token function\">__getattr__<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> name<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token keyword\">return<\/span> <span class=\"token builtin\">getattr<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_f<span class=\"token punctuation\">,<\/span> name<span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">with<\/span> <span class=\"token builtin\">open<\/span><span class=\"token punctuation\">(<\/span>local_path<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;rb&#034;<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">as<\/span> f<span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>storbinary<span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;STOR <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>remote_name<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">,<\/span> TrackingFile<span class=\"token punctuation\">(<\/span>f<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>transfer_progress<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>filename<span class=\"token punctuation\">,<\/span> file_size<span class=\"token punctuation\">,<\/span> file_size<span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>transfer_complete<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>filename<span class=\"token punctuation\">,<\/span> <span class=\"token boolean\">True<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u4e0a\u4f20\u6210\u529f&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;success&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u4e0a\u4f20\u5b8c\u6210: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>filename<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">except<\/span> Exception <span class=\"token keyword\">as<\/span> e<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>transfer_complete<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>filename<span class=\"token punctuation\">,<\/span> <span class=\"token boolean\">False<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">str<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u4e0a\u4f20\u5931\u8d25: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>filename<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> &#8211; <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_do_download<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> remote_name<span class=\"token punctuation\">,<\/span> local_path<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> self<span class=\"token punctuation\">.<\/span>_connected <span class=\"token keyword\">or<\/span> <span class=\"token keyword\">not<\/span> self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">return<\/span><br \/>\n        filename <span class=\"token operator\">&#061;<\/span> os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>basename<span class=\"token punctuation\">(<\/span>remote_name<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;info&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u5f00\u59cb\u4e0b\u8f7d: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>filename<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u83b7\u53d6\u6587\u4ef6\u5927\u5c0f<\/span><br \/>\n        file_size <span class=\"token operator\">&#061;<\/span> <span class=\"token number\">0<\/span><br \/>\n        <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            file_size <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>size<span class=\"token punctuation\">(<\/span>remote_name<span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">or<\/span> <span class=\"token number\">0<\/span><br \/>\n        <span class=\"token keyword\">except<\/span> Exception<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">pass<\/span><\/p>\n<p>        transferred <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span><br \/>\n        last_emit <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span>time<span class=\"token punctuation\">.<\/span>time<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">]<\/span><\/p>\n<p>        <span class=\"token keyword\">def<\/span> <span class=\"token function\">on_data<\/span><span class=\"token punctuation\">(<\/span>data<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            f<span class=\"token punctuation\">.<\/span>write<span class=\"token punctuation\">(<\/span>data<span class=\"token punctuation\">)<\/span><br \/>\n            transferred<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#043;&#061;<\/span> <span class=\"token builtin\">len<\/span><span class=\"token punctuation\">(<\/span>data<span class=\"token punctuation\">)<\/span><br \/>\n            now <span class=\"token operator\">&#061;<\/span> time<span class=\"token punctuation\">.<\/span>time<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> now <span class=\"token operator\">&#8211;<\/span> last_emit<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&gt;<\/span> <span class=\"token number\">0.1<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>transfer_progress<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>filename<span class=\"token punctuation\">,<\/span> transferred<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> file_size<span class=\"token punctuation\">)<\/span><br \/>\n                last_emit<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> now<\/p>\n<p>        <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">with<\/span> <span class=\"token builtin\">open<\/span><span class=\"token punctuation\">(<\/span>local_path<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;wb&#034;<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">as<\/span> f<span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>retrbinary<span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;RETR <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>remote_name<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">,<\/span> on_data<span class=\"token punctuation\">)<\/span><\/p>\n<p>            <span class=\"token keyword\">if<\/span> file_size <span class=\"token operator\">&gt;<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>transfer_progress<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>filename<span class=\"token punctuation\">,<\/span> file_size<span class=\"token punctuation\">,<\/span> file_size<span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>transfer_complete<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>filename<span class=\"token punctuation\">,<\/span> <span class=\"token boolean\">True<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u4e0b\u8f7d\u6210\u529f&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;success&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u4e0b\u8f7d\u5b8c\u6210: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>filename<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">except<\/span> Exception <span class=\"token keyword\">as<\/span> e<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>transfer_complete<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>filename<span class=\"token punctuation\">,<\/span> <span class=\"token boolean\">False<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">str<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u4e0b\u8f7d\u5931\u8d25: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>filename<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> &#8211; <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_do_raw_command<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> command<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> self<span class=\"token punctuation\">.<\/span>_connected <span class=\"token keyword\">or<\/span> <span class=\"token keyword\">not<\/span> self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>raw_command_result<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u9519\u8bef: \u672a\u8fde\u63a5\u5230\u670d\u52a1\u5668&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">return<\/span><\/p>\n<p>        <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            cmd <span class=\"token operator\">&#061;<\/span> command<span class=\"token punctuation\">.<\/span>strip<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> cmd<span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token keyword\">return<\/span><\/p>\n<p>            parts <span class=\"token operator\">&#061;<\/span> cmd<span class=\"token punctuation\">.<\/span>split<span class=\"token punctuation\">(<\/span><span class=\"token boolean\">None<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">1<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            cmd_name <span class=\"token operator\">&#061;<\/span> parts<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">.<\/span>upper<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            cmd_args <span class=\"token operator\">&#061;<\/span> parts<span class=\"token punctuation\">[<\/span><span class=\"token number\">1<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token keyword\">if<\/span> <span class=\"token builtin\">len<\/span><span class=\"token punctuation\">(<\/span>parts<span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&gt;<\/span> <span class=\"token number\">1<\/span> <span class=\"token keyword\">else<\/span> <span class=\"token string\">&#034;&#034;<\/span><\/p>\n<p>            <span class=\"token comment\"># \u7279\u6b8a\u5904\u7406\u4e00\u4e9b\u5e38\u89c1\u547d\u4ee4<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> cmd_name <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;LIST&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                lines <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><br \/>\n                <span class=\"token keyword\">if<\/span> cmd_args<span class=\"token punctuation\">:<\/span><br \/>\n                    self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>retrlines<span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;LIST <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>cmd_args<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">,<\/span> lines<span class=\"token punctuation\">.<\/span>append<span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>retrlines<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;LIST&#034;<\/span><span class=\"token punctuation\">,<\/span> lines<span class=\"token punctuation\">.<\/span>append<span class=\"token punctuation\">)<\/span><br \/>\n                result <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;\\\\n&#034;<\/span><span class=\"token punctuation\">.<\/span>join<span class=\"token punctuation\">(<\/span>lines<span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">if<\/span> lines <span class=\"token keyword\">else<\/span> <span class=\"token string\">&#034;(\u7a7a\u76ee\u5f55)&#034;<\/span><br \/>\n            <span class=\"token keyword\">elif<\/span> cmd_name <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;NLST&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                lines <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>retrlines<span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;NLST <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>cmd_args<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span> <span class=\"token keyword\">if<\/span> cmd_args <span class=\"token keyword\">else<\/span> <span class=\"token string\">&#034;NLST&#034;<\/span><span class=\"token punctuation\">,<\/span> lines<span class=\"token punctuation\">.<\/span>append<span class=\"token punctuation\">)<\/span><br \/>\n                result <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;\\\\n&#034;<\/span><span class=\"token punctuation\">.<\/span>join<span class=\"token punctuation\">(<\/span>lines<span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">if<\/span> lines <span class=\"token keyword\">else<\/span> <span class=\"token string\">&#034;(\u7a7a)&#034;<\/span><br \/>\n            <span class=\"token keyword\">elif<\/span> cmd_name <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;PWD&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                result <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>pwd<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">elif<\/span> cmd_name <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;CWD&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>cwd<span class=\"token punctuation\">(<\/span>cmd_args<span class=\"token punctuation\">)<\/span><br \/>\n                result <span class=\"token operator\">&#061;<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u5f53\u524d\u76ee\u5f55: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>pwd<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><br \/>\n            <span class=\"token keyword\">elif<\/span> cmd_name <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;SIZE&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                size <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>size<span class=\"token punctuation\">(<\/span>cmd_args<span class=\"token punctuation\">)<\/span><br \/>\n                result <span class=\"token operator\">&#061;<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>cmd_args<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>size<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> bytes&#034;<\/span><\/span> <span class=\"token keyword\">if<\/span> size <span class=\"token keyword\">is<\/span> <span class=\"token keyword\">not<\/span> <span class=\"token boolean\">None<\/span> <span class=\"token keyword\">else<\/span> <span class=\"token string\">&#034;\u65e0\u6cd5\u83b7\u53d6\u5927\u5c0f&#034;<\/span><br \/>\n            <span class=\"token keyword\">elif<\/span> cmd_name <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;MKD&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                result <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>mkd<span class=\"token punctuation\">(<\/span>cmd_args<span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">elif<\/span> cmd_name <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;RMD&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>rmd<span class=\"token punctuation\">(<\/span>cmd_args<span class=\"token punctuation\">)<\/span><br \/>\n                result <span class=\"token operator\">&#061;<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u5df2\u5220\u9664\u76ee\u5f55: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>cmd_args<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><br \/>\n            <span class=\"token keyword\">elif<\/span> cmd_name <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;DELE&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>delete<span class=\"token punctuation\">(<\/span>cmd_args<span class=\"token punctuation\">)<\/span><br \/>\n                result <span class=\"token operator\">&#061;<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u5df2\u5220\u9664\u6587\u4ef6: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>cmd_args<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><br \/>\n            <span class=\"token keyword\">elif<\/span> cmd_name <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;REN&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token comment\"># REN old new<\/span><br \/>\n                ren_parts <span class=\"token operator\">&#061;<\/span> cmd_args<span class=\"token punctuation\">.<\/span>split<span class=\"token punctuation\">(<\/span><span class=\"token boolean\">None<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">1<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">if<\/span> <span class=\"token builtin\">len<\/span><span class=\"token punctuation\">(<\/span>ren_parts<span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token number\">2<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>rename<span class=\"token punctuation\">(<\/span>ren_parts<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> ren_parts<span class=\"token punctuation\">[<\/span><span class=\"token number\">1<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                    result <span class=\"token operator\">&#061;<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u5df2\u91cd\u547d\u540d: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>ren_parts<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> -&gt; <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>ren_parts<span class=\"token punctuation\">[<\/span><span class=\"token number\">1<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><br \/>\n                <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    result <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;\u7528\u6cd5: REN &lt;\u65e7\u540d&gt; &lt;\u65b0\u540d&gt;&#034;<\/span><br \/>\n            <span class=\"token keyword\">elif<\/span> cmd_name <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;HELP&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                resp <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>sendcmd<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;HELP&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                result <span class=\"token operator\">&#061;<\/span> resp<br \/>\n            <span class=\"token keyword\">elif<\/span> cmd_name <span class=\"token keyword\">in<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;QUIT&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;BYE&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                result <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;\u8bf7\u4f7f\u7528\u754c\u9762\u4e0a\u7684\u65ad\u5f00\u6309\u94ae&#034;<\/span><br \/>\n            <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token comment\"># \u901a\u7528\u547d\u4ee4\u53d1\u9001<\/span><br \/>\n                resp <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>sendcmd<span class=\"token punctuation\">(<\/span>cmd<span class=\"token punctuation\">)<\/span><br \/>\n                result <span class=\"token operator\">&#061;<\/span> resp<\/p>\n<p>            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>raw_command_result<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>result<span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token keyword\">except<\/span> Exception <span class=\"token keyword\">as<\/span> e<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>raw_command_result<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u9519\u8bef: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_do_delete_file<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> name<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u5220\u9664\u8fdc\u7a0b\u6587\u4ef6&#034;&#034;&#034;<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> self<span class=\"token punctuation\">.<\/span>_connected <span class=\"token keyword\">or<\/span> <span class=\"token keyword\">not<\/span> self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">return<\/span><br \/>\n        <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>delete<span class=\"token punctuation\">(<\/span>name<span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;success&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u5df2\u5220\u9664\u6587\u4ef6: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>name<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token comment\"># \u5220\u9664\u540e\u5237\u65b0\u76ee\u5f55<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>_do_list<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">except<\/span> Exception <span class=\"token keyword\">as<\/span> e<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u5220\u9664\u6587\u4ef6\u5931\u8d25: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>name<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> &#8211; <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_do_delete_dir<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> name<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u5220\u9664\u8fdc\u7a0b\u76ee\u5f55&#034;&#034;&#034;<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> self<span class=\"token punctuation\">.<\/span>_connected <span class=\"token keyword\">or<\/span> <span class=\"token keyword\">not<\/span> self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">return<\/span><br \/>\n        <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>rmd<span class=\"token punctuation\">(<\/span>name<span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;success&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u5df2\u5220\u9664\u76ee\u5f55: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>name<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token comment\"># \u5220\u9664\u540e\u5237\u65b0\u76ee\u5f55<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>_do_list<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">except<\/span> Exception <span class=\"token keyword\">as<\/span> e<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u5220\u9664\u76ee\u5f55\u5931\u8d25: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>name<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> &#8211; <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_ftp_log<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> category<span class=\"token punctuation\">,<\/span> message<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;FTP \u547d\u4ee4\/\u54cd\u5e94\u65e5\u5fd7\u56de\u8c03&#034;&#034;&#034;<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>category<span class=\"token punctuation\">,<\/span> message<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_parse_list_line<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> line<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u89e3\u6790 LIST \u547d\u4ee4\u8f93\u51fa\u7684\u6bcf\u4e00\u884c&#034;&#034;&#034;<\/span><br \/>\n        <span class=\"token comment\"># Unix \u683c\u5f0f: drwxr-xr-x  2 user group  4096 Jan 01 12:00 filename<\/span><br \/>\n        <span class=\"token comment\"># DOS \u683c\u5f0f:  01-01-24  12:00AM  &lt;DIR&gt;  dirname<\/span><br \/>\n        <span class=\"token comment\">#            01-01-24  12:00AM       1234 filename<\/span><br \/>\n        parts <span class=\"token operator\">&#061;<\/span> line<span class=\"token punctuation\">.<\/span>split<span class=\"token punctuation\">(<\/span><span class=\"token boolean\">None<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">8<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token keyword\">if<\/span> <span class=\"token builtin\">len<\/span><span class=\"token punctuation\">(<\/span>parts<span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&gt;&#061;<\/span> <span class=\"token number\">9<\/span> <span class=\"token keyword\">and<\/span> <span class=\"token punctuation\">(<\/span>parts<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token keyword\">in<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token string\">&#039;d&#039;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#039;-&#039;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#039;l&#039;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#039;r&#039;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token comment\"># Unix \u683c\u5f0f<\/span><br \/>\n            is_dir <span class=\"token operator\">&#061;<\/span> parts<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#039;d&#039;<\/span><br \/>\n            <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                size <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">int<\/span><span class=\"token punctuation\">(<\/span>parts<span class=\"token punctuation\">[<\/span><span class=\"token number\">4<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">except<\/span> <span class=\"token punctuation\">(<\/span>ValueError<span class=\"token punctuation\">,<\/span> IndexError<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                size <span class=\"token operator\">&#061;<\/span> <span class=\"token number\">0<\/span><br \/>\n            name <span class=\"token operator\">&#061;<\/span> parts<span class=\"token punctuation\">[<\/span><span class=\"token number\">8<\/span><span class=\"token punctuation\">]<\/span><br \/>\n            <span class=\"token keyword\">return<\/span> <span class=\"token punctuation\">(<\/span>name<span class=\"token punctuation\">,<\/span> size<span class=\"token punctuation\">,<\/span> is_dir<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;&#034;<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token keyword\">elif<\/span> <span class=\"token builtin\">len<\/span><span class=\"token punctuation\">(<\/span>parts<span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&gt;&#061;<\/span> <span class=\"token number\">4<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token comment\"># \u5c1d\u8bd5 DOS \u683c\u5f0f<\/span><br \/>\n            <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                is_dir <span class=\"token operator\">&#061;<\/span> parts<span class=\"token punctuation\">[<\/span><span class=\"token number\">2<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#039;&lt;DIR&gt;&#039;<\/span><br \/>\n                size <span class=\"token operator\">&#061;<\/span> <span class=\"token number\">0<\/span> <span class=\"token keyword\">if<\/span> is_dir <span class=\"token keyword\">else<\/span> <span class=\"token builtin\">int<\/span><span class=\"token punctuation\">(<\/span>parts<span class=\"token punctuation\">[<\/span><span class=\"token number\">2<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                name <span class=\"token operator\">&#061;<\/span> parts<span class=\"token punctuation\">[<\/span><span class=\"token number\">3<\/span><span class=\"token punctuation\">]<\/span><br \/>\n                <span class=\"token keyword\">return<\/span> <span class=\"token punctuation\">(<\/span>name<span class=\"token punctuation\">,<\/span> size<span class=\"token punctuation\">,<\/span> is_dir<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">except<\/span> <span class=\"token punctuation\">(<\/span>ValueError<span class=\"token punctuation\">,<\/span> IndexError<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token keyword\">pass<\/span><\/p>\n<p>        <span class=\"token keyword\">return<\/span> <span class=\"token boolean\">None<\/span><\/p>\n<p>    <span class=\"token decorator annotation punctuation\">&#064;staticmethod<\/span><br \/>\n    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_format_size<\/span><span class=\"token punctuation\">(<\/span>size_bytes<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> size_bytes <span class=\"token operator\">&lt;<\/span> <span class=\"token number\">1024<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">return<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>size_bytes<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> B&#034;<\/span><\/span><br \/>\n        <span class=\"token keyword\">elif<\/span> size_bytes <span class=\"token operator\">&lt;<\/span> <span class=\"token number\">1024<\/span> <span class=\"token operator\">*<\/span> <span class=\"token number\">1024<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">return<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>size_bytes <span class=\"token operator\">\/<\/span> <span class=\"token number\">1024<\/span><span class=\"token punctuation\">:<\/span><span class=\"token format-spec\">.1f<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> KB&#034;<\/span><\/span><br \/>\n        <span class=\"token keyword\">elif<\/span> size_bytes <span class=\"token operator\">&lt;<\/span> <span class=\"token number\">1024<\/span> <span class=\"token operator\">*<\/span> <span class=\"token number\">1024<\/span> <span class=\"token operator\">*<\/span> <span class=\"token number\">1024<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">return<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>size_bytes <span class=\"token operator\">\/<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token number\">1024<\/span> <span class=\"token operator\">*<\/span> <span class=\"token number\">1024<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><span class=\"token format-spec\">.1f<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> MB&#034;<\/span><\/span><br \/>\n        <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">return<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>size_bytes <span class=\"token operator\">\/<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token number\">1024<\/span> <span class=\"token operator\">*<\/span> <span class=\"token number\">1024<\/span> <span class=\"token operator\">*<\/span> <span class=\"token number\">1024<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><span class=\"token format-spec\">.2f<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> GB&#034;<\/span><\/span><\/p>\n<p><span class=\"token comment\"># &#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;<\/span><br \/>\n<span class=\"token comment\">#  \u6587\u4ef6\u6d4f\u89c8\u5668 Widget<\/span><br \/>\n<span class=\"token comment\"># &#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;<\/span><br \/>\n<span class=\"token keyword\">class<\/span> <span class=\"token class-name\">FileBrowserWidget<\/span><span class=\"token punctuation\">(<\/span>QWidget<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u6587\u4ef6\u6d4f\u89c8\u5668\u7ec4\u4ef6&#xff0c;\u7528\u4e8e\u8fdc\u7a0b\u548c\u672c\u5730\u6587\u4ef6\u6d4f\u89c8&#034;&#034;&#034;<\/span><\/p>\n<p>    file_selected <span class=\"token operator\">&#061;<\/span> pyqtSignal<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">bool<\/span><span class=\"token punctuation\">)<\/span>  <span class=\"token comment\"># (\u6587\u4ef6\u8def\u5f84, \u662f\u5426\u4e3a\u76ee\u5f55)<\/span><br \/>\n    file_delete_requested <span class=\"token operator\">&#061;<\/span> pyqtSignal<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">bool<\/span><span class=\"token punctuation\">)<\/span>  <span class=\"token comment\"># (\u540d\u79f0, \u662f\u5426\u4e3a\u76ee\u5f55)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">__init__<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> title<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;\u6587\u4ef6\u6d4f\u89c8\u5668&#034;<\/span><span class=\"token punctuation\">,<\/span> is_remote<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">False<\/span><span class=\"token punctuation\">,<\/span> parent<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">None<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token builtin\">super<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>__init__<span class=\"token punctuation\">(<\/span>parent<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>is_remote <span class=\"token operator\">&#061;<\/span> is_remote<br \/>\n        self<span class=\"token punctuation\">.<\/span>current_path <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;&#034;<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>path_history <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><\/p>\n<p>        layout <span class=\"token operator\">&#061;<\/span> QVBoxLayout<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><br \/>\n        layout<span class=\"token punctuation\">.<\/span>setContentsMargins<span class=\"token punctuation\">(<\/span><span class=\"token number\">4<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">4<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">4<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">4<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        layout<span class=\"token punctuation\">.<\/span>setSpacing<span class=\"token punctuation\">(<\/span><span class=\"token number\">4<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u6807\u9898\u548c\u8def\u5f84<\/span><br \/>\n        header <span class=\"token operator\">&#061;<\/span> QHBoxLayout<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>title_label <span class=\"token operator\">&#061;<\/span> QLabel<span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;&lt;b&gt;<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>title<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&lt;\/b&gt;&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n        header<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>title_label<span class=\"token punctuation\">)<\/span><br \/>\n        header<span class=\"token punctuation\">.<\/span>addStretch<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        self<span class=\"token punctuation\">.<\/span>path_label <span class=\"token operator\">&#061;<\/span> QLineEdit<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>path_label<span class=\"token punctuation\">.<\/span>setReadOnly<span class=\"token punctuation\">(<\/span><span class=\"token boolean\">True<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>path_label<span class=\"token punctuation\">.<\/span>setPlaceholderText<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u8def\u5f84&#8230;&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>path_label<span class=\"token punctuation\">.<\/span>setMinimumWidth<span class=\"token punctuation\">(<\/span><span class=\"token number\">200<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        header<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>path_label<span class=\"token punctuation\">,<\/span> stretch<span class=\"token operator\">&#061;<\/span><span class=\"token number\">1<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        layout<span class=\"token punctuation\">.<\/span>addLayout<span class=\"token punctuation\">(<\/span>header<span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u6587\u4ef6\u5217\u8868<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>tree <span class=\"token operator\">&#061;<\/span> QTreeWidget<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>tree<span class=\"token punctuation\">.<\/span>setHeaderLabels<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;\u540d\u79f0&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u5927\u5c0f&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u7c7b\u578b&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>tree<span class=\"token punctuation\">.<\/span>setColumnCount<span class=\"token punctuation\">(<\/span><span class=\"token number\">3<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>tree<span class=\"token punctuation\">.<\/span>setRootIsDecorated<span class=\"token punctuation\">(<\/span><span class=\"token boolean\">False<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>tree<span class=\"token punctuation\">.<\/span>setSortingEnabled<span class=\"token punctuation\">(<\/span><span class=\"token boolean\">True<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>tree<span class=\"token punctuation\">.<\/span>setSelectionMode<span class=\"token punctuation\">(<\/span>QAbstractItemView<span class=\"token punctuation\">.<\/span>SelectionMode<span class=\"token punctuation\">.<\/span>SingleSelection<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>tree<span class=\"token punctuation\">.<\/span>setContextMenuPolicy<span class=\"token punctuation\">(<\/span>Qt<span class=\"token punctuation\">.<\/span>ContextMenuPolicy<span class=\"token punctuation\">.<\/span>CustomContextMenu<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>tree<span class=\"token punctuation\">.<\/span>customContextMenuRequested<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_show_context_menu<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>tree<span class=\"token punctuation\">.<\/span>itemDoubleClicked<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_on_item_double_clicked<span class=\"token punctuation\">)<\/span><\/p>\n<p>        header_view <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>tree<span class=\"token punctuation\">.<\/span>header<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        header_view<span class=\"token punctuation\">.<\/span>setStretchLastSection<span class=\"token punctuation\">(<\/span><span class=\"token boolean\">True<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        header_view<span class=\"token punctuation\">.<\/span>setSectionResizeMode<span class=\"token punctuation\">(<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> QHeaderView<span class=\"token punctuation\">.<\/span>ResizeMode<span class=\"token punctuation\">.<\/span>Stretch<span class=\"token punctuation\">)<\/span><br \/>\n        header_view<span class=\"token punctuation\">.<\/span>setSectionResizeMode<span class=\"token punctuation\">(<\/span><span class=\"token number\">1<\/span><span class=\"token punctuation\">,<\/span> QHeaderView<span class=\"token punctuation\">.<\/span>ResizeMode<span class=\"token punctuation\">.<\/span>ResizeToContents<span class=\"token punctuation\">)<\/span><br \/>\n        header_view<span class=\"token punctuation\">.<\/span>setSectionResizeMode<span class=\"token punctuation\">(<\/span><span class=\"token number\">2<\/span><span class=\"token punctuation\">,<\/span> QHeaderView<span class=\"token punctuation\">.<\/span>ResizeMode<span class=\"token punctuation\">.<\/span>ResizeToContents<span class=\"token punctuation\">)<\/span><\/p>\n<p>        layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>tree<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">set_file_list<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> items<span class=\"token punctuation\">,<\/span> current_path<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u8bbe\u7f6e\u6587\u4ef6\u5217\u8868 items: [(name, size, is_dir, modify), &#8230;]&#034;&#034;&#034;<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>tree<span class=\"token punctuation\">.<\/span>clear<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>current_path <span class=\"token operator\">&#061;<\/span> current_path<br \/>\n        self<span class=\"token punctuation\">.<\/span>path_label<span class=\"token punctuation\">.<\/span>setText<span class=\"token punctuation\">(<\/span>current_path<span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u6392\u5e8f&#xff1a;\u76ee\u5f55\u5728\u524d&#xff0c;\u6587\u4ef6\u5728\u540e<\/span><br \/>\n        dirs <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">sorted<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">[<\/span>i <span class=\"token keyword\">for<\/span> i <span class=\"token keyword\">in<\/span> items <span class=\"token keyword\">if<\/span> i<span class=\"token punctuation\">[<\/span><span class=\"token number\">2<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> key<span class=\"token operator\">&#061;<\/span><span class=\"token keyword\">lambda<\/span> x<span class=\"token punctuation\">:<\/span> x<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">.<\/span>lower<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        files <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">sorted<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">[<\/span>i <span class=\"token keyword\">for<\/span> i <span class=\"token keyword\">in<\/span> items <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> i<span class=\"token punctuation\">[<\/span><span class=\"token number\">2<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> key<span class=\"token operator\">&#061;<\/span><span class=\"token keyword\">lambda<\/span> x<span class=\"token punctuation\">:<\/span> x<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">.<\/span>lower<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token keyword\">for<\/span> name<span class=\"token punctuation\">,<\/span> size<span class=\"token punctuation\">,<\/span> is_dir<span class=\"token punctuation\">,<\/span> modify <span class=\"token keyword\">in<\/span> dirs <span class=\"token operator\">&#043;<\/span> files<span class=\"token punctuation\">:<\/span><br \/>\n            item <span class=\"token operator\">&#061;<\/span> QTreeWidgetItem<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            icon <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;&#x1f4c1;&#034;<\/span> <span class=\"token keyword\">if<\/span> is_dir <span class=\"token keyword\">else<\/span> <span class=\"token string\">&#034;&#x1f4c4;&#034;<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> name <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;..&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                icon <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;\u2b06\ufe0f&#034;<\/span><\/p>\n<p>            item<span class=\"token punctuation\">.<\/span>setText<span class=\"token punctuation\">(<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>icon<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>name<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n            item<span class=\"token punctuation\">.<\/span>setText<span class=\"token punctuation\">(<\/span><span class=\"token number\">1<\/span><span class=\"token punctuation\">,<\/span> self<span class=\"token punctuation\">.<\/span>_format_size<span class=\"token punctuation\">(<\/span>size<span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> is_dir <span class=\"token keyword\">else<\/span> <span class=\"token string\">&#034;&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            item<span class=\"token punctuation\">.<\/span>setText<span class=\"token punctuation\">(<\/span><span class=\"token number\">2<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u6587\u4ef6\u5939&#034;<\/span> <span class=\"token keyword\">if<\/span> is_dir <span class=\"token keyword\">else<\/span> <span class=\"token string\">&#034;\u6587\u4ef6&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            item<span class=\"token punctuation\">.<\/span>setData<span class=\"token punctuation\">(<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> Qt<span class=\"token punctuation\">.<\/span>ItemDataRole<span class=\"token punctuation\">.<\/span>UserRole<span class=\"token punctuation\">,<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n                <span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">:<\/span> name<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;size&#034;<\/span><span class=\"token punctuation\">:<\/span> size<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;is_dir&#034;<\/span><span class=\"token punctuation\">:<\/span> is_dir<br \/>\n            <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>tree<span class=\"token punctuation\">.<\/span>addTopLevelItem<span class=\"token punctuation\">(<\/span>item<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_on_item_double_clicked<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> item<span class=\"token punctuation\">,<\/span> column<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        data <span class=\"token operator\">&#061;<\/span> item<span class=\"token punctuation\">.<\/span>data<span class=\"token punctuation\">(<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> Qt<span class=\"token punctuation\">.<\/span>ItemDataRole<span class=\"token punctuation\">.<\/span>UserRole<span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> data<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>file_selected<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>data<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> data<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;is_dir&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_show_context_menu<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> pos<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        item <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>tree<span class=\"token punctuation\">.<\/span>itemAt<span class=\"token punctuation\">(<\/span>pos<span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> item<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">return<\/span><br \/>\n        data <span class=\"token operator\">&#061;<\/span> item<span class=\"token punctuation\">.<\/span>data<span class=\"token punctuation\">(<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> Qt<span class=\"token punctuation\">.<\/span>ItemDataRole<span class=\"token punctuation\">.<\/span>UserRole<span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> data<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">return<\/span><\/p>\n<p>        menu <span class=\"token operator\">&#061;<\/span> QMenu<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> data<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;is_dir&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            action <span class=\"token operator\">&#061;<\/span> menu<span class=\"token punctuation\">.<\/span>addAction<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u6253\u5f00\u76ee\u5f55&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            action<span class=\"token punctuation\">.<\/span>triggered<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span><br \/>\n                <span class=\"token keyword\">lambda<\/span><span class=\"token punctuation\">:<\/span> self<span class=\"token punctuation\">.<\/span>file_selected<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>data<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token boolean\">True<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> self<span class=\"token punctuation\">.<\/span>is_remote <span class=\"token keyword\">and<\/span> data<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">!&#061;<\/span> <span class=\"token string\">&#034;..&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                menu<span class=\"token punctuation\">.<\/span>addSeparator<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                del_action <span class=\"token operator\">&#061;<\/span> menu<span class=\"token punctuation\">.<\/span>addAction<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;&#x1f5d1;\ufe0f \u5220\u9664\u76ee\u5f55&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                del_action<span class=\"token punctuation\">.<\/span>triggered<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span><br \/>\n                    <span class=\"token keyword\">lambda<\/span><span class=\"token punctuation\">:<\/span> self<span class=\"token punctuation\">.<\/span>file_delete_requested<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>data<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token boolean\">True<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> self<span class=\"token punctuation\">.<\/span>is_remote<span class=\"token punctuation\">:<\/span><br \/>\n                action <span class=\"token operator\">&#061;<\/span> menu<span class=\"token punctuation\">.<\/span>addAction<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u4e0b\u8f7d&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                action<span class=\"token punctuation\">.<\/span>triggered<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span><br \/>\n                    <span class=\"token keyword\">lambda<\/span><span class=\"token punctuation\">:<\/span> self<span class=\"token punctuation\">.<\/span>file_selected<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>data<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token boolean\">False<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token punctuation\">)<\/span><br \/>\n                menu<span class=\"token punctuation\">.<\/span>addSeparator<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                del_action <span class=\"token operator\">&#061;<\/span> menu<span class=\"token punctuation\">.<\/span>addAction<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u5220\u9664\u6587\u4ef6&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                del_action<span class=\"token punctuation\">.<\/span>triggered<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span><br \/>\n                    <span class=\"token keyword\">lambda<\/span><span class=\"token punctuation\">:<\/span> self<span class=\"token punctuation\">.<\/span>file_delete_requested<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>data<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token boolean\">False<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                action <span class=\"token operator\">&#061;<\/span> menu<span class=\"token punctuation\">.<\/span>addAction<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u4e0a\u4f20&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                action<span class=\"token punctuation\">.<\/span>triggered<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span><br \/>\n                    <span class=\"token keyword\">lambda<\/span><span class=\"token punctuation\">:<\/span> self<span class=\"token punctuation\">.<\/span>file_selected<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>data<span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;name&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token boolean\">False<\/span><span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token punctuation\">)<\/span><br \/>\n        menu<span class=\"token punctuation\">.<\/span><span class=\"token keyword\">exec<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>tree<span class=\"token punctuation\">.<\/span>viewport<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>mapToGlobal<span class=\"token punctuation\">(<\/span>pos<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">load_local_directory<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> path<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u52a0\u8f7d\u672c\u5730\u76ee\u5f55\u5185\u5bb9&#034;&#034;&#034;<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>isdir<span class=\"token punctuation\">(<\/span>path<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">return<\/span><br \/>\n        items <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><br \/>\n        <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> path <span class=\"token operator\">!&#061;<\/span> os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>dirname<span class=\"token punctuation\">(<\/span>path<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span>  <span class=\"token comment\"># \u975e\u6839\u76ee\u5f55&#xff0c;\u6dfb\u52a0 ..<\/span><br \/>\n                items<span class=\"token punctuation\">.<\/span>append<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;..&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token boolean\">True<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">for<\/span> name <span class=\"token keyword\">in<\/span> os<span class=\"token punctuation\">.<\/span>listdir<span class=\"token punctuation\">(<\/span>path<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                full_path <span class=\"token operator\">&#061;<\/span> os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>join<span class=\"token punctuation\">(<\/span>path<span class=\"token punctuation\">,<\/span> name<span class=\"token punctuation\">)<\/span><br \/>\n                is_dir <span class=\"token operator\">&#061;<\/span> os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>isdir<span class=\"token punctuation\">(<\/span>full_path<span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                    size <span class=\"token operator\">&#061;<\/span> os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>getsize<span class=\"token punctuation\">(<\/span>full_path<span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> is_dir <span class=\"token keyword\">else<\/span> <span class=\"token number\">0<\/span><br \/>\n                <span class=\"token keyword\">except<\/span> OSError<span class=\"token punctuation\">:<\/span><br \/>\n                    size <span class=\"token operator\">&#061;<\/span> <span class=\"token number\">0<\/span><br \/>\n                items<span class=\"token punctuation\">.<\/span>append<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">(<\/span>name<span class=\"token punctuation\">,<\/span> size<span class=\"token punctuation\">,<\/span> is_dir<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>set_file_list<span class=\"token punctuation\">(<\/span>items<span class=\"token punctuation\">,<\/span> path<span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">except<\/span> PermissionError<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">pass<\/span><\/p>\n<p>    <span class=\"token decorator annotation punctuation\">&#064;staticmethod<\/span><br \/>\n    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_format_size<\/span><span class=\"token punctuation\">(<\/span>size_bytes<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> size_bytes <span class=\"token operator\">&lt;<\/span> <span class=\"token number\">1024<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">return<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>size_bytes<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> B&#034;<\/span><\/span><br \/>\n        <span class=\"token keyword\">elif<\/span> size_bytes <span class=\"token operator\">&lt;<\/span> <span class=\"token number\">1024<\/span> <span class=\"token operator\">*<\/span> <span class=\"token number\">1024<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">return<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>size_bytes <span class=\"token operator\">\/<\/span> <span class=\"token number\">1024<\/span><span class=\"token punctuation\">:<\/span><span class=\"token format-spec\">.1f<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> KB&#034;<\/span><\/span><br \/>\n        <span class=\"token keyword\">elif<\/span> size_bytes <span class=\"token operator\">&lt;<\/span> <span class=\"token number\">1024<\/span> <span class=\"token operator\">*<\/span> <span class=\"token number\">1024<\/span> <span class=\"token operator\">*<\/span> <span class=\"token number\">1024<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">return<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>size_bytes <span class=\"token operator\">\/<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token number\">1024<\/span> <span class=\"token operator\">*<\/span> <span class=\"token number\">1024<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><span class=\"token format-spec\">.1f<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> MB&#034;<\/span><\/span><br \/>\n        <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">return<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>size_bytes <span class=\"token operator\">\/<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token number\">1024<\/span> <span class=\"token operator\">*<\/span> <span class=\"token number\">1024<\/span> <span class=\"token operator\">*<\/span> <span class=\"token number\">1024<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><span class=\"token format-spec\">.2f<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> GB&#034;<\/span><\/span><\/p>\n<p><span class=\"token comment\"># &#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;<\/span><br \/>\n<span class=\"token comment\">#  \u4f20\u8f93\u8fdb\u5ea6 Widget<\/span><br \/>\n<span class=\"token comment\"># &#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;<\/span><br \/>\n<span class=\"token keyword\">class<\/span> <span class=\"token class-name\">TransferWidget<\/span><span class=\"token punctuation\">(<\/span>QWidget<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token keyword\">def<\/span> <span class=\"token function\">__init__<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> parent<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">None<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token builtin\">super<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>__init__<span class=\"token punctuation\">(<\/span>parent<span class=\"token punctuation\">)<\/span><br \/>\n        layout <span class=\"token operator\">&#061;<\/span> QVBoxLayout<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><br \/>\n        layout<span class=\"token punctuation\">.<\/span>setContentsMargins<span class=\"token punctuation\">(<\/span><span class=\"token number\">4<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">4<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">4<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">4<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        header <span class=\"token operator\">&#061;<\/span> QLabel<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;&lt;b&gt;\u4f20\u8f93\u961f\u5217&lt;\/b&gt;&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>header<span class=\"token punctuation\">)<\/span><\/p>\n<p>        self<span class=\"token punctuation\">.<\/span>transfer_list <span class=\"token operator\">&#061;<\/span> QTreeWidget<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>transfer_list<span class=\"token punctuation\">.<\/span>setHeaderLabels<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">[<\/span><span class=\"token string\">&#034;\u6587\u4ef6&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u65b9\u5411&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u8fdb\u5ea6&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u72b6\u6001&#034;<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>transfer_list<span class=\"token punctuation\">.<\/span>setColumnCount<span class=\"token punctuation\">(<\/span><span class=\"token number\">4<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>transfer_list<span class=\"token punctuation\">.<\/span>setRootIsDecorated<span class=\"token punctuation\">(<\/span><span class=\"token boolean\">False<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        header_view <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>transfer_list<span class=\"token punctuation\">.<\/span>header<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        header_view<span class=\"token punctuation\">.<\/span>setStretchLastSection<span class=\"token punctuation\">(<\/span><span class=\"token boolean\">True<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        header_view<span class=\"token punctuation\">.<\/span>setSectionResizeMode<span class=\"token punctuation\">(<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> QHeaderView<span class=\"token punctuation\">.<\/span>ResizeMode<span class=\"token punctuation\">.<\/span>Stretch<span class=\"token punctuation\">)<\/span><br \/>\n        header_view<span class=\"token punctuation\">.<\/span>setSectionResizeMode<span class=\"token punctuation\">(<\/span><span class=\"token number\">1<\/span><span class=\"token punctuation\">,<\/span> QHeaderView<span class=\"token punctuation\">.<\/span>ResizeMode<span class=\"token punctuation\">.<\/span>ResizeToContents<span class=\"token punctuation\">)<\/span><br \/>\n        header_view<span class=\"token punctuation\">.<\/span>setSectionResizeMode<span class=\"token punctuation\">(<\/span><span class=\"token number\">3<\/span><span class=\"token punctuation\">,<\/span> QHeaderView<span class=\"token punctuation\">.<\/span>ResizeMode<span class=\"token punctuation\">.<\/span>ResizeToContents<span class=\"token punctuation\">)<\/span><\/p>\n<p>        layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>transfer_list<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_progress_map <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token punctuation\">}<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">add_transfer<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> filename<span class=\"token punctuation\">,<\/span> direction<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;direction: &#039;upload&#039; or &#039;download&#039;&#034;&#034;&#034;<\/span><br \/>\n        item <span class=\"token operator\">&#061;<\/span> QTreeWidgetItem<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        icon <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;&#x1f4e4;&#034;<\/span> <span class=\"token keyword\">if<\/span> direction <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;upload&#034;<\/span> <span class=\"token keyword\">else<\/span> <span class=\"token string\">&#034;&#x1f4e5;&#034;<\/span><br \/>\n        item<span class=\"token punctuation\">.<\/span>setText<span class=\"token punctuation\">(<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> filename<span class=\"token punctuation\">)<\/span><br \/>\n        item<span class=\"token punctuation\">.<\/span>setText<span class=\"token punctuation\">(<\/span><span class=\"token number\">1<\/span><span class=\"token punctuation\">,<\/span> icon<span class=\"token punctuation\">)<\/span><br \/>\n        item<span class=\"token punctuation\">.<\/span>setText<span class=\"token punctuation\">(<\/span><span class=\"token number\">2<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;0%&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        item<span class=\"token punctuation\">.<\/span>setText<span class=\"token punctuation\">(<\/span><span class=\"token number\">3<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u7b49\u5f85\u4e2d&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>transfer_list<span class=\"token punctuation\">.<\/span>addTopLevelItem<span class=\"token punctuation\">(<\/span>item<span class=\"token punctuation\">)<\/span><\/p>\n<p>        progress <span class=\"token operator\">&#061;<\/span> QProgressBar<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        progress<span class=\"token punctuation\">.<\/span>setMaximum<span class=\"token punctuation\">(<\/span><span class=\"token number\">100<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        progress<span class=\"token punctuation\">.<\/span>setValue<span class=\"token punctuation\">(<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>transfer_list<span class=\"token punctuation\">.<\/span>setItemWidget<span class=\"token punctuation\">(<\/span>item<span class=\"token punctuation\">,<\/span> <span class=\"token number\">2<\/span><span class=\"token punctuation\">,<\/span> progress<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_progress_map<span class=\"token punctuation\">[<\/span>filename<span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">(<\/span>item<span class=\"token punctuation\">,<\/span> progress<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">update_progress<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> filename<span class=\"token punctuation\">,<\/span> transferred<span class=\"token punctuation\">,<\/span> total<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> filename <span class=\"token keyword\">in<\/span> self<span class=\"token punctuation\">.<\/span>_progress_map<span class=\"token punctuation\">:<\/span><br \/>\n            item<span class=\"token punctuation\">,<\/span> progress <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>_progress_map<span class=\"token punctuation\">[<\/span>filename<span class=\"token punctuation\">]<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> total <span class=\"token operator\">&gt;<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                pct <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">int<\/span><span class=\"token punctuation\">(<\/span>transferred <span class=\"token operator\">*<\/span> <span class=\"token number\">100<\/span> <span class=\"token operator\">\/<\/span> total<span class=\"token punctuation\">)<\/span><br \/>\n                progress<span class=\"token punctuation\">.<\/span>setValue<span class=\"token punctuation\">(<\/span>pct<span class=\"token punctuation\">)<\/span><br \/>\n                item<span class=\"token punctuation\">.<\/span>setText<span class=\"token punctuation\">(<\/span><span class=\"token number\">2<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>pct<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">%&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n            item<span class=\"token punctuation\">.<\/span>setText<span class=\"token punctuation\">(<\/span><span class=\"token number\">3<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u4f20\u8f93\u4e2d&#8230;&#034;<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">complete_transfer<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> filename<span class=\"token punctuation\">,<\/span> success<span class=\"token punctuation\">,<\/span> message<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> filename <span class=\"token keyword\">in<\/span> self<span class=\"token punctuation\">.<\/span>_progress_map<span class=\"token punctuation\">:<\/span><br \/>\n            item<span class=\"token punctuation\">,<\/span> progress <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>_progress_map<span class=\"token punctuation\">[<\/span>filename<span class=\"token punctuation\">]<\/span><br \/>\n            progress<span class=\"token punctuation\">.<\/span>setValue<span class=\"token punctuation\">(<\/span><span class=\"token number\">100<\/span> <span class=\"token keyword\">if<\/span> success <span class=\"token keyword\">else<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            item<span class=\"token punctuation\">.<\/span>setText<span class=\"token punctuation\">(<\/span><span class=\"token number\">2<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u5b8c\u6210&#034;<\/span> <span class=\"token keyword\">if<\/span> success <span class=\"token keyword\">else<\/span> <span class=\"token string\">&#034;\u5931\u8d25&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            item<span class=\"token punctuation\">.<\/span>setText<span class=\"token punctuation\">(<\/span><span class=\"token number\">3<\/span><span class=\"token punctuation\">,<\/span> message<span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> success<span class=\"token punctuation\">:<\/span><br \/>\n                item<span class=\"token punctuation\">.<\/span>setForeground<span class=\"token punctuation\">(<\/span><span class=\"token number\">3<\/span><span class=\"token punctuation\">,<\/span> QColor<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;#2ecc71&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                item<span class=\"token punctuation\">.<\/span>setForeground<span class=\"token punctuation\">(<\/span><span class=\"token number\">3<\/span><span class=\"token punctuation\">,<\/span> QColor<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;#e74c3c&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">clear_completed<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        items_to_remove <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><br \/>\n        <span class=\"token keyword\">for<\/span> i <span class=\"token keyword\">in<\/span> <span class=\"token builtin\">range<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>transfer_list<span class=\"token punctuation\">.<\/span>topLevelItemCount<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            item <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>transfer_list<span class=\"token punctuation\">.<\/span>topLevelItem<span class=\"token punctuation\">(<\/span>i<span class=\"token punctuation\">)<\/span><br \/>\n            status <span class=\"token operator\">&#061;<\/span> item<span class=\"token punctuation\">.<\/span>text<span class=\"token punctuation\">(<\/span><span class=\"token number\">3<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> status <span class=\"token keyword\">in<\/span> <span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u4e0a\u4f20\u6210\u529f&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u4e0b\u8f7d\u6210\u529f&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u4e0a\u4f20\u5931\u8d25&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u4e0b\u8f7d\u5931\u8d25&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                items_to_remove<span class=\"token punctuation\">.<\/span>append<span class=\"token punctuation\">(<\/span>i<span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">for<\/span> i <span class=\"token keyword\">in<\/span> <span class=\"token builtin\">reversed<\/span><span class=\"token punctuation\">(<\/span>items_to_remove<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>transfer_list<span class=\"token punctuation\">.<\/span>takeTopLevelItem<span class=\"token punctuation\">(<\/span>i<span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token comment\"># &#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;<\/span><br \/>\n<span class=\"token comment\">#  \u8c03\u8bd5\u63a7\u5236\u53f0 Widget<\/span><br \/>\n<span class=\"token comment\"># &#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;<\/span><br \/>\n<span class=\"token keyword\">class<\/span> <span class=\"token class-name\">DebugConsoleWidget<\/span><span class=\"token punctuation\">(<\/span>QWidget<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    command_submitted <span class=\"token operator\">&#061;<\/span> pyqtSignal<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">)<\/span>  <span class=\"token comment\"># \u7528\u6237\u8f93\u5165\u7684\u539f\u59cb\u547d\u4ee4<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">__init__<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> parent<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">None<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token builtin\">super<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>__init__<span class=\"token punctuation\">(<\/span>parent<span class=\"token punctuation\">)<\/span><br \/>\n        layout <span class=\"token operator\">&#061;<\/span> QVBoxLayout<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><br \/>\n        layout<span class=\"token punctuation\">.<\/span>setContentsMargins<span class=\"token punctuation\">(<\/span><span class=\"token number\">4<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">4<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">4<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">4<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u6807\u9898\u884c<\/span><br \/>\n        header <span class=\"token operator\">&#061;<\/span> QHBoxLayout<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        title <span class=\"token operator\">&#061;<\/span> QLabel<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;&lt;b&gt;\u8c03\u8bd5\u63a7\u5236\u53f0&lt;\/b&gt;&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        header<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>title<span class=\"token punctuation\">)<\/span><br \/>\n        header<span class=\"token punctuation\">.<\/span>addStretch<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        clear_btn <span class=\"token operator\">&#061;<\/span> QPushButton<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u6e05\u7a7a&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        clear_btn<span class=\"token punctuation\">.<\/span>setFixedWidth<span class=\"token punctuation\">(<\/span><span class=\"token number\">60<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        clear_btn<span class=\"token punctuation\">.<\/span>clicked<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>clear_log<span class=\"token punctuation\">)<\/span><br \/>\n        header<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>clear_btn<span class=\"token punctuation\">)<\/span><\/p>\n<p>        save_btn <span class=\"token operator\">&#061;<\/span> QPushButton<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u4fdd\u5b58\u65e5\u5fd7&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        save_btn<span class=\"token punctuation\">.<\/span>setFixedWidth<span class=\"token punctuation\">(<\/span><span class=\"token number\">80<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        save_btn<span class=\"token punctuation\">.<\/span>clicked<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>save_log<span class=\"token punctuation\">)<\/span><br \/>\n        header<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>save_btn<span class=\"token punctuation\">)<\/span><\/p>\n<p>        layout<span class=\"token punctuation\">.<\/span>addLayout<span class=\"token punctuation\">(<\/span>header<span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u65e5\u5fd7\u663e\u793a\u533a<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>log_text <span class=\"token operator\">&#061;<\/span> QTextEdit<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>log_text<span class=\"token punctuation\">.<\/span>setReadOnly<span class=\"token punctuation\">(<\/span><span class=\"token boolean\">True<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>log_text<span class=\"token punctuation\">.<\/span>setFont<span class=\"token punctuation\">(<\/span>QFont<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;Consolas&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">9<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>log_text<span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u547d\u4ee4\u8f93\u5165\u884c<\/span><br \/>\n        cmd_layout <span class=\"token operator\">&#061;<\/span> QHBoxLayout<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        cmd_label <span class=\"token operator\">&#061;<\/span> QLabel<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;FTP \u547d\u4ee4:&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        cmd_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>cmd_label<span class=\"token punctuation\">)<\/span><\/p>\n<p>        self<span class=\"token punctuation\">.<\/span>cmd_input <span class=\"token operator\">&#061;<\/span> QLineEdit<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>cmd_input<span class=\"token punctuation\">.<\/span>setPlaceholderText<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u8f93\u5165 FTP \u547d\u4ee4&#xff0c;\u5982: LIST \/, SIZE file.txt, MKD newdir, PWD &#8230;&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>cmd_input<span class=\"token punctuation\">.<\/span>setFont<span class=\"token punctuation\">(<\/span>QFont<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;Consolas&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">10<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>cmd_input<span class=\"token punctuation\">.<\/span>returnPressed<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_on_send_command<span class=\"token punctuation\">)<\/span><br \/>\n        cmd_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>cmd_input<span class=\"token punctuation\">)<\/span><\/p>\n<p>        send_btn <span class=\"token operator\">&#061;<\/span> QPushButton<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u53d1\u9001&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        send_btn<span class=\"token punctuation\">.<\/span>setFixedWidth<span class=\"token punctuation\">(<\/span><span class=\"token number\">60<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        send_btn<span class=\"token punctuation\">.<\/span>clicked<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_on_send_command<span class=\"token punctuation\">)<\/span><br \/>\n        cmd_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>send_btn<span class=\"token punctuation\">)<\/span><\/p>\n<p>        layout<span class=\"token punctuation\">.<\/span>addLayout<span class=\"token punctuation\">(<\/span>cmd_layout<span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u547d\u4ee4\u5386\u53f2<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_cmd_history <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_history_idx <span class=\"token operator\">&#061;<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token number\">1<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">append_log<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> category<span class=\"token punctuation\">,<\/span> message<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u6dfb\u52a0\u65e5\u5fd7\u6d88\u606f&#034;&#034;&#034;<\/span><br \/>\n        timestamp <span class=\"token operator\">&#061;<\/span> datetime<span class=\"token punctuation\">.<\/span>now<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>strftime<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;%H:%M:%S&#034;<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        color_map <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n            <span class=\"token string\">&#034;cmd&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;#e67e22&#034;<\/span><span class=\"token punctuation\">,<\/span>     <span class=\"token comment\"># \u6a59\u8272 &#8211; \u53d1\u9001\u7684\u547d\u4ee4<\/span><br \/>\n            <span class=\"token string\">&#034;resp&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;#3498db&#034;<\/span><span class=\"token punctuation\">,<\/span>    <span class=\"token comment\"># \u84dd\u8272 &#8211; \u670d\u52a1\u5668\u54cd\u5e94<\/span><br \/>\n            <span class=\"token string\">&#034;info&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;#95a5a6&#034;<\/span><span class=\"token punctuation\">,<\/span>    <span class=\"token comment\"># \u7070\u8272 &#8211; \u4fe1\u606f<\/span><br \/>\n            <span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;#e74c3c&#034;<\/span><span class=\"token punctuation\">,<\/span>   <span class=\"token comment\"># \u7ea2\u8272 &#8211; \u9519\u8bef<\/span><br \/>\n            <span class=\"token string\">&#034;success&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;#2ecc71&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token comment\"># \u7eff\u8272 &#8211; \u6210\u529f<\/span><br \/>\n        <span class=\"token punctuation\">}<\/span><\/p>\n<p>        prefix_map <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">{<\/span><br \/>\n            <span class=\"token string\">&#034;cmd&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;&gt;&gt;&gt;&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n            <span class=\"token string\">&#034;resp&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034;&lt;&lt;&lt;&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n            <span class=\"token string\">&#034;info&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034; \u2139\ufe0f&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n            <span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034; \u274c&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n            <span class=\"token string\">&#034;success&#034;<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">&#034; \u2705&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        <span class=\"token punctuation\">}<\/span><\/p>\n<p>        color <span class=\"token operator\">&#061;<\/span> color_map<span class=\"token punctuation\">.<\/span>get<span class=\"token punctuation\">(<\/span>category<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;#333333&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        prefix <span class=\"token operator\">&#061;<\/span> prefix_map<span class=\"token punctuation\">.<\/span>get<span class=\"token punctuation\">(<\/span>category<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;   &#034;<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        html <span class=\"token operator\">&#061;<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#039;&lt;span style&#061;&#034;color:#888;&#034;&gt;[<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>timestamp<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">]&lt;\/span&gt; &#039;<\/span><\/span><br \/>\n        html <span class=\"token operator\">&#043;&#061;<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#039;&lt;span style&#061;&#034;color:<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>color<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">;font-weight:bold;&#034;&gt;<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>prefix<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&lt;\/span&gt; &#039;<\/span><\/span><br \/>\n        html <span class=\"token operator\">&#043;&#061;<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#039;&lt;span style&#061;&#034;color:<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>color<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">;&#034;&gt;<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>self<span class=\"token punctuation\">.<\/span>_escape_html<span class=\"token punctuation\">(<\/span>message<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&lt;\/span&gt;&#039;<\/span><\/span><\/p>\n<p>        self<span class=\"token punctuation\">.<\/span>log_text<span class=\"token punctuation\">.<\/span>append<span class=\"token punctuation\">(<\/span>html<span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token comment\"># \u81ea\u52a8\u6eda\u52a8\u5230\u5e95\u90e8<\/span><br \/>\n        scrollbar <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>log_text<span class=\"token punctuation\">.<\/span>verticalScrollBar<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        scrollbar<span class=\"token punctuation\">.<\/span>setValue<span class=\"token punctuation\">(<\/span>scrollbar<span class=\"token punctuation\">.<\/span>maximum<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">clear_log<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>log_text<span class=\"token punctuation\">.<\/span>clear<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">save_log<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        path<span class=\"token punctuation\">,<\/span> _ <span class=\"token operator\">&#061;<\/span> QFileDialog<span class=\"token punctuation\">.<\/span>getSaveFileName<span class=\"token punctuation\">(<\/span><br \/>\n            self<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u4fdd\u5b58\u65e5\u5fd7&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;ftp_debug_log.txt&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n            <span class=\"token string\">&#034;\u6587\u672c\u6587\u4ef6 (*.txt);;\u6240\u6709\u6587\u4ef6 (*)&#034;<\/span><br \/>\n        <span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> path<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">with<\/span> <span class=\"token builtin\">open<\/span><span class=\"token punctuation\">(<\/span>path<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;w&#034;<\/span><span class=\"token punctuation\">,<\/span> encoding<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;utf-8&#034;<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">as<\/span> f<span class=\"token punctuation\">:<\/span><br \/>\n                f<span class=\"token punctuation\">.<\/span>write<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>log_text<span class=\"token punctuation\">.<\/span>toPlainText<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_on_send_command<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        cmd <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>cmd_input<span class=\"token punctuation\">.<\/span>text<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>strip<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> cmd<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>_cmd_history<span class=\"token punctuation\">.<\/span>insert<span class=\"token punctuation\">(<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> cmd<span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>_history_idx <span class=\"token operator\">&#061;<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token number\">1<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>command_submitted<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>cmd<span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>cmd_input<span class=\"token punctuation\">.<\/span>clear<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">keyPressEvent<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> event<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> event<span class=\"token punctuation\">.<\/span>key<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&#061;<\/span> Qt<span class=\"token punctuation\">.<\/span>Key<span class=\"token punctuation\">.<\/span>Key_Up<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> self<span class=\"token punctuation\">.<\/span>_cmd_history<span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>_history_idx <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">min<\/span><span class=\"token punctuation\">(<\/span><br \/>\n                    self<span class=\"token punctuation\">.<\/span>_history_idx <span class=\"token operator\">&#043;<\/span> <span class=\"token number\">1<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">len<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_cmd_history<span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#8211;<\/span> <span class=\"token number\">1<\/span><br \/>\n                <span class=\"token punctuation\">)<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>cmd_input<span class=\"token punctuation\">.<\/span>setText<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_cmd_history<span class=\"token punctuation\">[<\/span>self<span class=\"token punctuation\">.<\/span>_history_idx<span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">elif<\/span> event<span class=\"token punctuation\">.<\/span>key<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&#061;<\/span> Qt<span class=\"token punctuation\">.<\/span>Key<span class=\"token punctuation\">.<\/span>Key_Down<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> self<span class=\"token punctuation\">.<\/span>_cmd_history <span class=\"token keyword\">and<\/span> self<span class=\"token punctuation\">.<\/span>_history_idx <span class=\"token operator\">&gt;<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>_history_idx <span class=\"token operator\">-&#061;<\/span> <span class=\"token number\">1<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>cmd_input<span class=\"token punctuation\">.<\/span>setText<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_cmd_history<span class=\"token punctuation\">[<\/span>self<span class=\"token punctuation\">.<\/span>_history_idx<span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">elif<\/span> self<span class=\"token punctuation\">.<\/span>_history_idx <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>_history_idx <span class=\"token operator\">&#061;<\/span> <span class=\"token operator\">&#8211;<\/span><span class=\"token number\">1<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>cmd_input<span class=\"token punctuation\">.<\/span>clear<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token builtin\">super<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>keyPressEvent<span class=\"token punctuation\">(<\/span>event<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token decorator annotation punctuation\">&#064;staticmethod<\/span><br \/>\n    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_escape_html<\/span><span class=\"token punctuation\">(<\/span>text<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">return<\/span> text<span class=\"token punctuation\">.<\/span>replace<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;&amp;&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;&amp;amp;&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>replace<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;&lt;&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;&amp;lt;&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>replace<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;&gt;&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;&amp;gt;&#034;<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token comment\"># &#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;<\/span><br \/>\n<span class=\"token comment\">#  \u4e3b\u7a97\u53e3<\/span><br \/>\n<span class=\"token comment\"># &#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;<\/span><br \/>\n<span class=\"token keyword\">class<\/span> <span class=\"token class-name\">MainWindow<\/span><span class=\"token punctuation\">(<\/span>QMainWindow<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token keyword\">def<\/span> <span class=\"token function\">__init__<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token builtin\">super<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>__init__<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>setWindowTitle<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;FTP \u5ba2\u6237\u7aef\u8c03\u8bd5\u52a9\u624b&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>setMinimumSize<span class=\"token punctuation\">(<\/span><span class=\"token number\">1100<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">750<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># FTP \u5de5\u4f5c\u7ebf\u7a0b<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>ftp_worker <span class=\"token operator\">&#061;<\/span> FtpWorkerThread<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_on_log_message<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>file_list_received<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_on_file_list_received<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>transfer_progress<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_on_transfer_progress<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>transfer_complete<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_on_transfer_complete<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>connection_changed<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_on_connection_changed<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>raw_command_result<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_on_raw_command_result<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>start<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        self<span class=\"token punctuation\">.<\/span>_init_ui<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_load_settings<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_init_ui<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        central <span class=\"token operator\">&#061;<\/span> QWidget<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>setCentralWidget<span class=\"token punctuation\">(<\/span>central<span class=\"token punctuation\">)<\/span><br \/>\n        main_layout <span class=\"token operator\">&#061;<\/span> QVBoxLayout<span class=\"token punctuation\">(<\/span>central<span class=\"token punctuation\">)<\/span><br \/>\n        main_layout<span class=\"token punctuation\">.<\/span>setContentsMargins<span class=\"token punctuation\">(<\/span><span class=\"token number\">8<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">8<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">8<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">8<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        main_layout<span class=\"token punctuation\">.<\/span>setSpacing<span class=\"token punctuation\">(<\/span><span class=\"token number\">6<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># &#8212;- 1. \u8fde\u63a5\u7ba1\u7406 &#043; \u670d\u52a1\u5668\u63a7\u5236 &#8212;-<\/span><br \/>\n        conn_group <span class=\"token operator\">&#061;<\/span> QGroupBox<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u8fde\u63a5\u7ba1\u7406&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        conn_layout <span class=\"token operator\">&#061;<\/span> QGridLayout<span class=\"token punctuation\">(<\/span>conn_group<span class=\"token punctuation\">)<\/span><br \/>\n        conn_layout<span class=\"token punctuation\">.<\/span>setContentsMargins<span class=\"token punctuation\">(<\/span><span class=\"token number\">8<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">12<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">8<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">8<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        conn_layout<span class=\"token punctuation\">.<\/span>setHorizontalSpacing<span class=\"token punctuation\">(<\/span><span class=\"token number\">8<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        conn_layout<span class=\"token punctuation\">.<\/span>setVerticalSpacing<span class=\"token punctuation\">(<\/span><span class=\"token number\">6<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u72b6\u6001\u6307\u793a\u706f<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>status_indicator <span class=\"token operator\">&#061;<\/span> QLabel<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u25cf&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>status_indicator<span class=\"token punctuation\">.<\/span>setStyleSheet<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;color: #e74c3c; font-size: 18px;&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>status_indicator<span class=\"token punctuation\">.<\/span>setToolTip<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u672a\u8fde\u63a5&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        conn_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>status_indicator<span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u4e3b\u673a<\/span><br \/>\n        conn_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>QLabel<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u4e3b\u673a:&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">1<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>host_input <span class=\"token operator\">&#061;<\/span> QLineEdit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;127.0.0.1&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>host_input<span class=\"token punctuation\">.<\/span>setFixedWidth<span class=\"token punctuation\">(<\/span><span class=\"token number\">150<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        conn_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>host_input<span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">2<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u7aef\u53e3<\/span><br \/>\n        conn_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>QLabel<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u7aef\u53e3:&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">3<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>port_input <span class=\"token operator\">&#061;<\/span> QLineEdit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;2121&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>port_input<span class=\"token punctuation\">.<\/span>setFixedWidth<span class=\"token punctuation\">(<\/span><span class=\"token number\">70<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        conn_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>port_input<span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">4<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u7528\u6237\u540d<\/span><br \/>\n        conn_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>QLabel<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u7528\u6237\u540d:&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">5<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>user_input <span class=\"token operator\">&#061;<\/span> QLineEdit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;admin&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>user_input<span class=\"token punctuation\">.<\/span>setFixedWidth<span class=\"token punctuation\">(<\/span><span class=\"token number\">100<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        conn_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>user_input<span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">6<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u5bc6\u7801<\/span><br \/>\n        conn_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>QLabel<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u5bc6\u7801:&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">7<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>pass_input <span class=\"token operator\">&#061;<\/span> QLineEdit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;123456&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>pass_input<span class=\"token punctuation\">.<\/span>setEchoMode<span class=\"token punctuation\">(<\/span>QLineEdit<span class=\"token punctuation\">.<\/span>EchoMode<span class=\"token punctuation\">.<\/span>Password<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>pass_input<span class=\"token punctuation\">.<\/span>setFixedWidth<span class=\"token punctuation\">(<\/span><span class=\"token number\">100<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        conn_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>pass_input<span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">8<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u8fde\u63a5\/\u65ad\u5f00\u6309\u94ae<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>connect_btn <span class=\"token operator\">&#061;<\/span> QPushButton<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u8fde\u63a5&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>connect_btn<span class=\"token punctuation\">.<\/span>setFixedWidth<span class=\"token punctuation\">(<\/span><span class=\"token number\">70<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>connect_btn<span class=\"token punctuation\">.<\/span>setStyleSheet<span class=\"token punctuation\">(<\/span><br \/>\n            <span class=\"token string\">&#034;QPushButton { background-color: #2ecc71; color: white; &#034;<\/span><br \/>\n            <span class=\"token string\">&#034;font-weight: bold; border-radius: 4px; padding: 4px; }&#034;<\/span><br \/>\n            <span class=\"token string\">&#034;QPushButton:hover { background-color: #27ae60; }&#034;<\/span><br \/>\n        <span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>connect_btn<span class=\"token punctuation\">.<\/span>clicked<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_on_connect<span class=\"token punctuation\">)<\/span><br \/>\n        conn_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>connect_btn<span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">9<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        self<span class=\"token punctuation\">.<\/span>disconnect_btn <span class=\"token operator\">&#061;<\/span> QPushButton<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u65ad\u5f00&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>disconnect_btn<span class=\"token punctuation\">.<\/span>setFixedWidth<span class=\"token punctuation\">(<\/span><span class=\"token number\">70<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>disconnect_btn<span class=\"token punctuation\">.<\/span>setEnabled<span class=\"token punctuation\">(<\/span><span class=\"token boolean\">False<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>disconnect_btn<span class=\"token punctuation\">.<\/span>setStyleSheet<span class=\"token punctuation\">(<\/span><br \/>\n            <span class=\"token string\">&#034;QPushButton { background-color: #e74c3c; color: white; &#034;<\/span><br \/>\n            <span class=\"token string\">&#034;font-weight: bold; border-radius: 4px; padding: 4px; }&#034;<\/span><br \/>\n            <span class=\"token string\">&#034;QPushButton:hover { background-color: #c0392b; }&#034;<\/span><br \/>\n            <span class=\"token string\">&#034;QPushButton:disabled { background-color: #bdc3c7; }&#034;<\/span><br \/>\n        <span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>disconnect_btn<span class=\"token punctuation\">.<\/span>clicked<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_on_disconnect<span class=\"token punctuation\">)<\/span><br \/>\n        conn_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>disconnect_btn<span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">10<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        conn_layout<span class=\"token punctuation\">.<\/span>setColumnStretch<span class=\"token punctuation\">(<\/span><span class=\"token number\">11<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">1<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        main_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>conn_group<span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># &#8212;- 2. \u6587\u4ef6\u6d4f\u89c8\u5668&#xff08;\u53cc\u680f&#xff09; &#8212;-<\/span><br \/>\n        file_splitter <span class=\"token operator\">&#061;<\/span> QSplitter<span class=\"token punctuation\">(<\/span>Qt<span class=\"token punctuation\">.<\/span>Orientation<span class=\"token punctuation\">.<\/span>Horizontal<span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u672c\u5730\u6587\u4ef6\u6d4f\u89c8\u5668&#xff08;\u5de6\u4fa7&#xff09;<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>local_browser <span class=\"token operator\">&#061;<\/span> FileBrowserWidget<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u672c\u5730\u6587\u4ef6&#034;<\/span><span class=\"token punctuation\">,<\/span> is_remote<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">False<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>local_browser<span class=\"token punctuation\">.<\/span>file_selected<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_on_local_file_action<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>local_browser<span class=\"token punctuation\">.<\/span>load_local_directory<span class=\"token punctuation\">(<\/span>os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>expanduser<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;~&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        local_btn_layout <span class=\"token operator\">&#061;<\/span> QHBoxLayout<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        browse_btn <span class=\"token operator\">&#061;<\/span> QPushButton<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;&#x1f4c2; \u6d4f\u89c8&#8230;&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        browse_btn<span class=\"token punctuation\">.<\/span>clicked<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_browse_local<span class=\"token punctuation\">)<\/span><br \/>\n        local_btn_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>browse_btn<span class=\"token punctuation\">)<\/span><\/p>\n<p>        refresh_local_btn <span class=\"token operator\">&#061;<\/span> QPushButton<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;&#x1f504; \u5237\u65b0&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        refresh_local_btn<span class=\"token punctuation\">.<\/span>clicked<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span><br \/>\n            <span class=\"token keyword\">lambda<\/span><span class=\"token punctuation\">:<\/span> self<span class=\"token punctuation\">.<\/span>local_browser<span class=\"token punctuation\">.<\/span>load_local_directory<span class=\"token punctuation\">(<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>local_browser<span class=\"token punctuation\">.<\/span>current_path<br \/>\n            <span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token punctuation\">)<\/span><br \/>\n        local_btn_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>refresh_local_btn<span class=\"token punctuation\">)<\/span><br \/>\n        local_btn_layout<span class=\"token punctuation\">.<\/span>addStretch<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        local_container <span class=\"token operator\">&#061;<\/span> QWidget<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        local_container_layout <span class=\"token operator\">&#061;<\/span> QVBoxLayout<span class=\"token punctuation\">(<\/span>local_container<span class=\"token punctuation\">)<\/span><br \/>\n        local_container_layout<span class=\"token punctuation\">.<\/span>setContentsMargins<span class=\"token punctuation\">(<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        local_container_layout<span class=\"token punctuation\">.<\/span>setSpacing<span class=\"token punctuation\">(<\/span><span class=\"token number\">2<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        local_container_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>local_browser<span class=\"token punctuation\">)<\/span><br \/>\n        local_container_layout<span class=\"token punctuation\">.<\/span>addLayout<span class=\"token punctuation\">(<\/span>local_btn_layout<span class=\"token punctuation\">)<\/span><\/p>\n<p>        file_splitter<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>local_container<span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u8fdc\u7a0b\u6587\u4ef6\u6d4f\u89c8\u5668&#xff08;\u53f3\u4fa7&#xff09;<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>remote_browser <span class=\"token operator\">&#061;<\/span> FileBrowserWidget<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u8fdc\u7a0b\u6587\u4ef6&#034;<\/span><span class=\"token punctuation\">,<\/span> is_remote<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">True<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>remote_browser<span class=\"token punctuation\">.<\/span>file_selected<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_on_remote_file_action<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>remote_browser<span class=\"token punctuation\">.<\/span>file_delete_requested<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>_on_remote_delete_request<br \/>\n        <span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u4e0a\u4e00\u7ea7 &#043; \u5237\u65b0\u6309\u94ae<\/span><br \/>\n        remote_btn_layout <span class=\"token operator\">&#061;<\/span> QHBoxLayout<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        up_remote_btn <span class=\"token operator\">&#061;<\/span> QPushButton<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u2b06\ufe0f \u4e0a\u4e00\u7ea7&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        up_remote_btn<span class=\"token punctuation\">.<\/span>clicked<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_go_up_remote<span class=\"token punctuation\">)<\/span><br \/>\n        remote_btn_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>up_remote_btn<span class=\"token punctuation\">)<\/span><\/p>\n<p>        refresh_remote_btn <span class=\"token operator\">&#061;<\/span> QPushButton<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;&#x1f504; \u5237\u65b0&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        refresh_remote_btn<span class=\"token punctuation\">.<\/span>clicked<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>_refresh_remote<span class=\"token punctuation\">)<\/span><br \/>\n        remote_btn_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>refresh_remote_btn<span class=\"token punctuation\">)<\/span><br \/>\n        remote_btn_layout<span class=\"token punctuation\">.<\/span>addStretch<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        remote_container <span class=\"token operator\">&#061;<\/span> QWidget<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        remote_container_layout <span class=\"token operator\">&#061;<\/span> QVBoxLayout<span class=\"token punctuation\">(<\/span>remote_container<span class=\"token punctuation\">)<\/span><br \/>\n        remote_container_layout<span class=\"token punctuation\">.<\/span>setContentsMargins<span class=\"token punctuation\">(<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        remote_container_layout<span class=\"token punctuation\">.<\/span>setSpacing<span class=\"token punctuation\">(<\/span><span class=\"token number\">2<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        remote_container_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>remote_browser<span class=\"token punctuation\">)<\/span><br \/>\n        remote_container_layout<span class=\"token punctuation\">.<\/span>addLayout<span class=\"token punctuation\">(<\/span>remote_btn_layout<span class=\"token punctuation\">)<\/span><\/p>\n<p>        file_splitter<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>remote_container<span class=\"token punctuation\">)<\/span><\/p>\n<p>        file_splitter<span class=\"token punctuation\">.<\/span>setStretchFactor<span class=\"token punctuation\">(<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">1<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        file_splitter<span class=\"token punctuation\">.<\/span>setStretchFactor<span class=\"token punctuation\">(<\/span><span class=\"token number\">1<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">1<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        main_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>file_splitter<span class=\"token punctuation\">,<\/span> stretch<span class=\"token operator\">&#061;<\/span><span class=\"token number\">3<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># &#8212;- 3. \u4f20\u8f93\u961f\u5217 &#8212;-<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>transfer_widget <span class=\"token operator\">&#061;<\/span> TransferWidget<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        main_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>transfer_widget<span class=\"token punctuation\">,<\/span> stretch<span class=\"token operator\">&#061;<\/span><span class=\"token number\">1<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># &#8212;- 4. \u8c03\u8bd5\u63a7\u5236\u53f0 &#8212;-<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>debug_console <span class=\"token operator\">&#061;<\/span> DebugConsoleWidget<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token comment\"># \u5c06\u8c03\u8bd5\u63a7\u5236\u53f0\u7684\u547d\u4ee4\u63d0\u4ea4\u4fe1\u53f7\u8fde\u63a5\u5230\u5de5\u4f5c\u7ebf\u7a0b<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>debug_console<span class=\"token punctuation\">.<\/span>command_submitted<span class=\"token punctuation\">.<\/span>connect<span class=\"token punctuation\">(<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>execute_raw_command<br \/>\n        <span class=\"token punctuation\">)<\/span><br \/>\n        main_layout<span class=\"token punctuation\">.<\/span>addWidget<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>debug_console<span class=\"token punctuation\">,<\/span> stretch<span class=\"token operator\">&#061;<\/span><span class=\"token number\">2<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># &#8212;- \u72b6\u6001\u680f &#8212;-<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>statusBar<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>showMessage<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u5c31\u7eea&#034;<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token comment\"># &#8212;- \u8fde\u63a5\u64cd\u4f5c &#8212;-<\/span><br \/>\n    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_on_connect<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        host <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>host_input<span class=\"token punctuation\">.<\/span>text<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>strip<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        port <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>port_input<span class=\"token punctuation\">.<\/span>text<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>strip<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        user <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>user_input<span class=\"token punctuation\">.<\/span>text<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>strip<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        password <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>pass_input<span class=\"token punctuation\">.<\/span>text<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>strip<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> host <span class=\"token keyword\">or<\/span> <span class=\"token keyword\">not<\/span> port<span class=\"token punctuation\">:<\/span><br \/>\n            QMessageBox<span class=\"token punctuation\">.<\/span>warning<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u63d0\u793a&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u8bf7\u8f93\u5165\u4e3b\u673a\u5730\u5740\u548c\u7aef\u53e3&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">return<\/span><\/p>\n<p>        self<span class=\"token punctuation\">.<\/span>connect_btn<span class=\"token punctuation\">.<\/span>setEnabled<span class=\"token punctuation\">(<\/span><span class=\"token boolean\">False<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>statusBar<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>showMessage<span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u6b63\u5728\u8fde\u63a5 <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>host<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">:<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>port<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#8230;&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>connect_to_server<span class=\"token punctuation\">(<\/span>host<span class=\"token punctuation\">,<\/span> port<span class=\"token punctuation\">,<\/span> user<span class=\"token punctuation\">,<\/span> password<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_on_disconnect<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>disconnect_from_server<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>remote_browser<span class=\"token punctuation\">.<\/span>tree<span class=\"token punctuation\">.<\/span>clear<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>remote_browser<span class=\"token punctuation\">.<\/span>path_label<span class=\"token punctuation\">.<\/span>clear<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_on_connection_changed<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> connected<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>connect_btn<span class=\"token punctuation\">.<\/span>setEnabled<span class=\"token punctuation\">(<\/span><span class=\"token keyword\">not<\/span> connected<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>disconnect_btn<span class=\"token punctuation\">.<\/span>setEnabled<span class=\"token punctuation\">(<\/span>connected<span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token keyword\">if<\/span> connected<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>status_indicator<span class=\"token punctuation\">.<\/span>setStyleSheet<span class=\"token punctuation\">(<\/span><br \/>\n                <span class=\"token string\">&#034;color: #2ecc71; font-size: 18px;&#034;<\/span><br \/>\n            <span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>status_indicator<span class=\"token punctuation\">.<\/span>setToolTip<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u5df2\u8fde\u63a5&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>statusBar<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>showMessage<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u5df2\u8fde\u63a5&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>status_indicator<span class=\"token punctuation\">.<\/span>setStyleSheet<span class=\"token punctuation\">(<\/span><br \/>\n                <span class=\"token string\">&#034;color: #e74c3c; font-size: 18px;&#034;<\/span><br \/>\n            <span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>status_indicator<span class=\"token punctuation\">.<\/span>setToolTip<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u672a\u8fde\u63a5&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>statusBar<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>showMessage<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u5df2\u65ad\u5f00&#034;<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token comment\"># &#8212;- \u6587\u4ef6\u6d4f\u89c8 &#8212;-<\/span><br \/>\n    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_on_file_list_received<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> items<span class=\"token punctuation\">,<\/span> current_path<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>remote_browser<span class=\"token punctuation\">.<\/span>set_file_list<span class=\"token punctuation\">(<\/span>items<span class=\"token punctuation\">,<\/span> current_path<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>statusBar<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>showMessage<span class=\"token punctuation\">(<\/span><br \/>\n            <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u8fdc\u7a0b\u76ee\u5f55: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>current_path<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> (<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span><span class=\"token builtin\">len<\/span><span class=\"token punctuation\">(<\/span>items<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> \u4e2a\u9879\u76ee)&#034;<\/span><\/span><br \/>\n        <span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_on_remote_file_action<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> name<span class=\"token punctuation\">,<\/span> is_dir<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> is_dir<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> name <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;..&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>change_directory<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;..&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>change_directory<span class=\"token punctuation\">(<\/span>name<span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token comment\"># \u6587\u4ef6\u88ab\u9009\u4e2d \u2014 \u5f39\u51fa\u4e0b\u8f7d\u5bf9\u8bdd\u6846<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>_prompt_download<span class=\"token punctuation\">(<\/span>name<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_on_remote_delete_request<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> name<span class=\"token punctuation\">,<\/span> is_dir<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        kind <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;\u76ee\u5f55&#034;<\/span> <span class=\"token keyword\">if<\/span> is_dir <span class=\"token keyword\">else<\/span> <span class=\"token string\">&#034;\u6587\u4ef6&#034;<\/span><br \/>\n        reply <span class=\"token operator\">&#061;<\/span> QMessageBox<span class=\"token punctuation\">.<\/span>question<span class=\"token punctuation\">(<\/span><br \/>\n            self<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u786e\u8ba4\u5220\u9664&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n            <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u786e\u5b9a\u8981\u5220\u9664\u8fdc\u7a0b<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>kind<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">\u5417&#xff1f;\\\\n\\\\n\u540d\u79f0: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>name<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">\\\\n\\\\n&#034;<\/span><\/span><br \/>\n            <span class=\"token string\">&#034;\u6ce8\u610f: \u6b64\u64cd\u4f5c\u4e0d\u53ef\u6062\u590d\u3002&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n            QMessageBox<span class=\"token punctuation\">.<\/span>StandardButton<span class=\"token punctuation\">.<\/span>Yes <span class=\"token operator\">|<\/span> QMessageBox<span class=\"token punctuation\">.<\/span>StandardButton<span class=\"token punctuation\">.<\/span>No<br \/>\n        <span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> reply <span class=\"token operator\">&#061;&#061;<\/span> QMessageBox<span class=\"token punctuation\">.<\/span>StandardButton<span class=\"token punctuation\">.<\/span>Yes<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> is_dir<span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>delete_directory<span class=\"token punctuation\">(<\/span>name<span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>delete_file<span class=\"token punctuation\">(<\/span>name<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_on_local_file_action<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> name<span class=\"token punctuation\">,<\/span> is_dir<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> is_dir<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> name <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;..&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                parent <span class=\"token operator\">&#061;<\/span> os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>dirname<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>local_browser<span class=\"token punctuation\">.<\/span>current_path<span class=\"token punctuation\">)<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>local_browser<span class=\"token punctuation\">.<\/span>load_local_directory<span class=\"token punctuation\">(<\/span>parent<span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                new_path <span class=\"token operator\">&#061;<\/span> os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>join<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>local_browser<span class=\"token punctuation\">.<\/span>current_path<span class=\"token punctuation\">,<\/span> name<span class=\"token punctuation\">)<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>local_browser<span class=\"token punctuation\">.<\/span>load_local_directory<span class=\"token punctuation\">(<\/span>new_path<span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token comment\"># \u672c\u5730\u6587\u4ef6\u88ab\u9009\u4e2d \u2014 \u5f39\u51fa\u4e0a\u4f20\u5bf9\u8bdd\u6846<\/span><br \/>\n            full_path <span class=\"token operator\">&#061;<\/span> os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>join<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>local_browser<span class=\"token punctuation\">.<\/span>current_path<span class=\"token punctuation\">,<\/span> name<span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>_prompt_upload<span class=\"token punctuation\">(<\/span>full_path<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_go_up_remote<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>change_directory<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;..&#034;<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_refresh_remote<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>list_directory<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_browse_local<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        directory <span class=\"token operator\">&#061;<\/span> QFileDialog<span class=\"token punctuation\">.<\/span>getExistingDirectory<span class=\"token punctuation\">(<\/span><br \/>\n            self<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u9009\u62e9\u672c\u5730\u76ee\u5f55&#034;<\/span><span class=\"token punctuation\">,<\/span> self<span class=\"token punctuation\">.<\/span>local_browser<span class=\"token punctuation\">.<\/span>current_path<br \/>\n        <span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> directory<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>local_browser<span class=\"token punctuation\">.<\/span>load_local_directory<span class=\"token punctuation\">(<\/span>directory<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token comment\"># &#8212;- \u6587\u4ef6\u4f20\u8f93 &#8212;-<\/span><br \/>\n    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_prompt_download<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> remote_name<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        save_path<span class=\"token punctuation\">,<\/span> _ <span class=\"token operator\">&#061;<\/span> QFileDialog<span class=\"token punctuation\">.<\/span>getSaveFileName<span class=\"token punctuation\">(<\/span><br \/>\n            self<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u4e0b\u8f7d\u6587\u4ef6&#034;<\/span><span class=\"token punctuation\">,<\/span> os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>join<span class=\"token punctuation\">(<\/span>os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>expanduser<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;~&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> remote_name<span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> save_path<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>transfer_widget<span class=\"token punctuation\">.<\/span>add_transfer<span class=\"token punctuation\">(<\/span>remote_name<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;download&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>download_file<span class=\"token punctuation\">(<\/span>remote_name<span class=\"token punctuation\">,<\/span> save_path<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_prompt_upload<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> local_path<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        remote_name <span class=\"token operator\">&#061;<\/span> os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>basename<span class=\"token punctuation\">(<\/span>local_path<span class=\"token punctuation\">)<\/span><br \/>\n        reply <span class=\"token operator\">&#061;<\/span> QMessageBox<span class=\"token punctuation\">.<\/span>question<span class=\"token punctuation\">(<\/span><br \/>\n            self<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u786e\u8ba4\u4e0a\u4f20&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n            <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u4e0a\u4f20\u6587\u4ef6\u5230\u8fdc\u7a0b\u5f53\u524d\u76ee\u5f55&#xff1f;\\\\n\\\\n\u6587\u4ef6: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>remote_name<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">,<\/span><br \/>\n            QMessageBox<span class=\"token punctuation\">.<\/span>StandardButton<span class=\"token punctuation\">.<\/span>Yes <span class=\"token operator\">|<\/span> QMessageBox<span class=\"token punctuation\">.<\/span>StandardButton<span class=\"token punctuation\">.<\/span>No<br \/>\n        <span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> reply <span class=\"token operator\">&#061;&#061;<\/span> QMessageBox<span class=\"token punctuation\">.<\/span>StandardButton<span class=\"token punctuation\">.<\/span>Yes<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>transfer_widget<span class=\"token punctuation\">.<\/span>add_transfer<span class=\"token punctuation\">(<\/span>remote_name<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;upload&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>upload_file<span class=\"token punctuation\">(<\/span>local_path<span class=\"token punctuation\">,<\/span> remote_name<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_on_transfer_progress<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> filename<span class=\"token punctuation\">,<\/span> transferred<span class=\"token punctuation\">,<\/span> total<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>transfer_widget<span class=\"token punctuation\">.<\/span>update_progress<span class=\"token punctuation\">(<\/span>filename<span class=\"token punctuation\">,<\/span> transferred<span class=\"token punctuation\">,<\/span> total<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_on_transfer_complete<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> filename<span class=\"token punctuation\">,<\/span> success<span class=\"token punctuation\">,<\/span> message<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>transfer_widget<span class=\"token punctuation\">.<\/span>complete_transfer<span class=\"token punctuation\">(<\/span>filename<span class=\"token punctuation\">,<\/span> success<span class=\"token punctuation\">,<\/span> message<span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token comment\"># \u4f20\u8f93\u5b8c\u6210\u540e\u5237\u65b0\u8fdc\u7a0b\u76ee\u5f55<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> success<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>list_directory<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token comment\"># &#8212;- \u65e5\u5fd7 &#8212;-<\/span><br \/>\n    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_on_log_message<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> category<span class=\"token punctuation\">,<\/span> message<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>debug_console<span class=\"token punctuation\">.<\/span>append_log<span class=\"token punctuation\">(<\/span>category<span class=\"token punctuation\">,<\/span> message<span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> category <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;info&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>statusBar<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>showMessage<span class=\"token punctuation\">(<\/span>message<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_on_raw_command_result<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> result<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>debug_console<span class=\"token punctuation\">.<\/span>append_log<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;resp&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;[\u547d\u4ee4\u7ed3\u679c] <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>result<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token comment\"># &#8212;- \u8bbe\u7f6e\u4fdd\u5b58\/\u52a0\u8f7d &#8212;-<\/span><br \/>\n    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_load_settings<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        settings <span class=\"token operator\">&#061;<\/span> QSettings<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;FtpDebugAssistant&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;FTPHelper&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        host <span class=\"token operator\">&#061;<\/span> settings<span class=\"token punctuation\">.<\/span>value<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;host&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;127.0.0.1&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        port <span class=\"token operator\">&#061;<\/span> settings<span class=\"token punctuation\">.<\/span>value<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;port&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;2121&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        user <span class=\"token operator\">&#061;<\/span> settings<span class=\"token punctuation\">.<\/span>value<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;user&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;admin&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>host_input<span class=\"token punctuation\">.<\/span>setText<span class=\"token punctuation\">(<\/span>host<span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>port_input<span class=\"token punctuation\">.<\/span>setText<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">(<\/span>port<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>user_input<span class=\"token punctuation\">.<\/span>setText<span class=\"token punctuation\">(<\/span>user<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_save_settings<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        settings <span class=\"token operator\">&#061;<\/span> QSettings<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;FtpDebugAssistant&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;FTPHelper&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        settings<span class=\"token punctuation\">.<\/span>setValue<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;host&#034;<\/span><span class=\"token punctuation\">,<\/span> self<span class=\"token punctuation\">.<\/span>host_input<span class=\"token punctuation\">.<\/span>text<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        settings<span class=\"token punctuation\">.<\/span>setValue<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;port&#034;<\/span><span class=\"token punctuation\">,<\/span> self<span class=\"token punctuation\">.<\/span>port_input<span class=\"token punctuation\">.<\/span>text<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        settings<span class=\"token punctuation\">.<\/span>setValue<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;user&#034;<\/span><span class=\"token punctuation\">,<\/span> self<span class=\"token punctuation\">.<\/span>user_input<span class=\"token punctuation\">.<\/span>text<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">closeEvent<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> event<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_save_settings<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>ftp_worker<span class=\"token punctuation\">.<\/span>stop<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        event<span class=\"token punctuation\">.<\/span>accept<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token comment\"># &#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;<\/span><br \/>\n<span class=\"token comment\">#  \u5165\u53e3<\/span><br \/>\n<span class=\"token comment\"># &#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;&#061;<\/span><br \/>\n<span class=\"token keyword\">if<\/span> __name__ <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;__main__&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    app <span class=\"token operator\">&#061;<\/span> QApplication<span class=\"token punctuation\">(<\/span>sys<span class=\"token punctuation\">.<\/span>argv<span class=\"token punctuation\">)<\/span><br \/>\n    app<span class=\"token punctuation\">.<\/span>setStyle<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;Fusion&#034;<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token comment\"># \u8bbe\u7f6e\u8c03\u8272\u677f<\/span><br \/>\n    palette <span class=\"token operator\">&#061;<\/span> QPalette<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    palette<span class=\"token punctuation\">.<\/span>setColor<span class=\"token punctuation\">(<\/span>QPalette<span class=\"token punctuation\">.<\/span>ColorRole<span class=\"token punctuation\">.<\/span>Window<span class=\"token punctuation\">,<\/span> QColor<span class=\"token punctuation\">(<\/span><span class=\"token number\">245<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">245<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">245<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    palette<span class=\"token punctuation\">.<\/span>setColor<span class=\"token punctuation\">(<\/span>QPalette<span class=\"token punctuation\">.<\/span>ColorRole<span class=\"token punctuation\">.<\/span>WindowText<span class=\"token punctuation\">,<\/span> QColor<span class=\"token punctuation\">(<\/span><span class=\"token number\">33<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">33<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">33<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    palette<span class=\"token punctuation\">.<\/span>setColor<span class=\"token punctuation\">(<\/span>QPalette<span class=\"token punctuation\">.<\/span>ColorRole<span class=\"token punctuation\">.<\/span>Base<span class=\"token punctuation\">,<\/span> QColor<span class=\"token punctuation\">(<\/span><span class=\"token number\">255<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">255<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">255<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    palette<span class=\"token punctuation\">.<\/span>setColor<span class=\"token punctuation\">(<\/span>QPalette<span class=\"token punctuation\">.<\/span>ColorRole<span class=\"token punctuation\">.<\/span>AlternateBase<span class=\"token punctuation\">,<\/span> QColor<span class=\"token punctuation\">(<\/span><span class=\"token number\">240<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">240<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">240<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    palette<span class=\"token punctuation\">.<\/span>setColor<span class=\"token punctuation\">(<\/span>QPalette<span class=\"token punctuation\">.<\/span>ColorRole<span class=\"token punctuation\">.<\/span>ToolTipBase<span class=\"token punctuation\">,<\/span> QColor<span class=\"token punctuation\">(<\/span><span class=\"token number\">255<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">255<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">255<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    palette<span class=\"token punctuation\">.<\/span>setColor<span class=\"token punctuation\">(<\/span>QPalette<span class=\"token punctuation\">.<\/span>ColorRole<span class=\"token punctuation\">.<\/span>ToolTipText<span class=\"token punctuation\">,<\/span> QColor<span class=\"token punctuation\">(<\/span><span class=\"token number\">33<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">33<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">33<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    palette<span class=\"token punctuation\">.<\/span>setColor<span class=\"token punctuation\">(<\/span>QPalette<span class=\"token punctuation\">.<\/span>ColorRole<span class=\"token punctuation\">.<\/span>Text<span class=\"token punctuation\">,<\/span> QColor<span class=\"token punctuation\">(<\/span><span class=\"token number\">33<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">33<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">33<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    palette<span class=\"token punctuation\">.<\/span>setColor<span class=\"token punctuation\">(<\/span>QPalette<span class=\"token punctuation\">.<\/span>ColorRole<span class=\"token punctuation\">.<\/span>Button<span class=\"token punctuation\">,<\/span> QColor<span class=\"token punctuation\">(<\/span><span class=\"token number\">240<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">240<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">240<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    palette<span class=\"token punctuation\">.<\/span>setColor<span class=\"token punctuation\">(<\/span>QPalette<span class=\"token punctuation\">.<\/span>ColorRole<span class=\"token punctuation\">.<\/span>ButtonText<span class=\"token punctuation\">,<\/span> QColor<span class=\"token punctuation\">(<\/span><span class=\"token number\">33<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">33<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">33<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    palette<span class=\"token punctuation\">.<\/span>setColor<span class=\"token punctuation\">(<\/span>QPalette<span class=\"token punctuation\">.<\/span>ColorRole<span class=\"token punctuation\">.<\/span>Highlight<span class=\"token punctuation\">,<\/span> QColor<span class=\"token punctuation\">(<\/span><span class=\"token number\">52<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">152<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">219<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    palette<span class=\"token punctuation\">.<\/span>setColor<span class=\"token punctuation\">(<\/span>QPalette<span class=\"token punctuation\">.<\/span>ColorRole<span class=\"token punctuation\">.<\/span>HighlightedText<span class=\"token punctuation\">,<\/span> QColor<span class=\"token punctuation\">(<\/span><span class=\"token number\">255<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">255<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">255<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    app<span class=\"token punctuation\">.<\/span>setPalette<span class=\"token punctuation\">(<\/span>palette<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token comment\"># \u5168\u5c40\u6837\u5f0f<\/span><br \/>\n    app<span class=\"token punctuation\">.<\/span>setStyleSheet<span class=\"token punctuation\">(<\/span><span class=\"token triple-quoted-string string\">&#034;&#034;&#034;<br \/>\n        QGroupBox {<br \/>\n            font-weight: bold;<br \/>\n            border: 1px solid #ddd;<br \/>\n            border-radius: 6px;<br \/>\n            margin-top: 10px;<br \/>\n            padding-top: 14px;<br \/>\n        }<br \/>\n        QGroupBox::title {<br \/>\n            subcontrol-origin: margin;<br \/>\n            left: 10px;<br \/>\n            padding: 0 5px;<br \/>\n        }<br \/>\n        QLineEdit {<br \/>\n            border: 1px solid #ccc;<br \/>\n            border-radius: 4px;<br \/>\n            padding: 3px 6px;<br \/>\n            background: white;<br \/>\n        }<br \/>\n        QLineEdit:focus {<br \/>\n            border-color: #3498db;<br \/>\n        }<br \/>\n        QPushButton {<br \/>\n            border: 1px solid #ccc;<br \/>\n            border-radius: 4px;<br \/>\n            padding: 4px 12px;<br \/>\n            background: #f0f0f0;<br \/>\n        }<br \/>\n        QPushButton:hover {<br \/>\n            background: #e0e0e0;<br \/>\n        }<br \/>\n        QPushButton:pressed {<br \/>\n            background: #d0d0d0;<br \/>\n        }<br \/>\n        QTreeWidget {<br \/>\n            border: 1px solid #ddd;<br \/>\n            border-radius: 4px;<br \/>\n            background: white;<br \/>\n            alternate-background-color: #f8f8f8;<br \/>\n        }<br \/>\n        QTreeWidget::item:selected {<br \/>\n            background-color: #3498db;<br \/>\n            color: white;<br \/>\n        }<br \/>\n        QHeaderView::section {<br \/>\n            background-color: #ecf0f1;<br \/>\n            padding: 4px;<br \/>\n            border: 1px solid #ddd;<br \/>\n            font-weight: bold;<br \/>\n        }<br \/>\n        QTextEdit {<br \/>\n            border: 1px solid #ddd;<br \/>\n            border-radius: 4px;<br \/>\n            background: #1e1e1e;<br \/>\n            color: #d4d4d4;<br \/>\n        }<br \/>\n        QProgressBar {<br \/>\n            border: 1px solid #ddd;<br \/>\n            border-radius: 4px;<br \/>\n            text-align: center;<br \/>\n        }<br \/>\n        QProgressBar::chunk {<br \/>\n            background-color: #3498db;<br \/>\n            border-radius: 3px;<br \/>\n        }<br \/>\n    &#034;&#034;&#034;<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    window <span class=\"token operator\">&#061;<\/span> MainWindow<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    window<span class=\"token punctuation\">.<\/span>show<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    sys<span class=\"token punctuation\">.<\/span>exit<span class=\"token punctuation\">(<\/span>app<span class=\"token punctuation\">.<\/span><span class=\"token keyword\">exec<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<h3>4\u3001ftp_server_test.py&#xff08;\u6d4b\u8bd5\u4f7f\u7528&#xff09;<\/h3>\n<p><span class=\"token triple-quoted-string string\">&#034;&#034;&#034;<br \/>\nFTP \u670d\u52a1\u5668\u6d4b\u8bd5\u4f8b\u7a0b<br \/>\n\u7528\u4e8e\u6d4b\u8bd5 FTP \u5ba2\u6237\u7aef\u8c03\u8bd5\u52a9\u624b<br \/>\n&#034;&#034;&#034;<\/span><\/p>\n<p><span class=\"token keyword\">import<\/span> os<br \/>\n<span class=\"token keyword\">import<\/span> sys<br \/>\n<span class=\"token keyword\">import<\/span> threading<br \/>\n<span class=\"token keyword\">from<\/span> pyftpdlib<span class=\"token punctuation\">.<\/span>authorizers <span class=\"token keyword\">import<\/span> DummyAuthorizer<br \/>\n<span class=\"token keyword\">from<\/span> pyftpdlib<span class=\"token punctuation\">.<\/span>handlers <span class=\"token keyword\">import<\/span> FTPHandler<br \/>\n<span class=\"token keyword\">from<\/span> pyftpdlib<span class=\"token punctuation\">.<\/span>servers <span class=\"token keyword\">import<\/span> FTPServer<\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">SimpleFTPServer<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u7b80\u5355\u7684 FTP \u670d\u52a1\u5668&#034;&#034;&#034;<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">__init__<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> host<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;127.0.0.1&#034;<\/span><span class=\"token punctuation\">,<\/span> port<span class=\"token operator\">&#061;<\/span><span class=\"token number\">2121<\/span><span class=\"token punctuation\">,<\/span> directory<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;.\/ftp_root&#034;<\/span><span class=\"token punctuation\">,<\/span><br \/>\n                 username<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;admin&#034;<\/span><span class=\"token punctuation\">,<\/span> password<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;123456&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>host <span class=\"token operator\">&#061;<\/span> host<br \/>\n        self<span class=\"token punctuation\">.<\/span>port <span class=\"token operator\">&#061;<\/span> port<br \/>\n        self<span class=\"token punctuation\">.<\/span>directory <span class=\"token operator\">&#061;<\/span> directory<br \/>\n        self<span class=\"token punctuation\">.<\/span>username <span class=\"token operator\">&#061;<\/span> username<br \/>\n        self<span class=\"token punctuation\">.<\/span>password <span class=\"token operator\">&#061;<\/span> password<br \/>\n        self<span class=\"token punctuation\">.<\/span>server <span class=\"token operator\">&#061;<\/span> <span class=\"token boolean\">None<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>running <span class=\"token operator\">&#061;<\/span> <span class=\"token boolean\">False<\/span><\/p>\n<p>        <span class=\"token comment\"># \u786e\u4fdd\u76ee\u5f55\u5b58\u5728<\/span><br \/>\n        os<span class=\"token punctuation\">.<\/span>makedirs<span class=\"token punctuation\">(<\/span>directory<span class=\"token punctuation\">,<\/span> exist_ok<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">True<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u521b\u5efa\u4e00\u4e9b\u6d4b\u8bd5\u6587\u4ef6<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_create_test_files<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">_create_test_files<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u521b\u5efa\u6d4b\u8bd5\u6587\u4ef6&#034;&#034;&#034;<\/span><br \/>\n        test_files <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><br \/>\n            <span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;test1.txt&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u8fd9\u662f\u6d4b\u8bd5\u6587\u4ef6 1&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span><br \/>\n            <span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;test2.txt&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;\u8fd9\u662f\u6d4b\u8bd5\u6587\u4ef6 2&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span><br \/>\n            <span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;readme.txt&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;FTP \u670d\u52a1\u5668\u6d4b\u8bd5\u6587\u4ef6\\\\n\u7528\u4e8e\u6d4b\u8bd5\u5ba2\u6237\u7aef\u529f\u80fd&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span><br \/>\n        <span class=\"token punctuation\">]<\/span><\/p>\n<p>        <span class=\"token keyword\">for<\/span> filename<span class=\"token punctuation\">,<\/span> content <span class=\"token keyword\">in<\/span> test_files<span class=\"token punctuation\">:<\/span><br \/>\n            filepath <span class=\"token operator\">&#061;<\/span> os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>join<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>directory<span class=\"token punctuation\">,<\/span> filename<span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>exists<span class=\"token punctuation\">(<\/span>filepath<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                <span class=\"token keyword\">with<\/span> <span class=\"token builtin\">open<\/span><span class=\"token punctuation\">(<\/span>filepath<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#039;w&#039;<\/span><span class=\"token punctuation\">,<\/span> encoding<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#039;utf-8&#039;<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">as<\/span> f<span class=\"token punctuation\">:<\/span><br \/>\n                    f<span class=\"token punctuation\">.<\/span>write<span class=\"token punctuation\">(<\/span>content<span class=\"token punctuation\">)<\/span><br \/>\n                <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u2713 \u521b\u5efa\u6d4b\u8bd5\u6587\u4ef6: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>filename<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token comment\"># \u521b\u5efa\u5b50\u76ee\u5f55<\/span><br \/>\n        subdir <span class=\"token operator\">&#061;<\/span> os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>join<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>directory<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;subdir&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        os<span class=\"token punctuation\">.<\/span>makedirs<span class=\"token punctuation\">(<\/span>subdir<span class=\"token punctuation\">,<\/span> exist_ok<span class=\"token operator\">&#061;<\/span><span class=\"token boolean\">True<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> <span class=\"token keyword\">not<\/span> os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>exists<span class=\"token punctuation\">(<\/span>os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>join<span class=\"token punctuation\">(<\/span>subdir<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;test3.txt&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">with<\/span> <span class=\"token builtin\">open<\/span><span class=\"token punctuation\">(<\/span>os<span class=\"token punctuation\">.<\/span>path<span class=\"token punctuation\">.<\/span>join<span class=\"token punctuation\">(<\/span>subdir<span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;test3.txt&#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#039;w&#039;<\/span><span class=\"token punctuation\">,<\/span> encoding<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#039;utf-8&#039;<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">as<\/span> f<span class=\"token punctuation\">:<\/span><br \/>\n                f<span class=\"token punctuation\">.<\/span>write<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u8fd9\u662f\u5b50\u76ee\u5f55\u4e2d\u7684\u6d4b\u8bd5\u6587\u4ef6&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u2713 \u521b\u5efa\u5b50\u76ee\u5f55\u548c\u6587\u4ef6: subdir\/test3.txt&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">start<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u542f\u52a8 FTP \u670d\u52a1\u5668&#034;&#034;&#034;<\/span><br \/>\n        <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token comment\"># \u521b\u5efa\u6388\u6743\u5668<\/span><br \/>\n            authorizer <span class=\"token operator\">&#061;<\/span> DummyAuthorizer<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>            <span class=\"token comment\"># \u6dfb\u52a0\u7528\u6237&#xff08;\u5b8c\u6574\u6743\u9650&#xff09;<\/span><br \/>\n            authorizer<span class=\"token punctuation\">.<\/span>add_user<span class=\"token punctuation\">(<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>username<span class=\"token punctuation\">,<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>password<span class=\"token punctuation\">,<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>directory<span class=\"token punctuation\">,<\/span><br \/>\n                perm<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;elradfmw&#034;<\/span><br \/>\n            <span class=\"token punctuation\">)<\/span><\/p>\n<p>            <span class=\"token comment\"># \u6dfb\u52a0\u533f\u540d\u7528\u6237&#xff08;\u53ea\u8bfb&#xff09;<\/span><br \/>\n            authorizer<span class=\"token punctuation\">.<\/span>add_anonymous<span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>directory<span class=\"token punctuation\">,<\/span> perm<span class=\"token operator\">&#061;<\/span><span class=\"token string\">&#034;elr&#034;<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>            <span class=\"token comment\"># \u521b\u5efa FTP \u5904\u7406\u5668<\/span><br \/>\n            handler <span class=\"token operator\">&#061;<\/span> FTPHandler<br \/>\n            handler<span class=\"token punctuation\">.<\/span>authorizer <span class=\"token operator\">&#061;<\/span> authorizer<\/p>\n<p>            <span class=\"token comment\"># \u8bbe\u7f6e\u88ab\u52a8\u6a21\u5f0f\u7aef\u53e3\u8303\u56f4<\/span><br \/>\n            handler<span class=\"token punctuation\">.<\/span>passive_ports <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">range<\/span><span class=\"token punctuation\">(<\/span><span class=\"token number\">60000<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">60100<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>            <span class=\"token comment\"># \u521b\u5efa\u670d\u52a1\u5668<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>server <span class=\"token operator\">&#061;<\/span> FTPServer<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">.<\/span>host<span class=\"token punctuation\">,<\/span> self<span class=\"token punctuation\">.<\/span>port<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> handler<span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>server<span class=\"token punctuation\">.<\/span>max_cons <span class=\"token operator\">&#061;<\/span> <span class=\"token number\">256<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>server<span class=\"token punctuation\">.<\/span>max_cons_per_ip <span class=\"token operator\">&#061;<\/span> <span class=\"token number\">5<\/span><\/p>\n<p>            self<span class=\"token punctuation\">.<\/span>running <span class=\"token operator\">&#061;<\/span> <span class=\"token boolean\">True<\/span><br \/>\n            <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\\\\n<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span><span class=\"token string\">&#039;&#061;&#039;<\/span><span class=\"token operator\">*<\/span><span class=\"token number\">60<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;FTP \u670d\u52a1\u5668\u5df2\u542f\u52a8&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span><span class=\"token string\">&#039;&#061;&#039;<\/span><span class=\"token operator\">*<\/span><span class=\"token number\">60<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u4e3b\u673a: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>self<span class=\"token punctuation\">.<\/span>host<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u7aef\u53e3: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>self<span class=\"token punctuation\">.<\/span>port<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u7528\u6237\u540d: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>self<span class=\"token punctuation\">.<\/span>username<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u5bc6\u7801: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>self<span class=\"token punctuation\">.<\/span>password<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u6839\u76ee\u5f55: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>self<span class=\"token punctuation\">.<\/span>directory<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;<\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span><span class=\"token string\">&#039;&#061;&#039;<\/span><span class=\"token operator\">*<\/span><span class=\"token number\">60<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\\\\n\u6309 Ctrl&#043;C \u505c\u6b62\u670d\u52a1\u5668\\\\n&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>            <span class=\"token comment\"># \u542f\u52a8\u670d\u52a1\u5668<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>server<span class=\"token punctuation\">.<\/span>serve_forever<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>        <span class=\"token keyword\">except<\/span> KeyboardInterrupt<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\\\\n\\\\n\u6b63\u5728\u505c\u6b62\u670d\u52a1\u5668&#8230;&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>stop<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">except<\/span> Exception <span class=\"token keyword\">as<\/span> e<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u670d\u52a1\u5668\u9519\u8bef: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>e<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>running <span class=\"token operator\">&#061;<\/span> <span class=\"token boolean\">False<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">stop<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u505c\u6b62 FTP \u670d\u52a1\u5668&#034;&#034;&#034;<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> self<span class=\"token punctuation\">.<\/span>server<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>server<span class=\"token punctuation\">.<\/span>close_all<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>running <span class=\"token operator\">&#061;<\/span> <span class=\"token boolean\">False<\/span><br \/>\n            <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u2713 \u670d\u52a1\u5668\u5df2\u505c\u6b62&#034;<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token keyword\">def<\/span> <span class=\"token function\">main<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token triple-quoted-string string\">&#034;&#034;&#034;\u4e3b\u51fd\u6570&#034;&#034;&#034;<\/span><br \/>\n    <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\\\\n&#034;<\/span> <span class=\"token operator\">&#043;<\/span> <span class=\"token string\">&#034;&#061;&#034;<\/span><span class=\"token operator\">*<\/span><span class=\"token number\">60<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;FTP \u670d\u52a1\u5668\u6d4b\u8bd5\u4f8b\u7a0b&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;&#061;&#034;<\/span><span class=\"token operator\">*<\/span><span class=\"token number\">60<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token comment\"># \u9ed8\u8ba4\u914d\u7f6e<\/span><br \/>\n    host <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;127.0.0.1&#034;<\/span><br \/>\n    port <span class=\"token operator\">&#061;<\/span> <span class=\"token number\">2121<\/span><br \/>\n    directory <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">r&#034;D:\\\\user\\\\01417804\\\\\u684c\u9762\\\\PythonProject\\\\image&#034;<\/span><br \/>\n    username <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;admin&#034;<\/span><br \/>\n    password <span class=\"token operator\">&#061;<\/span> <span class=\"token string\">&#034;123456&#034;<\/span><\/p>\n<p>    <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\\\\n\u670d\u52a1\u5668\u914d\u7f6e:&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;  \u4e3b\u673a: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>host<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> (\u56de\u8f66\u4f7f\u7528\u9ed8\u8ba4\u503c)&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n    <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;  \u7aef\u53e3: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>port<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> (\u56de\u8f66\u4f7f\u7528\u9ed8\u8ba4\u503c)&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n    <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;  \u76ee\u5f55: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>directory<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> (\u56de\u8f66\u4f7f\u7528\u9ed8\u8ba4\u503c)&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n    <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;  \u7528\u6237\u540d: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>username<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> (\u56de\u8f66\u4f7f\u7528\u9ed8\u8ba4\u503c)&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n    <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string-interpolation\"><span class=\"token string\">f&#034;  \u5bc6\u7801: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span>password<span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\"> (\u56de\u8f66\u4f7f\u7528\u9ed8\u8ba4\u503c)&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><br \/>\n    <span class=\"token keyword\">print<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token comment\"># \u83b7\u53d6\u7528\u6237\u8f93\u5165<\/span><br \/>\n    host <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">input<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u4e3b\u673a\u5730\u5740: &#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>strip<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">or<\/span> host<br \/>\n    port <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">int<\/span><span class=\"token punctuation\">(<\/span><span class=\"token builtin\">input<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u7aef\u53e3\u53f7: &#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>strip<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">or<\/span> port<span class=\"token punctuation\">)<\/span><br \/>\n    directory <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">input<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u6839\u76ee\u5f55: &#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>strip<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">or<\/span> directory<br \/>\n    username <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">input<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u7528\u6237\u540d: &#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>strip<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">or<\/span> username<br \/>\n    password <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">input<\/span><span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;\u5bc6\u7801: &#034;<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>strip<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token keyword\">or<\/span> password<\/p>\n<p>    <span class=\"token comment\"># \u521b\u5efa\u5e76\u542f\u52a8\u670d\u52a1\u5668<\/span><br \/>\n    server <span class=\"token operator\">&#061;<\/span> SimpleFTPServer<span class=\"token punctuation\">(<\/span>host<span class=\"token punctuation\">,<\/span> port<span class=\"token punctuation\">,<\/span> directory<span class=\"token punctuation\">,<\/span> username<span class=\"token punctuation\">,<\/span> password<span class=\"token punctuation\">)<\/span><br \/>\n    server<span class=\"token punctuation\">.<\/span>start<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token keyword\">if<\/span> __name__ <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;__main__&#034;<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    main<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>![\u5728\u8fd9\u91cc\u63d2\u5165\u56fe\u7247\u63cf\u8ff0](https:\/\/i-blog.csdnimg.cn\/direct\/78c60869b1d04588b9f845e062311394<\/p>\n<h2>\u4e09\u3001\u5b9e\u73b0\u539f\u7406<\/h2>\n<p>\u672c\u5de5\u5177\u7684\u6838\u5fc3\u8bbe\u8ba1\u601d\u8def\u662f&#xff1a;\u5728 ftplib.FTP \u7684\u57fa\u7840\u4e0a\u505a\u4e00\u5c42\u201c\u534f\u8bae\u7ea7\u201d\u7684\u62e6\u622a\u4e0e\u5c01\u88c5&#xff0c;\u914d\u5408 Qt \u7684\u4fe1\u53f7\u69fd\u673a\u5236&#xff0c;\u628a\u8017\u65f6\u7684\u7f51\u7edc\u64cd\u4f5c\u653e\u5230\u540e\u53f0\u7ebf\u7a0b\u6267\u884c&#xff0c;\u4ece\u800c\u65e2\u4fdd\u8bc1\u754c\u9762\u6d41\u7545&#xff0c;\u53c8\u80fd\u628a\u6bcf\u4e00\u6b21 FTP \u547d\u4ee4\u4e0e\u54cd\u5e94\u5b9e\u65f6\u5448\u73b0\u5230\u8c03\u8bd5\u63a7\u5236\u53f0\u3002 \u4e0b\u9762\u4ece\u51e0\u4e2a\u5173\u952e\u70b9\u5c55\u5f00\u8bf4\u660e\u3002<\/p>\n<h3>1\u3001\u534f\u8bae\u62e6\u622a&#xff1a;\u7ee7\u627f FTP \u91cd\u5199 putline \/ getline<\/h3>\n<p>FTP \u534f\u8bae\u672c\u8d28\u4e0a\u662f\u57fa\u4e8e TCP \u7684\u6587\u672c\u534f\u8bae&#xff0c;\u5ba2\u6237\u7aef\u4e0e\u670d\u52a1\u5668\u4e4b\u95f4\u901a\u8fc7 ASCII \u547d\u4ee4\u548c\u54cd\u5e94\u8fdb\u884c\u4ea4\u4e92\u3002ftplib.FTP \u5185\u90e8\u628a\u201c\u53d1\u9001\u547d\u4ee4\u201d\u548c\u201c\u8bfb\u53d6\u54cd\u5e94\u201d\u5206\u522b\u5c01\u88c5\u5728 putline() \u4e0e getline() \u4e24\u4e2a\u65b9\u6cd5\u4e2d\u3002<\/p>\n<p>\u56e0\u6b64&#xff0c;\u53ea\u8981\u7ee7\u627f FTP \u5e76\u91cd\u5199\u8fd9\u4e24\u4e2a\u65b9\u6cd5&#xff0c;\u5c31\u80fd\u5728\u4e0d\u6539\u52a8\u4efb\u4f55\u4e1a\u52a1\u903b\u8f91\u7684\u524d\u63d0\u4e0b&#xff0c;\u6355\u83b7\u5230\u5ba2\u6237\u7aef\u53d1\u51fa\u7684\u6bcf\u4e00\u6761\u547d\u4ee4\u548c\u670d\u52a1\u5668\u8fd4\u56de\u7684\u6bcf\u4e00\u6761\u54cd\u5e94&#xff1a;<\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">DebugFTP<\/span><span class=\"token punctuation\">(<\/span>FTP<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token keyword\">def<\/span> <span class=\"token function\">putline<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> line<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> self<span class=\"token punctuation\">.<\/span>_log_callback<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>_log_callback<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;cmd&#034;<\/span><span class=\"token punctuation\">,<\/span> line<span class=\"token punctuation\">)<\/span>   <span class=\"token comment\"># \u62e6\u622a\u53d1\u51fa\u7684\u547d\u4ee4<\/span><br \/>\n        <span class=\"token builtin\">super<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>putline<span class=\"token punctuation\">(<\/span>line<span class=\"token punctuation\">)<\/span><\/p>\n<p>    <span class=\"token keyword\">def<\/span> <span class=\"token function\">getline<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        line <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">super<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">.<\/span>getline<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> self<span class=\"token punctuation\">.<\/span>_log_callback<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>_log_callback<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;resp&#034;<\/span><span class=\"token punctuation\">,<\/span> line<span class=\"token punctuation\">)<\/span>  <span class=\"token comment\"># \u62e6\u622a\u6536\u5230\u7684\u54cd\u5e94<\/span><br \/>\n        <span class=\"token keyword\">return<\/span> line<\/p>\n<ul>\n<li>putline \u5728\u547d\u4ee4\u771f\u6b63\u5199\u5165 socket \u4e4b\u524d\u88ab\u8c03\u7528&#xff0c;\u6b64\u65f6 line \u5c31\u662f\u5373\u5c06\u53d1\u9001\u7684\u539f\u59cb\u547d\u4ee4\u6587\u672c&#xff08;\u5982 USER admin\u3001PWD\u3001STOR test.txt&#xff09;\u3002<\/li>\n<li>getline \u5728\u4ece socket \u8bfb\u53d6\u5230\u4e00\u884c\u54cd\u5e94\u540e\u88ab\u8c03\u7528&#xff0c;\u6b64\u65f6 line \u5c31\u662f\u670d\u52a1\u5668\u8fd4\u56de\u7684\u539f\u59cb\u54cd\u5e94&#xff08;\u5982 230 Login successful.\u3001257 &#034;\/&#034; is the current directory.&#xff09;\u3002<\/li>\n<li>\u901a\u8fc7\u6784\u9020\u51fd\u6570\u4f20\u5165\u7684 log_callback \u56de\u8c03&#xff0c;\u628a (&#034;cmd&#034;, line) \u6216 (&#034;resp&#034;, line) \u4ea4\u7ed9\u4e0a\u5c42&#xff0c;\u518d\u7531\u4fe1\u53f7 log_message \u8f6c\u53d1\u5230\u8c03\u8bd5\u63a7\u5236\u53f0\u3002<\/li>\n<\/ul>\n<p>\u8fd9\u6837\u505a\u7684\u6700\u5927\u597d\u5904\u662f\u96f6\u4fb5\u5165&#xff1a;ftplib \u5185\u90e8\u6240\u6709\u547d\u4ee4&#xff08;login\u3001cwd\u3001storbinary\u3001retrbinary\u3001mlsd \u7b49&#xff09;\u6700\u7ec8\u90fd\u4f1a\u8d70\u8fd9\u4e24\u4e2a\u65b9\u6cd5&#xff0c;\u56e0\u6b64\u65e5\u5fd7\u8986\u76d6\u662f\u5b8c\u6574\u4e14\u81ea\u52a8\u7684&#xff0c;\u65e0\u9700\u4e3a\u6bcf\u4e2a\u547d\u4ee4\u5355\u72ec\u57cb\u70b9\u3002<\/p>\n<h3>2\u3001\u7ebf\u7a0b\u6a21\u578b&#xff1a;QThread &#043; \u4efb\u52a1\u961f\u5217<\/h3>\n<p>FTP \u7f51\u7edc\u64cd\u4f5c&#xff08;\u8fde\u63a5\u3001\u5217\u76ee\u5f55\u3001\u4e0a\u4f20\u3001\u4e0b\u8f7d&#xff09;\u90fd\u662f\u963b\u585e\u8c03\u7528&#xff0c;\u5982\u679c\u76f4\u63a5\u653e\u5728 GUI \u4e3b\u7ebf\u7a0b\u6267\u884c&#xff0c;\u754c\u9762\u4f1a\u5361\u6b7b\u3002\u56e0\u6b64\u672c\u9879\u76ee\u628a FtpWorkerThread \u4f5c\u4e3a\u552f\u4e00\u7684 FTP \u64cd\u4f5c\u6267\u884c\u8005&#xff0c;\u8fd0\u884c\u5728\u540e\u53f0\u7ebf\u7a0b\u4e2d\u3002<\/p>\n<h4>2.1 \u4efb\u52a1\u961f\u5217<\/h4>\n<p>\u5de5\u4f5c\u7ebf\u7a0b\u5185\u90e8\u7ef4\u62a4\u4e00\u4e2a\u7ebf\u7a0b\u5b89\u5168\u7684\u4efb\u52a1\u961f\u5217&#xff1a;<\/p>\n<p>self<span class=\"token punctuation\">.<\/span>_task_queue <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><br \/>\nself<span class=\"token punctuation\">.<\/span>_lock <span class=\"token operator\">&#061;<\/span> threading<span class=\"token punctuation\">.<\/span>Lock<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p><span class=\"token keyword\">def<\/span> <span class=\"token function\">_enqueue<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> task_type<span class=\"token punctuation\">,<\/span> params<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token keyword\">with<\/span> self<span class=\"token punctuation\">.<\/span>_lock<span class=\"token punctuation\">:<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>_task_queue<span class=\"token punctuation\">.<\/span>append<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">(<\/span>task_type<span class=\"token punctuation\">,<\/span> params<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><\/p>\n<p>\u4e3b\u7ebf\u7a0b&#xff08;\u754c\u9762&#xff09;\u901a\u8fc7 connect_to_server()\u3001upload_file() \u7b49\u65b9\u6cd5\u5411\u961f\u5217\u8ffd\u52a0\u4efb\u52a1&#xff0c;\u5de5\u4f5c\u7ebf\u7a0b\u5728 run() \u4e2d\u5faa\u73af\u53d6\u51fa\u5e76\u6267\u884c&#xff1a;<\/p>\n<p><span class=\"token keyword\">def<\/span> <span class=\"token function\">run<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token keyword\">while<\/span> <span class=\"token keyword\">not<\/span> self<span class=\"token punctuation\">.<\/span>_stop_flag<span class=\"token punctuation\">:<\/span><br \/>\n        task <span class=\"token operator\">&#061;<\/span> <span class=\"token boolean\">None<\/span><br \/>\n        <span class=\"token keyword\">with<\/span> self<span class=\"token punctuation\">.<\/span>_lock<span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> self<span class=\"token punctuation\">.<\/span>_task_queue<span class=\"token punctuation\">:<\/span><br \/>\n                task <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>_task_queue<span class=\"token punctuation\">.<\/span>pop<span class=\"token punctuation\">(<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> task <span class=\"token keyword\">is<\/span> <span class=\"token boolean\">None<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>msleep<span class=\"token punctuation\">(<\/span><span class=\"token number\">50<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">continue<\/span><br \/>\n        task_type<span class=\"token punctuation\">,<\/span> params <span class=\"token operator\">&#061;<\/span> task<br \/>\n        <span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n            <span class=\"token comment\"># \u6839\u636e task_type \u5206\u53d1\u5230\u5bf9\u5e94\u7684 _do_xxx \u65b9\u6cd5<\/span><br \/>\n            <span class=\"token punctuation\">.<\/span><span class=\"token punctuation\">.<\/span><span class=\"token punctuation\">.<\/span><br \/>\n        <span class=\"token keyword\">except<\/span> Exception <span class=\"token keyword\">as<\/span> e<span class=\"token punctuation\">:<\/span><br \/>\n            self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>log_message<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;error&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string-interpolation\"><span class=\"token string\">f&#034;\u64cd\u4f5c\u5931\u8d25: <\/span><span class=\"token interpolation\"><span class=\"token punctuation\">{<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">(<\/span>e<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">}<\/span><\/span><span class=\"token string\">&#034;<\/span><\/span><span class=\"token punctuation\">)<\/span><\/p>\n<ul>\n<li>\u961f\u5217\u4e3a\u7a7a\u65f6\u7ebf\u7a0b msleep(50) \u8ba9\u51fa CPU&#xff0c;\u907f\u514d\u7a7a\u8f6c\u3002<\/li>\n<li>\u6240\u6709\u4efb\u52a1\u5728\u540c\u4e00\u4e2a\u540e\u53f0\u7ebf\u7a0b\u4e2d\u4e32\u884c\u6267\u884c&#xff0c;\u5929\u7136\u907f\u514d\u4e86\u591a\u4e2a FTP \u64cd\u4f5c\u5e76\u53d1\u5bfc\u81f4\u7684\u534f\u8bae\u72b6\u6001\u9519\u4e71&#xff08;FTP \u662f\u6709\u72b6\u6001\u534f\u8bae&#xff0c;\u540c\u4e00\u8fde\u63a5\u4e0a\u5e76\u53d1\u64cd\u4f5c\u4f1a\u4e92\u76f8\u5e72\u6270&#xff09;\u3002<\/li>\n<li>\u6bcf\u4e2a\u4efb\u52a1\u7528 try\/except \u5305\u88f9&#xff0c;\u4efb\u4f55\u5f02\u5e38\u90fd\u4e0d\u4f1a\u5bfc\u81f4\u7ebf\u7a0b\u9000\u51fa&#xff0c;\u800c\u662f\u901a\u8fc7\u4fe1\u53f7\u4e0a\u62a5\u7ed9\u754c\u9762\u3002<\/li>\n<\/ul>\n<h4>2.2 \u7ebf\u7a0b\u5b89\u5168<\/h4>\n<ul>\n<li>\u4efb\u52a1\u5165\u961f\u4f7f\u7528 threading.Lock \u4fdd\u62a4&#xff0c;\u4fdd\u8bc1\u4e3b\u7ebf\u7a0b\u4e0e\u5de5\u4f5c\u7ebf\u7a0b\u5bf9\u961f\u5217\u7684\u5e76\u53d1\u8bbf\u95ee\u5b89\u5168\u3002<\/li>\n<li>\u5de5\u4f5c\u7ebf\u7a0b\u4e0d\u76f4\u63a5\u64cd\u4f5c\u4efb\u4f55\u754c\u9762\u63a7\u4ef6&#xff0c;\u53ea\u901a\u8fc7 FtpSignals \u4fe1\u53f7\u628a\u7ed3\u679c\u53d1\u56de\u4e3b\u7ebf\u7a0b&#xff1b;\u4e3b\u7ebf\u7a0b\u4e2d\u7684\u69fd\u51fd\u6570&#xff08;\u5982 _on_file_list_received&#xff09;\u8d1f\u8d23\u66f4\u65b0\u754c\u9762\u3002\u8fd9\u7b26\u5408 Qt \u7684\u7ebf\u7a0b\u89c4\u5219&#xff1a;\u53ea\u6709\u4e3b\u7ebf\u7a0b\u53ef\u4ee5\u64cd\u4f5c GUI \u63a7\u4ef6\u3002<\/li>\n<\/ul>\n<h3>3\u3001\u4fe1\u53f7\u69fd\u901a\u4fe1&#xff1a;FtpSignals<\/h3>\n<p>FtpSignals \u7ee7\u627f\u81ea QObject&#xff0c;\u96c6\u4e2d\u5b9a\u4e49\u4e86\u5de5\u4f5c\u7ebf\u7a0b\u4e0e\u4e3b\u7ebf\u7a0b\u4e4b\u95f4\u7684\u6240\u6709\u901a\u4fe1\u4fe1\u53f7&#xff1a;<\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">FtpSignals<\/span><span class=\"token punctuation\">(<\/span>QObject<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    log_message <span class=\"token operator\">&#061;<\/span> pyqtSignal<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">str<\/span><span class=\"token punctuation\">)<\/span>            <span class=\"token comment\"># (\u7c7b\u522b, \u6d88\u606f)<\/span><br \/>\n    file_list_received <span class=\"token operator\">&#061;<\/span> pyqtSignal<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">list<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">str<\/span><span class=\"token punctuation\">)<\/span>    <span class=\"token comment\"># (\u6587\u4ef6\u5217\u8868, \u5f53\u524d\u8def\u5f84)<\/span><br \/>\n    transfer_progress <span class=\"token operator\">&#061;<\/span> pyqtSignal<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">int<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">int<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token comment\"># (\u6587\u4ef6\u540d, \u5df2\u4f20\u8f93, \u603b\u5927\u5c0f)<\/span><br \/>\n    transfer_complete <span class=\"token operator\">&#061;<\/span> pyqtSignal<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">bool<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token builtin\">str<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token comment\"># (\u6587\u4ef6\u540d, \u6210\u529f, \u6d88\u606f)<\/span><br \/>\n    connection_changed <span class=\"token operator\">&#061;<\/span> pyqtSignal<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">bool<\/span><span class=\"token punctuation\">)<\/span>         <span class=\"token comment\"># \u8fde\u63a5\u72b6\u6001<\/span><br \/>\n    raw_command_result <span class=\"token operator\">&#061;<\/span> pyqtSignal<span class=\"token punctuation\">(<\/span><span class=\"token builtin\">str<\/span><span class=\"token punctuation\">)<\/span>          <span class=\"token comment\"># \u539f\u59cb\u547d\u4ee4\u6267\u884c\u7ed3\u679c<\/span><\/p>\n<ul>\n<li>log_message&#xff1a;\u643a\u5e26\u7c7b\u522b&#xff08;cmd \/ resp \/ info \/ error \/ success&#xff09;\u548c\u6d88\u606f\u6587\u672c&#xff0c;\u8c03\u8bd5\u63a7\u5236\u53f0\u636e\u6b64\u7528\u4e0d\u540c\u989c\u8272\u6e32\u67d3\u3002<\/li>\n<li>file_list_received&#xff1a;\u643a\u5e26\u89e3\u6790\u540e\u7684\u6587\u4ef6\u5217\u8868\u548c\u5f53\u524d\u8def\u5f84&#xff0c;\u8fdc\u7a0b\u6587\u4ef6\u6d4f\u89c8\u5668\u636e\u6b64\u5237\u65b0\u3002<\/li>\n<li>transfer_progress \/ transfer_complete&#xff1a;\u9a71\u52a8\u4f20\u8f93\u961f\u5217\u7684\u8fdb\u5ea6\u6761\u548c\u5b8c\u6210\u72b6\u6001\u3002<\/li>\n<li>connection_changed&#xff1a;\u901a\u77e5\u4e3b\u7ebf\u7a0b\u66f4\u65b0\u8fde\u63a5\u6309\u94ae\u7684\u53ef\u7528\u72b6\u6001\u548c\u72b6\u6001\u6307\u793a\u706f\u3002<\/li>\n<\/ul>\n<p>\u7531\u4e8e pyqtSignal \u662f\u8de8\u7ebf\u7a0b\u5b89\u5168\u7684&#xff0c;\u5de5\u4f5c\u7ebf\u7a0b emit \u7684\u4fe1\u53f7\u4f1a\u81ea\u52a8\u6392\u961f\u5230\u4e3b\u7ebf\u7a0b\u7684\u4e8b\u4ef6\u5faa\u73af\u4e2d\u6267\u884c\u5bf9\u5e94\u7684\u69fd\u51fd\u6570&#xff0c;\u4ece\u800c\u5b9e\u73b0\u4e86\u7ebf\u7a0b\u95f4\u5b89\u5168\u901a\u4fe1\u3002<\/p>\n<h3>4\u3001\u76ee\u5f55\u5217\u8868\u89e3\u6790&#xff1a;MLSD \u4f18\u5148&#xff0c;LIST \u515c\u5e95<\/h3>\n<p>FTP \u5217\u76ee\u5f55\u6709\u4e24\u79cd\u5e38\u89c1\u65b9\u5f0f&#xff1a;<\/p>\n<ul>\n<li>MLSD&#xff1a;\u8fd4\u56de\u7ed3\u6784\u5316\u6570\u636e&#xff08;\u7c7b\u578b\u3001\u5927\u5c0f\u3001\u4fee\u6539\u65f6\u95f4\u7b49&#xff09;&#xff0c;\u89e3\u6790\u7b80\u5355\u53ef\u9760&#xff0c;\u4f46\u9700\u8981\u670d\u52a1\u5668\u652f\u6301&#xff08;RFC 3659&#xff09;\u3002<\/li>\n<li>LIST&#xff1a;\u8fd4\u56de\u4eba\u7c7b\u53ef\u8bfb\u7684\u6587\u672c\u5217\u8868&#xff0c;\u683c\u5f0f\u56e0\u670d\u52a1\u5668\u800c\u5f02&#xff08;Unix \u98ce\u683c\u3001DOS \u98ce\u683c\u7b49&#xff09;&#xff0c;\u89e3\u6790\u8f83\u7e41\u7410\u3002<\/li>\n<\/ul>\n<p>\u672c\u5de5\u5177\u7684\u7b56\u7565\u662f\u4f18\u5148\u5c1d\u8bd5 MLSD&#xff0c;\u5931\u8d25\u5219\u56de\u9000\u5230 LIST&#xff1a;<\/p>\n<p><span class=\"token keyword\">try<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token keyword\">for<\/span> name<span class=\"token punctuation\">,<\/span> facts <span class=\"token keyword\">in<\/span> self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>mlsd<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        is_dir <span class=\"token operator\">&#061;<\/span> facts<span class=\"token punctuation\">.<\/span>get<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;type&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;&#034;<\/span><span class=\"token punctuation\">)<\/span> <span class=\"token operator\">&#061;&#061;<\/span> <span class=\"token string\">&#034;dir&#034;<\/span><br \/>\n        size <span class=\"token operator\">&#061;<\/span> <span class=\"token builtin\">int<\/span><span class=\"token punctuation\">(<\/span>facts<span class=\"token punctuation\">.<\/span>get<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;size&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token number\">0<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        modify <span class=\"token operator\">&#061;<\/span> facts<span class=\"token punctuation\">.<\/span>get<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;modify&#034;<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">&#034;&#034;<\/span><span class=\"token punctuation\">)<\/span><br \/>\n        items<span class=\"token punctuation\">.<\/span>append<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">(<\/span>name<span class=\"token punctuation\">,<\/span> size<span class=\"token punctuation\">,<\/span> is_dir<span class=\"token punctuation\">,<\/span> modify<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">)<\/span><br \/>\n<span class=\"token keyword\">except<\/span> error_perm<span class=\"token punctuation\">:<\/span><br \/>\n    lines <span class=\"token operator\">&#061;<\/span> <span class=\"token punctuation\">[<\/span><span class=\"token punctuation\">]<\/span><br \/>\n    self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>retrlines<span class=\"token punctuation\">(<\/span><span class=\"token string\">&#034;LIST&#034;<\/span><span class=\"token punctuation\">,<\/span> lines<span class=\"token punctuation\">.<\/span>append<span class=\"token punctuation\">)<\/span><br \/>\n    <span class=\"token keyword\">for<\/span> line <span class=\"token keyword\">in<\/span> lines<span class=\"token punctuation\">:<\/span><br \/>\n        parsed <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>_parse_list_line<span class=\"token punctuation\">(<\/span>line<span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> parsed<span class=\"token punctuation\">:<\/span><br \/>\n            items<span class=\"token punctuation\">.<\/span>append<span class=\"token punctuation\">(<\/span>parsed<span class=\"token punctuation\">)<\/span><\/p>\n<p>_parse_list_line \u540c\u65f6\u517c\u5bb9 Unix \u548c DOS \u4e24\u79cd\u5e38\u89c1\u683c\u5f0f&#xff1a;<\/p>\n<ul>\n<li>Unix \u683c\u5f0f&#xff1a;drwxr-xr-x 2 user group 4096 Jan 01 12:00 filename&#xff0c;\u901a\u8fc7\u6743\u9650\u4f4d\u9996\u5b57\u7b26\u5224\u65ad\u7c7b\u578b&#xff0c;\u53d6\u7b2c 5 \u4e2a\u5b57\u6bb5\u4e3a\u5927\u5c0f&#xff0c;\u7b2c 9 \u4e2a\u5b57\u6bb5\u4e3a\u6587\u4ef6\u540d\u3002<\/li>\n<li>DOS \u683c\u5f0f&#xff1a;01-01-24 12:00AM &lt;DIR&gt; dirname&#xff0c;\u901a\u8fc7 &lt;DIR&gt; \u6807\u8bb0\u5224\u65ad\u76ee\u5f55&#xff0c;\u5426\u5219\u53d6\u6570\u5b57\u5b57\u6bb5\u4e3a\u5927\u5c0f\u3002<\/li>\n<\/ul>\n<h3>5\u3001\u4e0a\u4f20\/\u4e0b\u8f7d\u8fdb\u5ea6\u8ddf\u8e2a<\/h3>\n<h4>5.1 \u4e0a\u4f20&#xff1a;\u5305\u88c5\u6587\u4ef6\u5bf9\u8c61<\/h4>\n<p>\u4e0a\u4f20\u65f6\u901a\u8fc7 storbinary \u9010\u5757\u8bfb\u53d6\u672c\u5730\u6587\u4ef6\u5e76\u53d1\u9001\u3002\u4e3a\u4e86\u8ddf\u8e2a\u8fdb\u5ea6&#xff0c;\u628a\u6587\u4ef6\u5bf9\u8c61\u5305\u88c5\u4e00\u5c42&#xff0c;\u5728\u6bcf\u6b21 read() \u65f6\u7d2f\u8ba1\u5df2\u8bfb\u5b57\u8282\u6570&#xff1a;<\/p>\n<p><span class=\"token keyword\">class<\/span> <span class=\"token class-name\">TrackingFile<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    <span class=\"token keyword\">def<\/span> <span class=\"token function\">read<\/span><span class=\"token punctuation\">(<\/span>self<span class=\"token punctuation\">,<\/span> <span class=\"token operator\">*<\/span>args<span class=\"token punctuation\">,<\/span> <span class=\"token operator\">**<\/span>kwargs<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        data <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>_f<span class=\"token punctuation\">.<\/span>read<span class=\"token punctuation\">(<\/span><span class=\"token operator\">*<\/span>args<span class=\"token punctuation\">,<\/span> <span class=\"token operator\">**<\/span>kwargs<span class=\"token punctuation\">)<\/span><br \/>\n        <span class=\"token keyword\">if<\/span> data<span class=\"token punctuation\">:<\/span><br \/>\n            transferred<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#043;&#061;<\/span> <span class=\"token builtin\">len<\/span><span class=\"token punctuation\">(<\/span>data<span class=\"token punctuation\">)<\/span><br \/>\n            now <span class=\"token operator\">&#061;<\/span> time<span class=\"token punctuation\">.<\/span>time<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n            <span class=\"token keyword\">if<\/span> now <span class=\"token operator\">&#8211;<\/span> last_emit<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&gt;<\/span> <span class=\"token number\">0.1<\/span><span class=\"token punctuation\">:<\/span><br \/>\n                self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>transfer_progress<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>filename<span class=\"token punctuation\">,<\/span> transferred<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> file_size<span class=\"token punctuation\">)<\/span><br \/>\n                last_emit<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> now<br \/>\n        <span class=\"token keyword\">return<\/span> data<\/p>\n<ul>\n<li>\u7528 transferred[0] \u5217\u8868\u800c\u975e\u666e\u901a\u53d8\u91cf&#xff0c;\u662f\u4e3a\u4e86\u5728\u95ed\u5305\u4e2d\u4fee\u6539\u5916\u90e8\u53d8\u91cf\u3002<\/li>\n<li>\u901a\u8fc7 time.time() \u505a\u8282\u6d41&#xff1a;\u6bcf 100ms \u624d\u53d1\u4e00\u6b21\u8fdb\u5ea6\u4fe1\u53f7&#xff0c;\u907f\u514d\u9ad8\u9891\u4fe1\u53f7\u5237\u7206\u754c\u9762\u3002<\/li>\n<\/ul>\n<h4>5.2 \u4e0b\u8f7d&#xff1a;\u56de\u8c03\u51fd\u6570<\/h4>\n<p>\u4e0b\u8f7d\u65f6\u901a\u8fc7 retrbinary \u7684 callback \u53c2\u6570\u63a5\u6536\u6570\u636e\u5757&#xff0c;\u540c\u6837\u7d2f\u8ba1\u5b57\u8282\u6570\u5e76\u8282\u6d41\u53d1\u9001\u8fdb\u5ea6&#xff1a;<\/p>\n<p><span class=\"token keyword\">def<\/span> <span class=\"token function\">on_data<\/span><span class=\"token punctuation\">(<\/span>data<span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    f<span class=\"token punctuation\">.<\/span>write<span class=\"token punctuation\">(<\/span>data<span class=\"token punctuation\">)<\/span><br \/>\n    transferred<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#043;&#061;<\/span> <span class=\"token builtin\">len<\/span><span class=\"token punctuation\">(<\/span>data<span class=\"token punctuation\">)<\/span><br \/>\n    now <span class=\"token operator\">&#061;<\/span> time<span class=\"token punctuation\">.<\/span>time<span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><br \/>\n    <span class=\"token keyword\">if<\/span> now <span class=\"token operator\">&#8211;<\/span> last_emit<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&gt;<\/span> <span class=\"token number\">0.1<\/span><span class=\"token punctuation\">:<\/span><br \/>\n        self<span class=\"token punctuation\">.<\/span>signals<span class=\"token punctuation\">.<\/span>transfer_progress<span class=\"token punctuation\">.<\/span>emit<span class=\"token punctuation\">(<\/span>filename<span class=\"token punctuation\">,<\/span> transferred<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> file_size<span class=\"token punctuation\">)<\/span><br \/>\n        last_emit<span class=\"token punctuation\">[<\/span><span class=\"token number\">0<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">&#061;<\/span> now<\/p>\n<p>\u4e0b\u8f7d\u524d\u5148\u901a\u8fc7 ftp.size() \u83b7\u53d6\u6587\u4ef6\u603b\u5927\u5c0f&#xff0c;\u7528\u4e8e\u8ba1\u7b97\u767e\u5206\u6bd4&#xff1b;\u82e5\u83b7\u53d6\u5931\u8d25\u5219\u8fdb\u5ea6\u6761\u663e\u793a\u4e3a\u4e0d\u786e\u5b9a\u72b6\u6001\u3002<\/p>\n<h3>6\u3001\u539f\u59cb\u547d\u4ee4\u6267\u884c<\/h3>\n<p>\u8c03\u8bd5\u63a7\u5236\u53f0\u5141\u8bb8\u7528\u6237\u624b\u52a8\u8f93\u5165\u4efb\u610f FTP \u547d\u4ee4\u3002_do_raw_command \u5bf9\u5e38\u89c1\u547d\u4ee4\u505a\u4e86\u4e13\u95e8\u5904\u7406&#xff1a;<\/p>\n<ul>\n<li>LIST \/ NLST&#xff1a;\u901a\u8fc7 retrlines \u83b7\u53d6\u591a\u884c\u7ed3\u679c\u3002<\/li>\n<li>PWD \/ CWD \/ SIZE \/ MKD \/ RMD \/ DELE \/ REN&#xff1a;\u8c03\u7528 ftplib \u5bf9\u5e94\u65b9\u6cd5\u3002<\/li>\n<li>\u5176\u4ed6\u547d\u4ee4&#xff1a;\u901a\u8fc7 sendcmd \u539f\u6837\u53d1\u9001\u5e76\u8fd4\u56de\u670d\u52a1\u5668\u54cd\u5e94\u3002<\/li>\n<\/ul>\n<p><span class=\"token keyword\">else<\/span><span class=\"token punctuation\">:<\/span><br \/>\n    resp <span class=\"token operator\">&#061;<\/span> self<span class=\"token punctuation\">.<\/span>ftp<span class=\"token punctuation\">.<\/span>sendcmd<span class=\"token punctuation\">(<\/span>cmd<span class=\"token punctuation\">)<\/span><br \/>\n    result <span class=\"token operator\">&#061;<\/span> resp<\/p>\n<p>\u8fd9\u6837\u65e2\u8986\u76d6\u4e86\u5e38\u7528\u64cd\u4f5c&#xff0c;\u53c8\u4fdd\u7559\u4e86\u4efb\u610f\u547d\u4ee4\u900f\u4f20\u7684\u80fd\u529b&#xff0c;\u65b9\u4fbf\u8c03\u8bd5\u975e\u6807\u51c6\u6216\u6269\u5c55\u7684 FTP \u547d\u4ee4\u3002<\/p>\n<h3>7\u3001\u6574\u4f53\u6570\u636e\u6d41<\/h3>\n<p>  #mermaid-svg-BFB4g9mWoCDucUl4{font-family:\\&#8221;trebuchet ms\\&#8221;,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-BFB4g9mWoCDucUl4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BFB4g9mWoCDucUl4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BFB4g9mWoCDucUl4 .error-icon{fill:#552222;}#mermaid-svg-BFB4g9mWoCDucUl4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BFB4g9mWoCDucUl4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BFB4g9mWoCDucUl4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BFB4g9mWoCDucUl4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BFB4g9mWoCDucUl4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BFB4g9mWoCDucUl4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BFB4g9mWoCDucUl4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BFB4g9mWoCDucUl4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BFB4g9mWoCDucUl4 .marker.cross{stroke:#333333;}#mermaid-svg-BFB4g9mWoCDucUl4 svg{font-family:\\&#8221;trebuchet ms\\&#8221;,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BFB4g9mWoCDucUl4 p{margin:0;}#mermaid-svg-BFB4g9mWoCDucUl4 .label{font-family:\\&#8221;trebuchet ms\\&#8221;,verdana,arial,sans-serif;color:#333;}#mermaid-svg-BFB4g9mWoCDucUl4 .cluster-label text{fill:#333;}#mermaid-svg-BFB4g9mWoCDucUl4 .cluster-label span{color:#333;}#mermaid-svg-BFB4g9mWoCDucUl4 .cluster-label span p{background-color:transparent;}#mermaid-svg-BFB4g9mWoCDucUl4 .label text,#mermaid-svg-BFB4g9mWoCDucUl4 span{fill:#333;color:#333;}#mermaid-svg-BFB4g9mWoCDucUl4 .node rect,#mermaid-svg-BFB4g9mWoCDucUl4 .node circle,#mermaid-svg-BFB4g9mWoCDucUl4 .node ellipse,#mermaid-svg-BFB4g9mWoCDucUl4 .node polygon,#mermaid-svg-BFB4g9mWoCDucUl4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-BFB4g9mWoCDucUl4 .rough-node .label text,#mermaid-svg-BFB4g9mWoCDucUl4 .node .label text,#mermaid-svg-BFB4g9mWoCDucUl4 .image-shape .label,#mermaid-svg-BFB4g9mWoCDucUl4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-BFB4g9mWoCDucUl4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-BFB4g9mWoCDucUl4 .rough-node .label,#mermaid-svg-BFB4g9mWoCDucUl4 .node .label,#mermaid-svg-BFB4g9mWoCDucUl4 .image-shape .label,#mermaid-svg-BFB4g9mWoCDucUl4 .icon-shape .label{text-align:center;}#mermaid-svg-BFB4g9mWoCDucUl4 .node.clickable{cursor:pointer;}#mermaid-svg-BFB4g9mWoCDucUl4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-BFB4g9mWoCDucUl4 .arrowheadPath{fill:#333333;}#mermaid-svg-BFB4g9mWoCDucUl4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-BFB4g9mWoCDucUl4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-BFB4g9mWoCDucUl4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BFB4g9mWoCDucUl4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-BFB4g9mWoCDucUl4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BFB4g9mWoCDucUl4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-BFB4g9mWoCDucUl4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-BFB4g9mWoCDucUl4 .cluster text{fill:#333;}#mermaid-svg-BFB4g9mWoCDucUl4 .cluster span{color:#333;}#mermaid-svg-BFB4g9mWoCDucUl4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\\&#8221;trebuchet ms\\&#8221;,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-BFB4g9mWoCDucUl4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-BFB4g9mWoCDucUl4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-BFB4g9mWoCDucUl4 .icon-shape,#mermaid-svg-BFB4g9mWoCDucUl4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BFB4g9mWoCDucUl4 .icon-shape p,#mermaid-svg-BFB4g9mWoCDucUl4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-BFB4g9mWoCDucUl4 .icon-shape .label rect,#mermaid-svg-BFB4g9mWoCDucUl4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BFB4g9mWoCDucUl4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-BFB4g9mWoCDucUl4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-BFB4g9mWoCDucUl4 :root{&#8211;mermaid-font-family:\\&#8221;trebuchet ms\\&#8221;,verdana,arial,sans-serif;}<\/p>\n<p>         <span class=\"edgeLabel\"><\/span><\/p>\n<p>         <span class=\"edgeLabel\"><\/span><\/p>\n<p>         <span class=\"edgeLabel\"><\/span><\/p>\n<p>         <span class=\"edgeLabel\"><\/span><\/p>\n<p>         <span class=\"edgeLabel\"><\/span><\/p>\n<p>         <span class=\"edgeLabel\"><\/span><\/p>\n<p>         <span class=\"edgeLabel\"><\/span><\/p>\n<p>         <span class=\"edgeLabel\"><\/span><\/p>\n<p>         <span class=\"nodeLabel\"><\/p>\n<p>\u7528\u6237\u70b9\u51fb\u754c\u9762\u6309\u94ae<\/p>\n<p><\/span><\/p>\n<p>         <span class=\"nodeLabel\"><\/p>\n<p>\u4e3b\u7ebf\u7a0b\u8c03\u7528 FtpWorkerThread \u7684\u5165\u961f\u65b9\u6cd5<\/p>\n<p><\/span><\/p>\n<p>         <span class=\"nodeLabel\"><\/p>\n<p>\u4efb\u52a1\u5199\u5165\u7ebf\u7a0b\u5b89\u5168\u961f\u5217<\/p>\n<p><\/span><\/p>\n<p>         <span class=\"nodeLabel\"><\/p>\n<p>\u540e\u53f0\u7ebf\u7a0b run() \u53d6\u51fa\u4efb\u52a1<\/p>\n<p><\/span><\/p>\n<p>         <span class=\"nodeLabel\"><\/p>\n<p>\u6267\u884c FTP \u64cd\u4f5c&#xff08;DebugFTP&#xff09;<\/p>\n<p><\/span><\/p>\n<p>         <span class=\"nodeLabel\"><\/p>\n<p>putline\/getline \u62e6\u622a\u547d\u4ee4\u4e0e\u54cd\u5e94<\/p>\n<p><\/span><\/p>\n<p>         <span class=\"nodeLabel\"><\/p>\n<p>\u901a\u8fc7 FtpSignals \u4fe1\u53f7\u53d1\u56de\u4e3b\u7ebf\u7a0b<\/p>\n<p><\/span><\/p>\n<p>         <span class=\"nodeLabel\"><\/p>\n<p>\u4e3b\u7ebf\u7a0b\u69fd\u51fd\u6570\u66f4\u65b0\u754c\u9762<\/p>\n<p><\/span><\/p>\n<p>         <span class=\"nodeLabel\"><\/p>\n<p>\u8c03\u8bd5\u63a7\u5236\u53f0 \/ \u6587\u4ef6\u6d4f\u89c8\u5668 \/ \u8fdb\u5ea6\u6761<\/p>\n<p><\/span><\/p>\n<h3>8\u3001\u5c0f\u7ed3<\/h3>\n<table>\n<tr>\u8bbe\u8ba1\u70b9\u5b9e\u73b0\u65b9\u5f0f\u89e3\u51b3\u7684\u95ee\u9898<\/tr>\n<tbody>\n<tr>\n<td>\u534f\u8bae\u62e6\u622a<\/td>\n<td>\u7ee7\u627f FTP \u91cd\u5199 putline \/ getline<\/td>\n<td>\u96f6\u4fb5\u5165\u6355\u83b7\u5168\u90e8\u547d\u4ee4\u4e0e\u54cd\u5e94<\/td>\n<\/tr>\n<tr>\n<td>\u540e\u53f0\u6267\u884c<\/td>\n<td>QThread &#043; \u4efb\u52a1\u961f\u5217<\/td>\n<td>\u907f\u514d\u7f51\u7edc\u963b\u585e\u5361\u6b7b\u754c\u9762<\/td>\n<\/tr>\n<tr>\n<td>\u7ebf\u7a0b\u901a\u4fe1<\/td>\n<td>pyqtSignal \u4fe1\u53f7\u69fd<\/td>\n<td>\u8de8\u7ebf\u7a0b\u5b89\u5168\u66f4\u65b0\u754c\u9762<\/td>\n<\/tr>\n<tr>\n<td>\u76ee\u5f55\u89e3\u6790<\/td>\n<td>MLSD \u4f18\u5148 &#043; LIST \u515c\u5e95<\/td>\n<td>\u517c\u5bb9\u4e0d\u540c\u670d\u52a1\u5668<\/td>\n<\/tr>\n<tr>\n<td>\u8fdb\u5ea6\u8ddf\u8e2a<\/td>\n<td>\u5305\u88c5\u6587\u4ef6\u5bf9\u8c61 \/ \u56de\u8c03 &#043; \u8282\u6d41<\/td>\n<td>\u5b9e\u65f6\u4e14\u4e0d\u5237\u7206\u754c\u9762<\/td>\n<\/tr>\n<tr>\n<td>\u539f\u59cb\u547d\u4ee4<\/td>\n<td>sendcmd \u900f\u4f20<\/td>\n<td>\u652f\u6301\u4efb\u610f FTP \u547d\u4ee4\u8c03\u8bd5<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u901a\u8fc7\u4ee5\u4e0a\u8bbe\u8ba1&#xff0c;\u672c\u5de5\u5177\u65e2\u662f\u4e00\u4e2a\u53ef\u7528\u7684 FTP \u5ba2\u6237\u7aef&#xff0c;\u66f4\u662f\u4e00\u4e2a\u534f\u8bae\u7ea7\u8c03\u8bd5\u5668\u2014\u2014\u6240\u6709\u4ea4\u4e92\u8fc7\u7a0b\u5b8c\u5168\u900f\u660e\u53ef\u89c1&#xff0c;\u975e\u5e38\u9002\u5408\u5b66\u4e60 FTP \u534f\u8bae\u6216\u6392\u67e5\u670d\u52a1\u5668\u95ee\u9898\u3002<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/09\/20260918093351-6aad057f7200a.png\" alt=\"\u5728\u8fd9\u91cc\u63d2\u5165\u56fe\u7247\u63cf\u8ff0\" \/><\/p>\n<p>er)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>PyQt \u5b9e\u73b0FTP\u5ba2\u6237\u7aef\u8c03\u8bd5\u52a9\u624b\u6e90\u7801\u5206\u4eab\u4e00\u3001\u6548\u679c\u5c55\u793a\u4e8c\u3001\u6e90\u7801\u5206\u4eab1\u3001\u5de5\u7a0b\u7ed3\u67842\u3001\u5e93\u5b89\u88c53\u3001main.py4\u3001ftp_server_test.py&#xff08;\u6d4b\u8bd5\u4f7f\u7528&#xff09;\u4e09\u3001\u5b9e\u73b0\u539f\u74061\u3001\u534f\u8bae\u62e6\u622a&#xff1a;\u7ee7\u627f FTP \u91cd\u5199 putline \/ getline2\u3001\u7ebf\u7a0b\u6a21\u578b&#xff1a;QThread  \u4efb\u52a1\u961f\u52172.1 \u4efb\u52a1\u961f\u52172.2 \u7ebf\u7a0b\u5b89\u51683\u3001\u4fe1\u53f7\u69fd\u901a\u4fe1&#xff1a;FtpSignals4\u3001\u76ee\u5f55\u5217\u8868\u89e3\u6790&#xff1a;MLSD \u4f18\u5148&#xff0c;L<\/p>\n","protected":false},"author":2,"featured_media":106958,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[1705,100],"topic":[],"class_list":["post-106965","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-server","tag-pyqt","tag-100"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v20.3 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>PyQt \u5b9e\u73b0FTP\u5ba2\u6237\u7aef\u8c03\u8bd5\u52a9\u624b\u6e90\u7801\u5206\u4eab - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.wsisp.com\/helps\/106965.html\" \/>\n<meta property=\"og:locale\" content=\"zh_CN\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"PyQt \u5b9e\u73b0FTP\u5ba2\u6237\u7aef\u8c03\u8bd5\u52a9\u624b\u6e90\u7801\u5206\u4eab - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\" \/>\n<meta property=\"og:description\" content=\"PyQt \u5b9e\u73b0FTP\u5ba2\u6237\u7aef\u8c03\u8bd5\u52a9\u624b\u6e90\u7801\u5206\u4eab\u4e00\u3001\u6548\u679c\u5c55\u793a\u4e8c\u3001\u6e90\u7801\u5206\u4eab1\u3001\u5de5\u7a0b\u7ed3\u67842\u3001\u5e93\u5b89\u88c53\u3001main.py4\u3001ftp_server_test.py&#xff08;\u6d4b\u8bd5\u4f7f\u7528&#xff09;\u4e09\u3001\u5b9e\u73b0\u539f\u74061\u3001\u534f\u8bae\u62e6\u622a&#xff1a;\u7ee7\u627f FTP \u91cd\u5199 putline \/ getline2\u3001\u7ebf\u7a0b\u6a21\u578b&#xff1a;QThread \u4efb\u52a1\u961f\u52172.1 \u4efb\u52a1\u961f\u52172.2 \u7ebf\u7a0b\u5b89\u51683\u3001\u4fe1\u53f7\u69fd\u901a\u4fe1&#xff1a;FtpSignals4\u3001\u76ee\u5f55\u5217\u8868\u89e3\u6790&#xff1a;MLSD \u4f18\u5148&#xff0c;L\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.wsisp.com\/helps\/106965.html\" \/>\n<meta property=\"og:site_name\" content=\"\u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-18T09:33:52+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/09\/20260918093346-6aad057aa3dce.png\" \/>\n<meta name=\"author\" content=\"admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u4f5c\u8005\" \/>\n\t<meta name=\"twitter:data1\" content=\"admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4\" \/>\n\t<meta name=\"twitter:data2\" content=\"29 \u5206\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/106965.html\",\"url\":\"https:\/\/www.wsisp.com\/helps\/106965.html\",\"name\":\"PyQt \u5b9e\u73b0FTP\u5ba2\u6237\u7aef\u8c03\u8bd5\u52a9\u624b\u6e90\u7801\u5206\u4eab - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\",\"isPartOf\":{\"@id\":\"https:\/\/www.wsisp.com\/helps\/#website\"},\"datePublished\":\"2026-09-18T09:33:52+00:00\",\"dateModified\":\"2026-09-18T09:33:52+00:00\",\"author\":{\"@id\":\"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/358e386c577a3ab51c4493330a20ad41\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.wsisp.com\/helps\/106965.html#breadcrumb\"},\"inLanguage\":\"zh-Hans\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.wsisp.com\/helps\/106965.html\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/106965.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"\u9996\u9875\",\"item\":\"https:\/\/www.wsisp.com\/helps\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"PyQt \u5b9e\u73b0FTP\u5ba2\u6237\u7aef\u8c03\u8bd5\u52a9\u624b\u6e90\u7801\u5206\u4eab\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/#website\",\"url\":\"https:\/\/www.wsisp.com\/helps\/\",\"name\":\"\u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\",\"description\":\"\u9999\u6e2f\u670d\u52a1\u5668_\u9999\u6e2f\u4e91\u670d\u52a1\u5668\u8d44\u8baf_\u670d\u52a1\u5668\u5e2e\u52a9\u6587\u6863_\u670d\u52a1\u5668\u6559\u7a0b\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.wsisp.com\/helps\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"zh-Hans\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/358e386c577a3ab51c4493330a20ad41\",\"name\":\"admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"zh-Hans\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/gravatar.wp-china-yes.net\/avatar\/?s=96&d=mystery\",\"contentUrl\":\"https:\/\/gravatar.wp-china-yes.net\/avatar\/?s=96&d=mystery\",\"caption\":\"admin\"},\"sameAs\":[\"http:\/\/wp.wsisp.com\"],\"url\":\"https:\/\/www.wsisp.com\/helps\/author\/admin\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"PyQt \u5b9e\u73b0FTP\u5ba2\u6237\u7aef\u8c03\u8bd5\u52a9\u624b\u6e90\u7801\u5206\u4eab - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.wsisp.com\/helps\/106965.html","og_locale":"zh_CN","og_type":"article","og_title":"PyQt \u5b9e\u73b0FTP\u5ba2\u6237\u7aef\u8c03\u8bd5\u52a9\u624b\u6e90\u7801\u5206\u4eab - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","og_description":"PyQt \u5b9e\u73b0FTP\u5ba2\u6237\u7aef\u8c03\u8bd5\u52a9\u624b\u6e90\u7801\u5206\u4eab\u4e00\u3001\u6548\u679c\u5c55\u793a\u4e8c\u3001\u6e90\u7801\u5206\u4eab1\u3001\u5de5\u7a0b\u7ed3\u67842\u3001\u5e93\u5b89\u88c53\u3001main.py4\u3001ftp_server_test.py&#xff08;\u6d4b\u8bd5\u4f7f\u7528&#xff09;\u4e09\u3001\u5b9e\u73b0\u539f\u74061\u3001\u534f\u8bae\u62e6\u622a&#xff1a;\u7ee7\u627f FTP \u91cd\u5199 putline \/ getline2\u3001\u7ebf\u7a0b\u6a21\u578b&#xff1a;QThread \u4efb\u52a1\u961f\u52172.1 \u4efb\u52a1\u961f\u52172.2 \u7ebf\u7a0b\u5b89\u51683\u3001\u4fe1\u53f7\u69fd\u901a\u4fe1&#xff1a;FtpSignals4\u3001\u76ee\u5f55\u5217\u8868\u89e3\u6790&#xff1a;MLSD \u4f18\u5148&#xff0c;L","og_url":"https:\/\/www.wsisp.com\/helps\/106965.html","og_site_name":"\u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","article_published_time":"2026-09-18T09:33:52+00:00","og_image":[{"url":"https:\/\/www.wsisp.com\/helps\/wp-content\/uploads\/2026\/09\/20260918093346-6aad057aa3dce.png"}],"author":"admin","twitter_card":"summary_large_image","twitter_misc":{"\u4f5c\u8005":"admin","\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4":"29 \u5206"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.wsisp.com\/helps\/106965.html","url":"https:\/\/www.wsisp.com\/helps\/106965.html","name":"PyQt \u5b9e\u73b0FTP\u5ba2\u6237\u7aef\u8c03\u8bd5\u52a9\u624b\u6e90\u7801\u5206\u4eab - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","isPartOf":{"@id":"https:\/\/www.wsisp.com\/helps\/#website"},"datePublished":"2026-09-18T09:33:52+00:00","dateModified":"2026-09-18T09:33:52+00:00","author":{"@id":"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/358e386c577a3ab51c4493330a20ad41"},"breadcrumb":{"@id":"https:\/\/www.wsisp.com\/helps\/106965.html#breadcrumb"},"inLanguage":"zh-Hans","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.wsisp.com\/helps\/106965.html"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.wsisp.com\/helps\/106965.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"\u9996\u9875","item":"https:\/\/www.wsisp.com\/helps"},{"@type":"ListItem","position":2,"name":"PyQt \u5b9e\u73b0FTP\u5ba2\u6237\u7aef\u8c03\u8bd5\u52a9\u624b\u6e90\u7801\u5206\u4eab"}]},{"@type":"WebSite","@id":"https:\/\/www.wsisp.com\/helps\/#website","url":"https:\/\/www.wsisp.com\/helps\/","name":"\u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","description":"\u9999\u6e2f\u670d\u52a1\u5668_\u9999\u6e2f\u4e91\u670d\u52a1\u5668\u8d44\u8baf_\u670d\u52a1\u5668\u5e2e\u52a9\u6587\u6863_\u670d\u52a1\u5668\u6559\u7a0b","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.wsisp.com\/helps\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"zh-Hans"},{"@type":"Person","@id":"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/358e386c577a3ab51c4493330a20ad41","name":"admin","image":{"@type":"ImageObject","inLanguage":"zh-Hans","@id":"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/image\/","url":"https:\/\/gravatar.wp-china-yes.net\/avatar\/?s=96&d=mystery","contentUrl":"https:\/\/gravatar.wp-china-yes.net\/avatar\/?s=96&d=mystery","caption":"admin"},"sameAs":["http:\/\/wp.wsisp.com"],"url":"https:\/\/www.wsisp.com\/helps\/author\/admin"}]}},"_links":{"self":[{"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/posts\/106965","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/comments?post=106965"}],"version-history":[{"count":0,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/posts\/106965\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/media\/106958"}],"wp:attachment":[{"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/media?parent=106965"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/categories?post=106965"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/tags?post=106965"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/topic?post=106965"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}