#背景
職場の方がラズベリーパイで大気やら紫外線やらのデータを収集しています。
そのデータを拝借しようと当初WinSCPでローカルにコピーしてたんですが、回数こなすうちに
億劫になったので、SFTPでデータを取得しようと考えました。そのコードを書き残します。
SSH...暗号化された通信 FTP...ファイル転送プロトコル
SSH + FTP = SFTP SSHで暗号化された通信で、ファイルの転送を行うこと
#ラズパイのデータを標準出力する
現在こんな感じでラズパイにデータが入ってます。
今回は20180716.csvというファイルのデータを出力してみます。
- Java SFTPでアップロード・ダウンロード(known_hosts不要)
- Java+JSchでsftpによるファイル操作を行う
こちらのページを参考にさせて頂きました。ありがとうございます。
※JavaでSFTPでのファイル転送するためにJSchというライブラリを使います。
まずは、こちらのDownloadからjarファイルをダウンロード(※2018/08/01時点の最新はjsch-0.1.54.jarです)
英語ばっかりで何書いてるか分かんないって方は翻訳してくださいね。
pom.xmlの**<dependencies>
タグ内にjschの<dependency>
**タグを追加します。こんな感じで
<dependencies>
<!--JSch_adding_at_self_-->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.54</version>
</dependency>
</dependencies>
コードはほぼ参考ページのをコピーさせていただきました。
import com.jcraft.jsch.*;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class test {
public static void main(String[] args) throws JSchException, SftpException, FileNotFoundException, IOException {
String host = "192.168.29.29";
int port = 22;
String user = "pi";
String password = "raspberry";
String dir = "/home/pi/iot/pressure/data/2018/";
String fileName = "20180716.csv";
JSch jsch;
Session session = null;
ChannelSftp channel = null;
FileInputStream fin = null;
BufferedInputStream bin = null;
try {
//接続
jsch = new JSch();
session = jsch.getSession(user, host, port);
session.setConfig("StrictHostKeyChecking", "no");//known_hostsのチェックをスキップ
session.setPassword(password);
session.connect();
channel = (ChannelSftp) session.openChannel("sftp");
channel.connect();
channel.cd(dir);
//ダウンロード
bin = new BufferedInputStream(channel.get(fileName));
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int length;
while (true) {
length = bin.read(buf);
if (length == -1) {
break;
}
bout.write(buf, 0, length);
}
//標準出力
System.out.format("%1$s", new String(bout.toByteArray(), StandardCharsets.UTF_8));
}
finally {
if (fin != null) {
try {
fin.close();
}
catch (IOException e) {
}
}
if (bin != null) {
try {
bin.close();
}
catch (IOException e) {
}
}
if (channel != null) {
try {
channel.disconnect();
}
catch (Exception e) {
}
}
if (session != null) {
try {
session.disconnect();
}
catch (Exception e) {
}
}
}
}
}
#ラズパイのファイルをローカルに出力する
今度はデータをローカルのファイルに出力してみます。
上のコードの標準出力という箇所を、ファイルに書出し 以下の内容に変更しただけです。
import com.jcraft.jsch.*;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
public class test {
public static void main(String[] args) throws JSchException, SftpException, FileNotFoundException, IOException {
String host = "192.168.29.29";
int port = 22;
String user = "pi";
String password = "raspberry";
String dir = "/home/pi/iot/pressure/data/2018/";
String fileName = "20180716.csv";
JSch jsch;
Session session = null;
ChannelSftp channel = null;
FileInputStream fin = null;
BufferedInputStream bin = null;
try {
jsch = new JSch();
session = jsch.getSession(user, host, port);
session.setConfig("StrictHostKeyChecking", "no");
session.setPassword(password);
session.connect();
channel = (ChannelSftp) session.openChannel("sftp");
channel.connect();
channel.cd(dir);
bin = new BufferedInputStream(channel.get(fileName));
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int length;
while (true) {
length = bin.read(buf);
if (length == -1) {
break;
}
bout.write(buf, 0, length);
}
File file = new File("C:/tedkuma/BOX/★"+fileName);//ファイルに書出し
file.createNewFile();
FileWriter fw = new FileWriter(file);
fw.write(new String(bout.toByteArray()));
fw.close();
System.out.print("出力成功");
}
finally {
if (fin != null) {
try {
fin.close();
}
catch (IOException e) {
}
}
if (bin != null) {
try {
bin.close();
}
catch (IOException e) {
}
}
if (channel != null) {
try {
channel.disconnect();
}
catch (Exception e) {
}
}
if (session != null) {
try {
session.disconnect();
}
catch (Exception e) {
}
}
}
}
}
コンソールに出力成功と表示され、対象のディレクトリに★の付いたファイルが出来ています。
中身も大丈夫そうです。先ほどと同じデータがCSV出力されています。
#更新日1日以内のファイルをローカルに出力する
先日書いた 更新日が1日以内のファイルを特定する という記事の内容を流用して、
更新日1日以内のファイルだけをローカルに出力してみます。
ChannelSftp.LsEntryのページが参考になります。
LsEntryからgetAttrs()でファイルの属性を受け取って、getMTime()で更新日が取得できます。
個人的につまづいたのは、ラズパイ側の情報を受け取ったときにfilelistの中に
ファイル以外に(.とか..の)ディレクトリを受け取ってエラーが出てしまったことです。
isDir()でディレクトリの判別が出来たので、ディレクトリでなければ処理をするという流れにしました。
import com.jcraft.jsch.*;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.Vector;
public class test {
public static void main(String[] args) throws JSchException, SftpException, FileNotFoundException, IOException {
String host = "192.168.29.29";
int port = 22;
String user = "pi";
String password = "raspberry";
String dir = "/home/pi/iot/pressure/data/2018/";
JSch jsch;
Session session = null;
ChannelSftp channel = null;
FileInputStream fin = null;
BufferedInputStream bin = null;
try {
jsch = new JSch();
session = jsch.getSession(user, host, port);
session.setConfig("StrictHostKeyChecking", "no");
session.setPassword(password);
session.connect();
channel = (ChannelSftp) session.openChannel("sftp");
channel.connect();
channel.cd(dir);
Calendar st = Calendar.getInstance(); //Calendarクラスで現在日時を取得
st.add(Calendar.DATE, -1); //1日前を取得
Date start = st.getTime(); //Dateに直す
Calendar en = Calendar.getInstance();
en.add(Calendar.MINUTE, -10); //10分前を取得
Date end = en.getTime();
Vector<?> filelist = channel.ls(dir);
for(int i=0; i<filelist.size();i++){
LsEntry entry = (LsEntry) filelist.get(i);
String filename= entry.getFilename();
SftpATTRS attrs = entry.getAttrs();
Date lastModified = new Date(attrs.getMTime() * 1000L);
if(attrs.isDir()) {
//ディレクトリだったら何もしない
}if(start.compareTo(lastModified)<0 && end.compareTo(lastModified)>0){
bin = new BufferedInputStream(channel.get(filename));
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int length;
while (true) {
length = bin.read(buf);
if (length == -1) {
break;
}
bout.write(buf, 0, length);
}
File file = new File("C:/tedkuma/★"+filename);
file.createNewFile();
FileWriter fw = new FileWriter(file);
fw.write(new String(bout.toByteArray()));
fw.close();
System.out.print("出力成功");
}
}
}
finally {
if (fin != null) {
try {
fin.close();
}
catch (IOException e) {
}
}
if (bin != null) {
try {
bin.close();
}
catch (IOException e) {
}
}
if (channel != null) {
try {
channel.disconnect();
}
catch (Exception e) {
}
}
if (session != null) {
try {
session.disconnect();
}
catch (Exception e) {
}
}
}
}
}