m_shige1979のときどきITブログ

プログラムの勉強をしながら学習したことや経験したことをぼそぼそと書いていきます

Github(変なおっさんの顔でるので気をつけてね)

https://github.com/mshige1979

go言語でjson形式の設定ファイルを読み込む

実行する際の変数の外出

設定ファイルにして配置しておくとやりやすいので対応する。

前提

設定ファイルはjson

実装

config.json
{
    "url": "http://hogehoge.com",
    "count": 100,
    "user": "hoge",
    "pass": "foo"
}
sample1.go
package main

import (
    "log"
    "os"
    "io/ioutil"
    "encoding/json"
    "strconv"
)

// jsonの設定ファイルを読み込むサンプル
func main() {
    // 処理開始
    log.Println("start")

    jsonString, err := ioutil.ReadFile("config.json")
    if err != nil {
        log.Println(err)
        os.Exit(1)
    }

    // config.jsonの中身を出力
    // そのままだとbyteデータになるのでstringに変換
    log.Println(string(jsonString))

    // 構造体定義
    type Config struct {
        Url   string  `json:"url"`
        Count int     `json:"count"`
        User  string  `json:"user"`
        Pass  string  `json:"pass"`
    }

    // 設定変数用意
    c := new(Config)

    // 設定
    err = json.Unmarshal(jsonString, c)
    if err != nil {
        log.Println(err)
        os.Exit(2)
    }

    // 結果出力
    log.Println("url   = " + c.Url)
    log.Println("count = " + strconv.Itoa(c.Count))
    log.Println("user  = " + c.User)
    log.Println("pass  = " + c.Pass)

    // 処理終了
    log.Println("end")
}

$ go run sample1.go
2017/10/28 14:32:33 start
2017/10/28 14:32:33 {
    "url": "http://hogehoge.com",
    "count": 100,
    "user": "hoge",
    "pass": "foo"
}


2017/10/28 14:32:33 url   = http://hogehoge.com
2017/10/28 14:32:33 count = 100
2017/10/28 14:32:33 user  = hoge
2017/10/28 14:32:33 pass  = foo
2017/10/28 14:32:33 end
$

注意点

構造体に設定する際はフィールドの項目は外部公開できるように1文字目を大文字にしておくこと
そうしないと構造体のデータに設定されてくれない

【C++】動的にデータを追加するvector、listを使う

配列などを定義して使用する際は

素数を使用しますが、用意する要素数が不明瞭な場合は件数の指定が曖昧になります。
5件の場合もあれば10件の場合など
その際に使用するのがvector

実装

サンプル
//============================================================================
// Name        : sample04.cpp
// Author      :
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <vector>
#include <list>
#include <cstring>

using namespace std;

int main() {
	cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!

	/**
	 * vectorの場合
	 */
	vector<string> strlist;
	strlist.push_back("aaaa1");
	strlist.push_back("aaaa2");
	strlist.push_back("aaaa3");
	strlist.push_back("aaaa4");

	// イテレータを使用して抽出
	for (vector<string>::iterator it = strlist.begin(); it != strlist.end(); ++it) {
		cout << *it << endl;
	}

	vector<int> intlist;
	intlist.push_back(100);
	intlist.push_back(200);
	intlist.push_back(300);
	intlist.push_back(400);

	// 回数指定で抽出
	for (int i=0;i<intlist.size();i++) {
		int a = intlist.operator[](i);
		cout << a << endl;
	}

	/**
	 * listの場合
	 */
	list<string> strlist2;
	strlist2.push_back("bbbb1");
	strlist2.push_back("bbbb2");
	strlist2.push_back("bbbb3");
	strlist2.push_back("bbbb4");

	// イテレータを使用して抽出
	for (list<string>::iterator it = strlist2.begin(); it != strlist2.end(); ++it) {
		cout << *it << endl;
	}

	return 0;
}

!!!Hello World!!!
aaaa1
aaaa2
aaaa3
aaaa4
100
200
300
400
bbbb1
bbbb2
bbbb3
bbbb4
vectorの場合

要素の途中の項目にもアクセスできます。listよりは少し遅いとのこと

listの場合

イテレータなどの処理以外で参照しかできない分処理は速いらしい

所感

まあ、とりあえず現状は動的配列としてはvectorを使用したほうが良い感じに見える。
いろいろ調べて行くうちに別の方法が見つかると思いますが…

【C++】カレントディレクトリ配下のファイル一覧を抽出する

今回はC言語の勉強

いろんなところでお世話になるファイル検索
指定ディレクトリ配下の一覧を抽出することを行います。

やること

単純に指定ディレクトリ配下のディレクトリより「.txt」のファイルを検索してコンソールへ出力します。

実装

sample03.cpp
//============================================================================
// Name        : sample03.cpp
// Author      :
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <windows.h>
#include <cstring>
#include <unistd.h>

using namespace std;

int main() {
	cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!

	// カレントディレクトリを取得
	char dir[512];
	getcwd(dir, 512);
	cout << dir << endl;

	// 検索パス
	string str = "";
	str.append(dir);
	str.append("/work/*.txt");

	// 検索データ
	WIN32_FIND_DATA ffData;

	// 検索開始
	HANDLE handle = FindFirstFile(str.c_str(), &ffData);
	if (handle == INVALID_HANDLE_VALUE) {
		cout << "取得失敗" << endl;
	} else {
		cout << "取得成功" << endl;

		do {
			// ファイル名を出力する
			string fileInfo = "";
			SYSTEMTIME stFileTime;
			char strFileTime[256];

			// 日付を変換
			FileTimeToSystemTime(&ffData.ftLastWriteTime , &stFileTime);
			wsprintf(strFileTime , TEXT("%d%d%d%d%d%d秒") ,
					stFileTime.wYear , stFileTime.wMonth ,
					stFileTime.wDay , stFileTime.wHour ,
					stFileTime.wMinute , stFileTime.wSecond);

			// 書式整形
			fileInfo.append("file:");
			fileInfo.append(ffData.cFileName);
			fileInfo.append(" ");
			fileInfo.append("最終更新日時:");
			fileInfo.append(strFileTime);

			cout << fileInfo << endl;

		}while(FindNextFile(handle, &ffData));// 次のファイルを検索する

		// ファイルハンドルを閉じる
		FindClose(handle);
	}

	return 0;
}
ディレクトリにサンプルファイルを準備

f:id:m_shige1979:20170806123106j:plain

実行結果
!!!Hello World!!!
C:\pleiades\pleiades-e4.5-cpp-jre_20160312\pleiades\workspace\sample03
取得成功
file:0001.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒
file:0002.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒
file:0003.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒
file:0004.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒
file:0005.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒
file:0006.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒
file:0007.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒
file:0008.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒
file:0009.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒
file:0010.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒
file:0011.txt 最終更新日時:2017年 8月 6日 2時 55分 42秒

所感

toString()ない(´・ω・`)
Javaってとりあえず面倒な場合はtoString()で文字列にすればよくね?みたいな感じがあったけど
C言語ってJava以上に型に厳密な感じだな〜
もう少し楽してコード書きたいような気がしてきた〜

pleiades(eclipse)のCDT(MinGW)でDLLを作成する

会社とかでするときとかさあ

VisualStudioないんですけど…
なんで買っといてくんないの(´・ω・`)
Community入れたくなるんですけど…

というわけで

フリーかどうか知らんがeclipseに入っていたMinGWを使ってDLLを作成してみる

プロジェクトを作成する

共用ライブラリとして作成

f:id:m_shige1979:20170806104546j:plain

ソースディレクトリと空のソースファイルを用意

f:id:m_shige1979:20170806104746j:plain

実装
/*
 * sample01.cpp
 *
 *  Created on: 2017/08/06
 *      Author: hogehoge
 */


extern "C" {
	__declspec(dllexport)

	/**
	 * 加算
	 */
	int add(int a, int b) {
		return a + b;
	}
};

extern "C" {
	__declspec(dllexport)

	/**
	 * 減算
	 */
	int sub(int a, int b) {
		return a - b;
	}
};
プロパティのリンカーフラグを追加

f:id:m_shige1979:20170806105454j:plain
※「-static」を追加

ライブラリ名などを設定

f:id:m_shige1979:20170806105611j:plain
※インポートライブラリ名を「libsample01.lib」を作成する
※defファイルとして「sample01.def」を作成する

ビルドを行う

f:id:m_shige1979:20170806105912j:plain
Debugディレクトリ配下に作成されていることを確認

静的インポートで使用する

プロジェクトを作成する

f:id:m_shige1979:20170806110533j:plain

プロパティのリンカーのその他のオブジェクトに「libsample01.lib」を追加

f:id:m_shige1979:20170806110743j:plain
※リンカーフラグに「-static」も忘れずに追加

実装
//============================================================================
// Name        : sample02.cpp
// Author      :
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
using namespace std;

// エクスポート関数定義
extern "C" __declspec(dllexport) int add(int a, int b);
extern "C" __declspec(dllexport) int sub(int a, int b);

int main() {
	cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!

	cout << add(100, 40) << endl;
	cout << sub(100, 40) << endl;

	return 0;
}

※ヘッダーファイル用意するのめんどかったので今回は直書きです。

ビルド

f:id:m_shige1979:20170806111223j:plain
※「libsample01.dll」を配置しておくこと

実行
!!!Hello World!!!
140
60

できた感じです。

わかったこと

eclipseMinGW(64bit)はリンカーフラグに「-static」を設定しないとcoutが出力してくれない
・dllは実行プログラムと同じ場所もしくはsystem32などのシステムファイルに配置しないと読み込まない
c言語ってjavaとかと違って例外とか発生させないのでエラーでも結果がよくわからんw

所感

そもそもC言語できないんですけどね(´・ω・`)
あんましやる気はないけどとりあえずやってみた感じです。
C++のクラスとかそこそこやってみようかな…

Azure Storage ServiceでBlobの読み書きをJavaで行う

PHPではなく

Java

pom.xml

    <dependencies>
        <!-- https://mvnrepository.com/artifact/com.microsoft.azure/azure-storage -->
        <dependency>
            <groupId>com.microsoft.azure</groupId>
            <artifactId>azure-storage</artifactId>
            <version>5.0.0</version>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-io -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>
        
    </dependencies>

実装

一覧出力
import java.net.URISyntaxException;
import java.security.InvalidKeyException;

import com.microsoft.azure.storage.CloudStorageAccount;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.blob.CloudBlobClient;
import com.microsoft.azure.storage.blob.CloudBlobContainer;
import com.microsoft.azure.storage.blob.ListBlobItem;

public class Sample01 {
	
	// 接続文字列
	public static final String storageConnectionString =
		    "DefaultEndpointsProtocol=http;" +
		    "AccountName=自分のアカウント名;" +
		    "AccountKey=自分のアクセスキー";
	
	/**
	 * 指定されたコンテナのblob一覧を取得するサンプル
	 * @param args
	 * @throws URISyntaxException 
	 * @throws InvalidKeyException 
	 * @throws StorageException 
	 */
	public static void main(String[] args) throws InvalidKeyException, URISyntaxException, StorageException {
		
		// ストレージアカウントオブジェクトを取得
		CloudStorageAccount storageAccount = CloudStorageAccount.parse(storageConnectionString);
		
		// Blobクライアントオブジェクトを取得
		CloudBlobClient blobClient = storageAccount.createCloudBlobClient();
		
		// blobの指定したtest01コンテナを取得
		CloudBlobContainer container = blobClient.getContainerReference("test01");
		
		// blob情報を出力する
		for (ListBlobItem blobItem : container.listBlobs()) {
	        System.out.println(blobItem.getUri());
	    }
	}

}
読み込み
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.security.InvalidKeyException;

import com.microsoft.azure.storage.CloudStorageAccount;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.blob.CloudBlobClient;
import com.microsoft.azure.storage.blob.CloudBlobContainer;
import com.microsoft.azure.storage.blob.CloudBlockBlob;

public class Sample02 {
	
	// 接続文字列
	public static final String storageConnectionString =
		    "DefaultEndpointsProtocol=http;" +
		    "AccountName=自分のアカウント名;" +
		    "AccountKey=自分のアクセスキー";
	
	/**
	 * 指定されたコンテナのblobを読み込むサンプル
	 * @param args
	 * @throws URISyntaxException 
	 * @throws InvalidKeyException 
	 * @throws StorageException 
	 * @throws IOException 
	 */
	public static void main(String[] args) throws InvalidKeyException, URISyntaxException, StorageException, IOException {
		
		// ストレージアカウントオブジェクトを取得
		CloudStorageAccount storageAccount = CloudStorageAccount.parse(storageConnectionString);
		
		// Blobクライアントオブジェクトを取得
		CloudBlobClient blobClient = storageAccount.createCloudBlobClient();
		
		// blobの指定したtest01コンテナを取得
		CloudBlobContainer container = blobClient.getContainerReference("test01");
		
		// blobデータを読み込む
		CloudBlockBlob blob = container.getBlockBlobReference("testdata_20170716233116.txt");
		InputStream input = blob.openInputStream();
		InputStreamReader inr = new InputStreamReader(input, "UTF-8");
		
		// 読み込んだ値を出力する
		String utf8str = org.apache.commons.io.IOUtils.toString(inr);
		System.out.println(utf8str);

	}
}
書き込み
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.security.InvalidKeyException;

import com.microsoft.azure.storage.CloudStorageAccount;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.blob.BlobOutputStream;
import com.microsoft.azure.storage.blob.CloudBlobClient;
import com.microsoft.azure.storage.blob.CloudBlobContainer;
import com.microsoft.azure.storage.blob.CloudBlockBlob;

public class Sample03 {
	
	// 接続文字列
	public static final String storageConnectionString =
		    "DefaultEndpointsProtocol=http;" +
		    "AccountName=自分のアカウント名;" +
		    "AccountKey=自分のアクセスキー";
	
	/**
	 * 指定されたコンテナのblobを書き込むサンプル
	 * @param args
	 * @throws URISyntaxException 
	 * @throws InvalidKeyException 
	 * @throws StorageException 
	 * @throws IOException 
	 */
	public static void main(String[] args) throws InvalidKeyException, URISyntaxException, StorageException, IOException {
		
		// ストレージアカウントオブジェクトを取得
		CloudStorageAccount storageAccount = CloudStorageAccount.parse(storageConnectionString);
		
		// Blobクライアントオブジェクトを取得
		CloudBlobClient blobClient = storageAccount.createCloudBlobClient();
		
		// blobの指定したtest01コンテナを取得
		CloudBlobContainer container = blobClient.getContainerReference("test01");
		
		// blobデータへ書き込む準備
		CloudBlockBlob blob = container.getBlockBlobReference("testdata_20170725000000.txt");
		BlobOutputStream output = blob.openOutputStream();
		
		// データを書き込む
		output.write("aaaaaaa".getBytes());
		output.close();
	}
}

所感

今回というかファイルをローカルに扱うのは準備が面倒な感じがしたのでテキストデータを読み込んだり、書き込んだりする方法を記載。
PHPの場合はそのまま読み込んでも良いけど、Javaの場合は型が厳密なのでそこそこ手段が別れているような感じです。

scoket.ioで下層パスごとに処理を記載する

パス別に処理を分割したいみたいな…

ホスト名は実際のwebサイトみたいに扱って/hogehoge1、/hogehoge2とかでsocket通信したいみたいな感じですかね

やったこと

下層パスを用意して、処理を記載。
クライアントもそれに合わせたURIを指定してアクセス

実装

サーバ側
var io = require('socket.io').listen(3000);

// 下層パス1
io.of("/hogehoge/test1").on("connect", socketFunction1);

// 下層パス2
io.of("/hogehoge/test2").on("connect", socketFunction2);

// 接続処理1
function socketFunction1(socket) {

    console.log("/hogehoge/test1: connected");

    // メッセージ
    var msg = {
        "client": "client_" + (new Date()).getTime(),
        "msg": "接続OKです。"
    };
    socket.emit("client_info", msg);

    // 切断
    socket.on("disconnect", function() {
        console.log("/hogehoge/test1: disconnected");
    });

    // メッセージ受信
    socket.on("message", function(data) {
        console.log("送信:" + data);
    });

}

// 接続処理2
function socketFunction2(socket) {

    console.log("/hogehoge/test2: connected");

    // メッセージ
    var msg = {
        "client": "client_" + (new Date()).getTime(),
        "msg": "接続OKです。"
    };
    socket.emit("client_info", msg);

    // 切断
    socket.on("disconnect", function() {
        console.log("/hogehoge/test2:" + "disconnected");
    });

    // メッセージ受信
    socket.on("message", function(data) {
        console.log("送信:" + data);
    });

}
クライアント1
var client = require("socket.io-client");
var socket = client.connect("http://localhost:3000/hogehoge/test1");

// 接続
socket.on("connect", function() {
    console.log("/hogehoge/test1: client connected");
});

// メッセージ受信
socket.on("message", function(data) {
    console.log("/hogehoge/test1:" + "受信文字:" + data);
});

// 接続情報
socket.on("client_info", function(data) {
    clientId = data.client;
    console.log("client:" + clientId);
});

// 5秒後に切断
setTimeout(function() {
    socket.disconnect();
}, 5000);
クライアント2
var client = require("socket.io-client");
var socket = client.connect("http://localhost:3000/hogehoge/test2");

var clientId = "";

// 接続
socket.on("connect", function() {
    console.log("/hogehoge/test2 client connected");
});

// メッセージ受信
socket.on("message", function(data) {
    console.log("/hogehoge/test2: " +  "受信文字:" + data);
});

// 接続情報
socket.on("client_info", function(data) {
    clientId = data.client;
    console.log("client:" + clientId);
});

// 5秒後に切断
setTimeout(function() {
    socket.disconnect();
}, 5000);

所感

サーバ側はそれぞれ用意しないといけないのと同じでクライアントもURIを指定する必要がある。
まあ、サーバで設定するイベントの使用可否が変わってくるはずなのでこの辺の問題は受け入れる事となる。
実際にhttp://localhost:3000/sample1みたいなURIのsocket.io通信自体はあるのでその設定自体がわかっただけでも良いこととなりました。
最初はwebサーバとかでなんかしないといけないとか考えてて面倒くさいと思っていたのでちょっと楽になった感じ
javascriptjqueryしか使っていないのでnodejsをもう少し勉強してjavascriptの知識向上に役立てたい。

nodejsのsocket.ioのサーバにJavaで作成したクライアントで接続する

ソケット通信のサンプルって

基本TCP/IP関連のやつなんですね。
まあ、わかりますけど、websocketとか使う際はどんなデータが流れてくるとかどんな手法で送信したらよいとかちょっとわかりづらい事があります。

今回はJavaでsocket.ioのサンプルを探して見ました。

簡単なやつですけど助かりました。

実装

サーバ側
var io = require('socket.io').listen(3000);

// 接続
io.sockets.on("connect", function(socket) {
    console.log("connected");

    // 接続後にクライアントへ送信する
    socket.emit("message", "接続OKです。");

    // 切断
    socket.on("disconnect", function(data) {
        console.log(data);
        console.log("disconnected");
    });

    // メッセージ受信
    socket.on("message", function(data) {
        console.log("送信:" + data);
    });

});
クライアント側
package socket_sample01;

import java.net.URISyntaxException;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;

public class Sample01 {
	
	private static Socket socket;
	
	public static void main(String[] args) throws URISyntaxException, InterruptedException {
		socket = IO.socket("http://localhost:3000");

        // サーバーからのmessageがemitされた時
        socket.on("message", new Emitter.Listener() {
            public void call(Object... objects) {
                // 最初の引数を表示
                System.out.println(objects[0]);
                //サーバー側にmessageで送信
                socket.emit("message", "This is Java");
            }
        });
        
        // 接続開始
        socket.connect();
        
        // タイマーようのタスク
        class SampleTask extends TimerTask {

        	/** このメソッドがTimerから呼ばれる */
        	@Override
        	public void run() {
        		System.out.println("タスク実行:" + new Date());
        		
        		// 切断処理
        		socket.disconnect();
        	}
        }
        
        // 一定時間後に処理を切断するように指示
        TimerTask task = new SampleTask();
        Timer timer = new Timer("myTimer");
        System.out.println("処理開始:" + new Date());
        timer.schedule(task, TimeUnit.SECONDS.toMillis(3)); //3秒遅延させる
        TimeUnit.SECONDS.sleep(5);
        timer.cancel();
        System.out.println("処理終了");

	}

}

クライアントのライブラリ

  <dependencies>
    <dependency>
      <groupId>io.socket</groupId>
      <artifactId>socket.io-client</artifactId>
      <version>1.0.0</version>
    </dependency>
  </dependencies>

所感

簡単な接続自体はできた。
単純なメッセージではなく、配列とかクラスのようなデータの場合はどのような設定で送信すればよいのかちょっと調べてみよう。