简体   繁体   English

使用Python创建FTP客户端

[英]Creating an FTP client with Python

I've always thought about creating my own ftp client ever since I've started using the Internet. 自从我开始使用互联网以来,我一直在考虑创建自己的ftp客户端。 And now that I'm studying Python, I'm thinking about creating one as an exercises/personal project. 现在我正在学习Python,我正在考虑创建一个作为练习/个人项目。

I'm wondering, 我很好奇,

  • What libraries do you guys suggest? 你们建议哪些图书馆? Will ftplib suffice? ftplib满足吗? Or would you suggest another library(preferably one that has good docs)? 或者你会建议另一个图书馆(最好是一个有良好文档的图书馆)?
  • I'm thinking about using wxPython. 我正在考虑使用wxPython。 Is it a good idea? 这是个好主意吗? Should I learn it first? 我应该先学习吗?
  • I'm coming from a Web Development background. 我来自Web开发背景。 What tips/suggestions would you guys give to me? 你们会给我什么提示/建议?

I'd appreciate any guidance/help. 我很感激任何指导/帮助。 Thanks in advance! 提前致谢! :) :)

It sounds like you want to make a program that has a GUI. 听起来你想要制作一个具有GUI的程序。 May I recommend using PyQt for that part of your application? 我可以建议在应用程序的这一部分使用PyQt吗? ftplib should be fine for your FTP support, and you can find documentation right here . ftplib应该适合您的FTP支持,您可以在这里找到文档。

Alternatively for FTP support, you can use the QFtp class from the QtNetwork module from PyQt framework. 或者,对于FTP支持,您可以使用PyQt框架中的QtNetwork模块中的QFtp类。 The following is an example FTP client that comes with PyQt. 以下是PyQt附带的示例FTP客户端。 The images come with it. 图像随之而来。

#!/usr/bin/env python

"""PyQt4 port of the network/ftp example from Qt v4.x"""

# This is only needed for Python v2 but is harmless for Python v3.
import sip
sip.setapi('QString', 2)

from PyQt4 import QtCore, QtGui, QtNetwork

import ftp_rc


class FtpWindow(QtGui.QDialog):
    def __init__(self, parent=None):
        super(FtpWindow, self).__init__(parent)

        self.isDirectory = {}
        self.currentPath = ''
        self.ftp = None
        self.outFile = None

        ftpServerLabel = QtGui.QLabel("Ftp &server:")
        self.ftpServerLineEdit = QtGui.QLineEdit('ftp.trolltech.com')
        ftpServerLabel.setBuddy(self.ftpServerLineEdit)

        self.statusLabel = QtGui.QLabel("Please enter the name of an FTP server.")

        self.fileList = QtGui.QTreeWidget()
        self.fileList.setEnabled(False)
        self.fileList.setRootIsDecorated(False)
        self.fileList.setHeaderLabels(("Name", "Size", "Owner", "Group", "Time"))
        self.fileList.header().setStretchLastSection(False)

        self.connectButton = QtGui.QPushButton("Connect")
        self.connectButton.setDefault(True)

        self.cdToParentButton = QtGui.QPushButton()
        self.cdToParentButton.setIcon(QtGui.QIcon(':/images/cdtoparent.png'))
        self.cdToParentButton.setEnabled(False)

        self.downloadButton = QtGui.QPushButton("Download")
        self.downloadButton.setEnabled(False)

        self.quitButton = QtGui.QPushButton("Quit")

        buttonBox = QtGui.QDialogButtonBox()
        buttonBox.addButton(self.downloadButton,
                QtGui.QDialogButtonBox.ActionRole)
        buttonBox.addButton(self.quitButton, QtGui.QDialogButtonBox.RejectRole)

        self.progressDialog = QtGui.QProgressDialog(self)

        self.fileList.itemActivated.connect(self.processItem)
        self.fileList.currentItemChanged.connect(self.enableDownloadButton)
        self.progressDialog.canceled.connect(self.cancelDownload)
        self.connectButton.clicked.connect(self.connectOrDisconnect)
        self.cdToParentButton.clicked.connect(self.cdToParent)
        self.downloadButton.clicked.connect(self.downloadFile)
        self.quitButton.clicked.connect(self.close)

        topLayout = QtGui.QHBoxLayout()
        topLayout.addWidget(ftpServerLabel)
        topLayout.addWidget(self.ftpServerLineEdit)
        topLayout.addWidget(self.cdToParentButton)
        topLayout.addWidget(self.connectButton)

        mainLayout = QtGui.QVBoxLayout()
        mainLayout.addLayout(topLayout)
        mainLayout.addWidget(self.fileList)
        mainLayout.addWidget(self.statusLabel)
        mainLayout.addWidget(buttonBox)
        self.setLayout(mainLayout)

        self.setWindowTitle("FTP")

    def sizeHint(self):
        return QtCore.QSize(500, 300)

    def connectOrDisconnect(self):
        if self.ftp:
            self.ftp.abort()
            self.ftp.deleteLater()
            self.ftp = None

            self.fileList.setEnabled(False)
            self.cdToParentButton.setEnabled(False)
            self.downloadButton.setEnabled(False)
            self.connectButton.setEnabled(True)
            self.connectButton.setText("Connect")
            self.setCursor(QtCore.Qt.ArrowCursor)

            return

        self.setCursor(QtCore.Qt.WaitCursor)

        self.ftp = QtNetwork.QFtp(self)
        self.ftp.commandFinished.connect(self.ftpCommandFinished)
        self.ftp.listInfo.connect(self.addToList)
        self.ftp.dataTransferProgress.connect(self.updateDataTransferProgress)

        self.fileList.clear()
        self.currentPath = ''
        self.isDirectory.clear()

        url = QtCore.QUrl(self.ftpServerLineEdit.text())
        if not url.isValid() or url.scheme().lower() != 'ftp':
            self.ftp.connectToHost(self.ftpServerLineEdit.text(), 21)
            self.ftp.login()
        else:
            self.ftp.connectToHost(url.host(), url.port(21))

            user_name = url.userName()
            if user_name:
                try:
                    # Python v3.
                    user_name = bytes(user_name, encoding='latin1')
                except:
                    # Python v2.
                    pass

                self.ftp.login(QtCore.QUrl.fromPercentEncoding(user_name), url.password())
            else:
                self.ftp.login()

            if url.path():
                self.ftp.cd(url.path())

        self.fileList.setEnabled(True)
        self.connectButton.setEnabled(False)
        self.connectButton.setText("Disconnect")
        self.statusLabel.setText("Connecting to FTP server %s..." % self.ftpServerLineEdit.text())

    def downloadFile(self):
        fileName = self.fileList.currentItem().text(0)

        if QtCore.QFile.exists(fileName):
            QtGui.QMessageBox.information(self, "FTP",
                    "There already exists a file called %s in the current "
                    "directory." % fileName)
            return

        self.outFile = QtCore.QFile(fileName)
        if not self.outFile.open(QtCore.QIODevice.WriteOnly):
            QtGui.QMessageBox.information(self, "FTP",
                    "Unable to save the file %s: %s." % (fileName, self.outFile.errorString()))
            self.outFile = None
            return

        self.ftp.get(self.fileList.currentItem().text(0), self.outFile)

        self.progressDialog.setLabelText("Downloading %s..." % fileName)
        self.downloadButton.setEnabled(False)
        self.progressDialog.exec_()

    def cancelDownload(self):
        self.ftp.abort()

    def ftpCommandFinished(self, _, error):
        self.setCursor(QtCore.Qt.ArrowCursor)

        if self.ftp.currentCommand() == QtNetwork.QFtp.ConnectToHost:
            if error:
                QtGui.QMessageBox.information(self, "FTP",
                        "Unable to connect to the FTP server at %s. Please "
                        "check that the host name is correct." % self.ftpServerLineEdit.text())
                self.connectOrDisconnect()
                return

            self.statusLabel.setText("Logged onto %s." % self.ftpServerLineEdit.text())
            self.fileList.setFocus()
            self.downloadButton.setDefault(True)
            self.connectButton.setEnabled(True)
            return

        if self.ftp.currentCommand() == QtNetwork.QFtp.Login:
            self.ftp.list()

        if self.ftp.currentCommand() == QtNetwork.QFtp.Get:
            if error:
                self.statusLabel.setText("Canceled download of %s." % self.outFile.fileName())
                self.outFile.close()
                self.outFile.remove()
            else:
                self.statusLabel.setText("Downloaded %s to current directory." % self.outFile.fileName())
                self.outFile.close()

            self.outFile = None
            self.enableDownloadButton()
            self.progressDialog.hide()
        elif self.ftp.currentCommand() == QtNetwork.QFtp.List:
            if not self.isDirectory:
                self.fileList.addTopLevelItem(QtGui.QTreeWidgetItem(["<empty>"]))
                self.fileList.setEnabled(False)

    def addToList(self, urlInfo):
        item = QtGui.QTreeWidgetItem()
        item.setText(0, urlInfo.name())
        item.setText(1, str(urlInfo.size()))
        item.setText(2, urlInfo.owner())
        item.setText(3, urlInfo.group())
        item.setText(4, urlInfo.lastModified().toString('MMM dd yyyy'))

        if urlInfo.isDir():
            icon = QtGui.QIcon(':/images/dir.png')
        else:
            icon = QtGui.QIcon(':/images/file.png')
        item.setIcon(0, icon)

        self.isDirectory[urlInfo.name()] = urlInfo.isDir()
        self.fileList.addTopLevelItem(item)
        if not self.fileList.currentItem():
            self.fileList.setCurrentItem(self.fileList.topLevelItem(0))
            self.fileList.setEnabled(True)

    def processItem(self, item):
        name = item.text(0)
        if self.isDirectory.get(name):
            self.fileList.clear()
            self.isDirectory.clear()
            self.currentPath += '/' + name
            self.ftp.cd(name)
            self.ftp.list()
            self.cdToParentButton.setEnabled(True)
            self.setCursor(QtCore.Qt.WaitCursor)

    def cdToParent(self):
        self.setCursor(QtCore.Qt.WaitCursor)
        self.fileList.clear()
        self.isDirectory.clear()

        dirs = self.currentPath.split('/')
        if len(dirs) > 1:
            self.currentPath = ''
            self.cdToParentButton.setEnabled(False)
            self.ftp.cd('/')
        else:
            self.currentPath = '/'.join(dirs[:-1])
            self.ftp.cd(self.currentPath)

        self.ftp.list()

    def updateDataTransferProgress(self, readBytes, totalBytes):
        self.progressDialog.setMaximum(totalBytes)
        self.progressDialog.setValue(readBytes)

    def enableDownloadButton(self):
        current = self.fileList.currentItem()
        if current:
            currentFile = current.text(0)
            self.downloadButton.setEnabled(not self.isDirectory.get(currentFile))
        else:
            self.downloadButton.setEnabled(False)


if __name__ == '__main__':

    import sys

    app = QtGui.QApplication(sys.argv)
    ftpWin = FtpWindow()
    ftpWin.show()
    sys.exit(ftpWin.exec_())

Python's standard library is just a great place to start: http://docs.python.org/library/ftplib.html Python的标准库只是一个很好的起点: http//docs.python.org/library/ftplib.html

Note: And if for some reason you want to write your own client, you can simple read the source, which is a good training exercise in itself ... 注意:如果由于某种原因你想编写自己的客户端,你可以简单地阅读源代码,这本身就是一个很好的培训练习......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Python 是否有丰富的 ftp 客户端库? - Is there a rich ftp client library for Python? 如何将远程 Python FTP 服务器连接到本地 Python FTP 客户端 - How to connect remote Python FTP server to local Python FTP client 为 python 客户端服务器创建 Gui - Creating Gui for python client server 通过套接字/ ftp python从服务器向客户端发送文件 - Sending files to client from server via socket/ftp python 在 FTP 中使用 Python 创建年/月/日文件夹结构 - Creating year / month / day folder structure with Python in FTP Google BigQuery-Python客户端-创建/管理作业 - Google BigQuery - python client - creating/managing jobs Python 官方 Stripe 客户端创建两个客户 - Python Official Stripe Client Creating Two Customers 尝试通过FTP在客户端中将字符串从客户端发送到服务器时传递&#39;b&#39; - 'b' is getting passed when sending string from client to server in python while trying FTP implementation 如何在Python / Django中的客户端请求之间维护服务器启动的FTP连接? - How to maintain server-initiated FTP connection between client requests in Python/Django? Python FTP 无法连接,但使用具有相同凭据的 FileZilla 等客户端工作 - Python FTP cannot connect, but using client like FileZilla with same credentials works
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM