使用 Python 通过 SSH 从服务器读取文件

发布于 2024-08-08 13:53:24 字数 464 浏览 5 评论 0原文

我正在尝试使用 Python 中的 SSH 从服务器读取文件。我正在使用 Paramiko 进行连接。我可以连接到服务器并运行 cat filename 之类的命令,并从服务器取回数据,但我尝试读取的某些文件大小约为 1 GB 或更大。

如何使用Python逐行读取服务器上的文件?

附加信息:通常执行的操作是运行 cat filename 命令并将结果存储在变量中并进行处理。但由于这里的文件相当大,我正在寻找一种从服务器上逐行读取文件的方法。

编辑:我可以读取一堆数据并将其分成几行,但问题是缓冲区中接收到的数据并不总是包含完整的行。例如,如果缓冲区有 300 行,则最后一行可能只是服务器上行的一半,而下一半将在下次调用服务器时获取。我想要完整的行

编辑2:我可以使用什么命令来打印文件中特定范围内的行。比如打印前 100 行,然后打印下 100 行,依此类推?这样缓冲区将始终包含完整的行。

I am trying to read a file from a server using SSH from Python. I am using Paramiko to connect. I can connect to the server and run a command like cat filename and get the data back from the server but some files I am trying to read are around 1 GB or more in size.

How can I read the file on the server line by line using Python?

Additional Info: What is regularly do is run a cat filename command and store the result in a variable and work off that. But since the file here is quite big, I am looking for a way to read a file line by line off the server.

EDIT: I can read a bunch of data and split it into lines but the problem is that the data received in the buffer does not always include the complete lines. For eg, if buffer has 300 lines, the last line may only be half of the line on the server and the next half would be fetched in the next call to the server. I want complete lines

EDIT 2: what command can I use to print lines in a file in a certain range. Like print first 100 lines, then the next 100 and so on? This way the buffer will always contain complete lines.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

煞人兵器 2024-08-15 13:53:24

Paramiko 的 SFTPClient 允许您获取类似文件的对象,以 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()

Paramiko's SFTPClient class allows you to get a file-like object to read data from a remote file in a Pythonic way.

Assuming you have an open 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()
以酷 2024-08-15 13:53:24

这是@Matt Good 的答案的扩展,使用 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)

Here's an extension to @Matt Good's answer, using 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)

old Fabric 1 answer:

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)
莳間冲淡了誓言ζ 2024-08-15 13:53:24
#!/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)
#!/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)
反差帅 2024-08-15 13:53:24

看起来早在 2013 年 9 月,paramiko 就添加了这些对象本身支持上下文管理器的功能,因此如果您想要两者 马特的干净答案 jfs 的上下文管理器,现在您需要的是:

with ssh_client.open_sftp() as sftp_client:
    with sftp_client.open('remote_filename') as remote_file:
        for line in remote_file:
            # process line

It looks like back in Sept 2013 paramiko added the ability for these objects to support context managers natively, so if you want both Matt's clean answer with jfs's context manager, now all you need is:

with ssh_client.open_sftp() as sftp_client:
    with sftp_client.open('remote_filename') as remote_file:
        for line in remote_file:
            # process line
灰色世界里的红玫瑰 2024-08-15 13:53:24

“逐行”是什么意思 - 网络主机之间有大量数据缓冲区,并且它们都不是面向行的。

因此,您可以读取一堆数据,然后将其在近端分成几行。

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 来移动千兆字节的数据并没有什么问题。

What do you mean by "line by line" - there are lots of data buffers between network hosts, and none of them are line-oriented.

So you can read a bunch of data, then split it into lines at the near end.

ssh otherhost cat somefile | python process_standard_input.py | do_process_locally

Or you can have a process read a bunch of data at the far end, break it up, and format it line by line and send it to you.

scp process_standard_input.py otherhost
ssh otherhost python process_standard_input.py somefile |  do_process_locally

The only difference I would care about is what way reduces the volume of data over a limited network pipe. In your situation it may, or may not matter.

There is nothing wrong in general with using cat over an SSH pipe to move gigabytes of data.

瑾兮 2024-08-15 13:53:24

我尝试使用 paramikofabric 来执行此操作。但是由于这个答案,我能够得出以下答案:

from ftplib import FTP_TLS

source = '/file/path/in/FTP/server.txt'
destiny = '/file/path/in/local/machine.txt'

with FTP_TLS() as ftps:
  ftps.connect(host, port)
  ftps.sendcmd(f'USER { username }')
  ftps.sendcmd(f'PASS { password }')

  with ftps as conn:
    with open(destiny, 'wb') as file:
      conn.retrbinary(f'RETR { source }', file.write)

I lost almost half a day of work trying to use paramiko and fabric to do this. But thanks to this answer I was able to come up with the following answer:

from ftplib import FTP_TLS

source = '/file/path/in/FTP/server.txt'
destiny = '/file/path/in/local/machine.txt'

with FTP_TLS() as ftps:
  ftps.connect(host, port)
  ftps.sendcmd(f'USER { username }')
  ftps.sendcmd(f'PASS { password }')

  with ftps as conn:
    with open(destiny, 'wb') as file:
      conn.retrbinary(f'RETR { source }', file.write)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文