4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-08-01

#背景
職場の方がラズベリーパイで大気やら紫外線やらのデータを収集しています。
そのデータを拝借しようと当初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

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?