使用 Python 使用 SSH 从服务器读取文件
Posted
技术标签:
【中文标题】使用 Python 使用 SSH 从服务器读取文件【英文标题】:Read a file from server with SSH using Python 【发布时间】:2010-12-08 11:48:39 【问题描述】:我正在尝试使用来自 Python 的 SSH 从服务器读取文件。我正在使用 Paramiko 进行连接。我可以连接到服务器并运行类似cat filename
的命令并从服务器取回数据,但我尝试读取的一些文件大小约为 1 GB 或更大。
如何使用 Python 逐行读取服务器上的文件?
附加信息:经常做的是运行cat filename
命令并将结果存储在一个变量中并解决它。但是由于这里的文件很大,所以我正在寻找一种方法来从服务器上逐行读取文件。
编辑:我可以读取一堆数据并将其分成几行,但问题是缓冲区中接收到的数据并不总是包含完整的行。例如,如果缓冲区有 300 行,则最后一行可能只是服务器上行的一半,而下一半将在下一次调用服务器时获取。我想要完整的线条
编辑 2:我可以使用什么命令来打印某个范围内的文件中的行。就像打印前 100 行,然后打印下 100 行等等?这样缓冲区将始终包含完整的行。
【问题讨论】:
【参考方案1】:你所说的“逐行”是什么意思 - 网络主机之间有很多数据缓冲区,而且它们都不是面向行的。
所以你可以读取一堆数据,然后在近端将其拆分成行。
ssh otherhost cat somefile | python process_standard_input.py | do_process_locally
或者您可以让一个进程在远端读取一堆数据,将其分解,并逐行格式化并发送给您。
scp process_standard_input.py otherhost
ssh otherhost python process_standard_input.py somefile | do_process_locally
我关心的唯一区别是如何减少有限网络管道上的数据量。在您的情况下,这可能重要,也可能不重要。
在 SSH 管道上使用 cat
来移动千兆字节的数据通常没有任何问题。
【讨论】:
【参考方案2】:#!/usr/bin/env python
import paramiko
import select
client = paramiko.SSHClient()
client.load_system_host_keys()
client.connect('yourhost.com')
transport = client.get_transport()
channel = transport.open_session()
channel.exec_command("cat /path/to/your/file")
while True:
rl, wl, xl = select.select([channel],[],[],0.0)
if len(rl) > 0:
# Must be stdout
print channel.recv(1024)
【讨论】:
paramiko 的好例子,但再次强调了这种任务的非面向线的性质。 继续阅读,直到你得到一个换行符或其他换行符。【参考方案3】:Paramiko's SFTPClient
class 允许你获取一个类文件对象,以 Python 方式从远程文件中读取数据。
假设你有一个开放的SSHClient
:
sftp_client = ssh_client.open_sftp()
remote_file = sftp_client.open('remote_filename')
try:
for line in remote_file:
# process line
finally:
remote_file.close()
【讨论】:
+1,比和猫混在一起要好得多(因为我喜欢猫科动物!-)。 虽然正确,但这种幼稚的实现非常缓慢。它需要一些改进才能获得良好的性能。见Reading file opened with Python Paramiko SFTPClient.open method is slow。【参考方案4】:这是@Matt Good's answer 的扩展,使用fabric:
from fabric.connection import Connection
with Connection(host, user) as c, c.sftp() as sftp, \
sftp.open('remote_filename') as file:
for line in file:
process(line)
旧织物 1 个答案:
from contextlib import closing
from fabric.network import connect
with closing(connect(user, host, port)) as ssh, \
closing(ssh.open_sftp()) as sftp, \
closing(sftp.open('remote_filename')) as file:
for line in file:
process(line)
【讨论】:
我以前从未见过 contextlib.closure 。所以这可以让你将任何带有 close() 方法的东西变成一个类似上下文管理器的东西,尽管它可能没有 __enter__ 和 __exit__? @hughbrown:是的。任何带有.close()
方法的对象都可以。 closing
的实现很简单,见svn.python.org/view/python/trunk/Lib/contextlib.py?view=markup
事实上with sftp.open('remote_filename') as f:
也可以使用
@user128285:它可能取决于特定的库版本(较新的版本不需要closing()
调用)。
@AllanRuin:是的,fabric 2 需要不同的代码。我已经更新了答案。【参考方案5】:
看起来早在 2013 年 9 月 paramiko 就为这些对象添加了原生支持上下文管理器的功能,因此如果您想要 Matt's clean answer 和 jfs's context manager,现在您只需要:
with ssh_client.open_sftp() as sftp_client:
with sftp_client.open('remote_filename') as remote_file:
for line in remote_file:
# process line
【讨论】:
以上是关于使用 Python 使用 SSH 从服务器读取文件的主要内容,如果未能解决你的问题,请参考以下文章
使用 Node.js 和 SSH2 从 SFTP 服务器读取文件
如何使用 Python 和 Paramiko 创建 SSH 隧道?
如何使用Paramiko Python通过SSH从远程服务器复制文件? FileNotFoundError:[WinError 3]系统找不到指定的路径