URL | |
---|---|
基本 | https://qiita.com/cielavenir/items/9d068c49186060a47650 |
Pythonの.ssh/config読み出し | https://qiita.com/cielavenir/items/6aa9e6dc1166ae947c6f |
大きいファイルの取得 | https://qiita.com/cielavenir/items/f38223c156e4aaab58ad |
そこそこ大きい100MBほどの、リモートのテキストファイルを処理したいことはあると思います。
このような場合、逐次読み出しだと遅くなるので、一気に読み出してオンメモリで処理する必要があります。
Perl
Perlはバッファまわりが賢いようなのでlocal $/
でも行けますし、string ioのようなことをしても良いです。
#!/usr/bin/perl
use strict;
use Net::SFTP::Foreign;
my $sftp = Net::SFTP::Foreign->new('host');
my $file_content;
if(0){
open(my $fh,'>',\$file_content);
$sftp->get('/foo/bar',$fh);
$fh->close;
}else{
my $fh = $sftp->open('/foo/bar',Net::SFTP::Foreign::Constants::SSH2_FXF_READ);
$file_content = do { local $/; <$fh> };
$fh->close;
}
print length($file_content);
$sftp->disconnect;
Ruby
https://qiita.com/yohm/items/c469671d866ca32643f9 で触れられているように、sftp.download!は遅いです。後述するPythonと異なり、(バッファの設定とか調べましたが)SFTPの範囲ではどうしようもないようです。
身も蓋もないですが、sftp.session.scp.download!
を使います。もちろん(Net::SSHのインスタンスをsshとしたとき)ssh.scp.download!
でもOKです。
require 'net/sftp'
require 'net/scp'
Net::SFTP.start('host',nil){|sftp|
io = StringIO.new
sftp.session.scp.download!('/foo/bar',io)
p io.string.size
}
Python
Python2では以下のようにprefetchで良いようです。
with sftp.file('/foo/bar','r') as f:
f.prefetch()
f.read()
ただ、Python3やPyPyではあまり高速になりませんでした。getfoを使えば良いようです。
Python2/3対応にするには以下のようなことをすれば良いです。
if sys.version_info[0]>=3:
from io import StringIO, BytesIO
def getTextString(sftp, path):
io=BytesIO()
sftp.getfo(path,io)
return io.getvalue().decode('utf-8')
def getTextIO(sftp, path):
return StringIO(getTextString(sftp, path))
else:
from StringIO import StringIO
def getTextString(sftp, path):
return getTextIO(sftp, path).getvalue()
def getTextIO(sftp, path):
io=StringIO()
sftp.getfo(path,io)
io.seek(0)
return io