Help us understand the problem. What is going on with this article?

メモ : 【Java】SFTPでRaspberry Piのデータを取得する

More than 1 year has passed since last update.

背景

職場の方がラズベリーパイで大気やら紫外線やらのデータを収集しています。
そのデータを拝借しようと当初WinSCPでローカルにコピーしてたんですが、回数こなすうちに
億劫になったので、SFTPでデータを取得しようと考えました。そのコードを書き残します。

ラズパイのデータコピーしてたんですけども.png

       SSH...暗号化された通信   FTP...ファイル転送プロトコル

       SSH + FTP = SFTP   SSHで暗号化された通信で、ファイルの転送を行うこと

ラズパイのデータを標準出力する

現在こんな感じでラズパイにデータが入ってます。
今回は20180716.csvというファイルのデータを出力してみます。
1.png
 - Java SFTPでアップロード・ダウンロード(known_hosts不要)
 - Java+JSchでsftpによるファイル操作を行う
 :grinning:こちらのページを参考にさせて頂きました。ありがとうございます。

※JavaでSFTPでのファイル転送するためにJSchというライブラリを使います。
まずは、こちらDownloadからjarファイルをダウンロード(※2018/08/01時点の最新はjsch-0.1.54.jarです)
英語ばっかりで何書いてるか分かんないって方は翻訳してくださいね。

pom.xmlの<dependencies>タグ内にjschの<dependency>タグを追加します。こんな感じで

pom.xml
    <dependencies>
        <!--JSch_adding_at_self_-->
        <dependency>
            <groupId>com.jcraft</groupId>
            <artifactId>jsch</artifactId>
            <version>0.1.54</version>
        </dependency>
    </dependencies>

コードはほぼ参考ページのをコピーさせていただきました。

test.java
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) {
                }
            }
        }
    }
}

では実行してみます。CSVの内容が書き出されました。
2.png

ラズパイのファイルをローカルに出力する

今度はデータをローカルのファイルに出力してみます。
上のコードの標準出力という箇所を、ファイルに書出し 以下の内容に変更しただけです。

test.java
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) {
                }
            }
        }
    }
}

コンソールに出力成功と表示され、対象のディレクトリに★の付いたファイルが出来ています。
3.png

中身も大丈夫そうです。先ほどと同じデータがCSV出力されています。
4.png

更新日1日以内のファイルをローカルに出力する

先日書いた 更新日が1日以内のファイルを特定する という記事の内容を流用して、
更新日1日以内のファイルだけをローカルに出力してみます。

ChannelSftp.LsEntryのページが参考になります。
LsEntryからgetAttrs()でファイルの属性を受け取って、getMTime()で更新日が取得できます。

個人的につまづいたのは、ラズパイ側の情報を受け取ったときにfilelistの中に
ファイル以外に(.とか..の)ディレクトリを受け取ってエラーが出てしまったことです。
isDir()でディレクトリの判別が出来たので、ディレクトリでなければ処理をするという流れにしました。
Rlogin.png

test.java
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) {
                }
            }
        }
    }
}

対象のディレクトリに更新日1日以内のファイルだけが★付きの名前でコピーされています。
5.png

昨晩のデータが入っているので、データの中身も問題なさそうです。
6.png

tedkuma
ずーっとエクセルが得意なだけの営業事務してました。プログラマーになりたいとアラフォーデビューと同時に開発のお仕事に転職。開発経験が浅いので、チートシートとして書き残しつつ、ワタシみたいな人に共有したいと記事を書いています。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away