Создание FTP-клиента с Python

Я всегда думал о создании моего собственного ftp-клиента с тех пор, как начал использовать Интернет. И теперь, когда я изучаю Python, я собираюсь создать его как упражнение / личный проект.

Мне любопытно,

  • Какие библиотеки вы предлагаете? Будет ли ftplib достаточно? Или вы предложите другую библиотеку (желательно, у которой есть хорошие документы)?
  • Я думаю об использовании wxPython. Это хорошая идея? Должен ли я сначала изучить его?
  • Я исхожу из веб-разработки. Какие советы / предложения вы мне дадите?

Я был бы признателен за любое руководство / помощь. Заранее спасибо! 🙂

2 Solutions collect form web for “Создание FTP-клиента с Python”

Похоже, вы хотите создать программу с графическим интерфейсом. Могу ли я рекомендовать использование PyQt для этой части вашего приложения? ftplib должно быть хорошо для вашей поддержки FTP, и вы можете найти документацию прямо здесь .

В качестве альтернативы для поддержки FTP вы можете использовать класс QFtp из модуля QtNetwork из инфраструктуры PyQt . Ниже приведен пример FTP-клиента с PyQt. Изображения идут вместе с ним.

 #!/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(':http://img.rupython.com/pythoncdtoparent.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(':http://img.rupython.com/pythondir.png') else: icon = QtGui.QIcon(':http://img.rupython.com/pythonfile.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_()) . #!/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(':http://img.rupython.com/pythoncdtoparent.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(':http://img.rupython.com/pythondir.png') else: icon = QtGui.QIcon(':http://img.rupython.com/pythonfile.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 – это отличное место для запуска: http://docs.python.org/library/ftplib.html

Примечание. И если по какой-то причине вы хотите написать своего собственного клиента, вы можете просто прочитать источник, который сам по себе является хорошим упражнением …

  • Python FTP для iPad
  • Загрузите большие файлы через FTP с помощью python
  • Создание списка из ретрансляции в Python
  • Библиотеки Python для загрузки / загрузки FTP?
  • Как удалить файлы с помощью скрипта Python с FTP-сервера старше 7 дней?
  • Объект «NoneType» не имеет атрибута «sendall» PYTHON
  • Один сервер ftp в python
  • Можно ли читать файлы FTP, не записывая их с помощью Python?
  • Python - лучший язык программирования в мире.