投稿者「admin」のアーカイブ

Pythonと各種ツールの連携

Pythonを活用するための
「ツールとライブラリに関するノート」
を公開しています.著作権は保持していますが「フリーソフト」としますので,自由にご使用ください.

—- 掲載しているサンプルプログラムやデータ —-

test11.txt myconf.jconf
snd01.wav snd02.wav
bn_gmp01.c bn_gmp02.c bn_mpfr01.c
MeCabEx.py kspeech.py

Pythonによるデータ処理のテキスト

学生に教えるためのテキストを作っています.
「Python3を用いたデータ処理の基礎」
無料で差し上げますので,意見や感想をくださいませ.
→ katsu_wm%mukogawa-u.ac.jp (’%’を’@’に変えるとメールアドレスになります)
→ コメントもできます(非公開)(名前,メールアドレス無しでも大丈夫です)
 
ご意見,ご助言をいただいた方は,テキストの謝辞の頁に謝意と共にお名前を掲載させていただきます.(ご希望なさらない方はその旨ご連絡ください)

「Python3を用いたデータ処理の基礎」(PDF形式,78ページ,2.02MB)

まだ試作段階で,どんどん改訂しています.

ここに公開しているテキストは「フリーソフトウェア」とします.(著作権は保持しています)
印刷,再配布共にしていただいて構いませんが,その際は内容の改変をせずにお願いします.
 
● テキスト中のサンプルデータ

dat_kokugo.csv dat_kokugo_noheader.csv dat_seiseki.csv
dat_seiseki_2.csv address_jp.csv dat_rand1M.csv
db01_gov_office.csv db01_geographic.csv genDB01.py

Java FX 8 の入門書

うちのゼミの活動を通してわかったことをまとめてマニュアルにしています.
 
まだ世間では Java は SE 7 が標準なのでしょうか.
Java SE 8 / Java FX 8 に関する情報がまだ世間に少なすぎて,仕方がないので本家ORACLEのサイトを見ながら,サンプルプログラム作って実験しながら自力で使い方を発掘しています.
 
まだまだ発展途上で,やり残し満載のマニュアルですが,どんどん加筆してゆきます.
 
PDFで約2.7MBです→javafx_main.pdf
 
まだクレームをいただけるような状態でもないですが,ご意見いただけたらありがたいです.
→ katsu_wm%mukogawa-u.ac.jp (%を@に変えてください)
 
【マニュアル中のサンプルプログラム】
FXsample01.java
FXsample02.java
FX3Dsample01.java
FX3Dsample03.java
 貼り付ける画像:texture.gif
FXMLsample01.fxml
FXMLsample01.java
FXMLappl001.java
FXMLDocumentController.java
FXMLDocument.fxml
FXChart01.java
FXChart02.java
FXChart03.java
FXChart04.java
FXimage01.java
FXimage02.java
 読み込む画像:Earth.jpg
AnimSample01.java
FX3Dsample04.java
 貼り付ける画像:physical-free-world-map-b1.jpg
DateTest01.java
DateTest02.java
DateTest06.java
DateTest07.java
FXsample05.java
LmbdSample01.java
SoundTest01.java
SoundTest02.java
SoundTest03.java
 サウンドサンプル:music001.wav(サイズに注意!:17MB)
 (提供元:フリーBGM素材 『霞む道を』 試聴ページ フリーBGM DOVA-SYNDROME
GUIdesign01のプロジェクト
FXsample04.java
 
—– 目次 —————————————————–
1 はじめに
2 GUI構築の基本
2.1 Applicationクラス
2.2 StageクラスとSceneクラス
2.3 ウィンドウサイズの変更を禁止する設定
2.4 GUIの可視属性の設定
2.5 複数のウィンドウを生成する方法
2.6 アプリケーションの終了に関する処理
2.6.1 アプリケーション終了時に呼び出されるメソッド
3 三次元グラフィックス
3.1 基礎事項
3.2 直方体,円柱,球
3.2.1 シーングラフの準備
3.2.2 Colorクラスによる色の指定
3.2.3 基本的な三次元オブジェクトの扱い
3.2.4 平行移動,回転,拡縮
3.2.5 光源
3.2.6 直投影型カメラ
3.2.7 透視投影型カメラ
3.3 メッシュ・グラフィックス
3.3.1 メッシュへのテクスチャの貼付け
4 FXMLを利用したGUI構築
4.1 サンプルプログラム
4.2 NetBeans IDEの利用
4.2.1 生成された雛形を利用したアプリケーション開発
4.2.2 単独で動作するアプリケーションの生成について
4.3 Java FX Scene Builder
4.3.1 インスペクタ
4.3.2 イベントハンドラとの関連付け
4.3.3 NetBeans IDEとの連携
5 図形の描画
5.1 Shapeを利用した描画
5.1.1 線の描画: Line / Polyline
5.1.2 線に属性を与えるメソッド
5.1.3 図形描画における「枠」と「塗り」
5.1.4 各種図形の描画: Rectangle / Circle / Ellipse / Arc / Polygon
5.1.5 塗りの属性
5.1.6 文字の描画: Text
5.1.6.1 システムで利用できるフォントを調べる方法
5.1.7 画像の表示: ImageView
5.1.8 Shapeオブジェクトの位置の設定: relocate
5.2 Canvasを利用した描画
5.2.1 GraphicsContext
5.2.2 各種の描画メソッド
5.3 チャートの描画
5.3.1 棒グラフ:BarChart
5.3.2 折れ線グラフ:LineChart
5.3.3 円グラフ:PieChart
5.4 画像データの扱い
5.4.1 画像データの入力: Imageクラス
5.4.2 画素(ピクセル)の操作
5.4.3 画像データの出力
5.4.4 サンプルプログラム
5.4.5 ノードの描画状態のキャプチャ
6 時間によるイベント処理(アニメーション)
6.1 タイミング・イベントについて
6.2 タイムラインとキーフレーム
6.3 サンプルプログラム
7 日付と時刻
7.1 旧来のAPI(Java SE 7)
7.1.1 日付と時刻のためのクラス
7.2 新しいAPI(Java SE 8)
7.2.1 基本的なクラス
7.2.2 日付・時刻に関する基本的な処理
7.2.3 和暦の扱い
8 ラムダ式
8.1 イベントハンドラ登録への応用
8.2 関数型インターフェースでの応用
9 サウンドの再生(Java SE 7)
9.1 基礎事項
9.2 実用的なサウンド再生
10 メディアデータの再生(Java FX 8)
10.1 動画再生に関すること
11 付録
11.1 Java FXで利用できるGUIの部品(代表的なもの)
11.1.1 コンテナ:Containers
11.1.1.1 HBox,VBoxを用いたGUIの配置
11.1.2 コントロール:Controlls
11.1.2.1 項目データを与える方法
11.1.3 値の変化を検知するイベント
11.2 メニューの構築
11.3 ファイル選択ダイアログの実装
11.4 Java FX 8 の重要なクラス
11.5 イベントについて
11.5.1 旧来のGUIで扱うイベント
11.5.2 タッチデバイスで扱うイベント
—————————————————————-

超入門:立体の表示,回転と平行移動,カメラ,光源の基本

超入門:立体の表示,回転と平行移動,カメラ,光源の基本
 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.stage.Stage;
import javafx.scene.shape.*;
import javafx.scene.transform.*;
import javafx.geometry.Point3D;
 
public class FX3Dsample01 extends Application {
 
	@Override
	public void start(Stage Stage) {
		//--- Top Node and Scene ---
		Group root = new Group();
		Scene scene = new Scene(root, 1024, 768, Color.rgb(0,0,0));
 
		// Axis for Rotation
		Point3D aX = new Point3D(100,0,0);
		Point3D aY = new Point3D(0,100,0);
		Point3D aZ = new Point3D(0,0,100);
 
		//--- Solid Model Generation ---
		// (Box)
		Box bx1 = new Box(300d,200d,150d);
		root.getChildren().add(bx1);
		PhongMaterial mt1 = new PhongMaterial(); // 別々に作る!
		mt1.setDiffuseColor(Color.rgb(255,0,0));
		bx1.setMaterial(mt1);
		bx1.getTransforms().addAll(
			new Translate(-300d,0d,0d), // 先に平行移動
			new Rotate(30,aX),
			new Rotate(30,aY),
			new Rotate(20,aZ)
		);
		// (Cylinder)
		Cylinder cl1 = new Cylinder(80d,300d);
		root.getChildren().add(cl1);
		PhongMaterial mt2 = new PhongMaterial(); // 別々に作る!
		mt2.setDiffuseColor(Color.rgb(0,255,0));
		cl1.setMaterial(mt2);
		cl1.getTransforms().addAll(
			new Rotate(30,aX),
			new Rotate(0,aY),
			new Rotate(-20,aZ)
		);
		// (Sphere)
		Sphere sp1 = new Sphere(140d);
		root.getChildren().add(sp1);
		PhongMaterial mt3 = new PhongMaterial(); // 別々に作る!
		mt3.setDiffuseColor(Color.rgb(0,0,255));
		sp1.setMaterial(mt3);
		sp1.getTransforms().addAll(
			new Translate(280d,0d,0d)
		);
 
		//--- Light Setting ---
		AmbientLight aLight = new AmbientLight(Color.rgb(127, 127, 127));
		root.getChildren().add(aLight);
 
		PointLight pLight = new PointLight(Color.rgb(255,255,255));
		pLight.setTranslateX(500d);
		pLight.setTranslateY(-300d);
		pLight.setTranslateZ(-200d);
		root.getChildren().add(pLight);
 
		//--- Camera Setting ---
		ParallelCamera cmr = new ParallelCamera();
		cmr.getTransforms().addAll(
			new Translate(-512d,-384d,0d)
		);
		scene.setCamera(cmr);
 
		//--- Window Activation ---
		Stage.setTitle("FX3Dsample01");
		Stage.setScene(scene);
		Stage.show();
	}
 
	public static void main(String[] args) {
		launch(args);
	}
}

 
FX3Dsample01_exe

FXMLアプリケーション構築例(NetBeans IDE & Java FX Scene Builder)

マニュアルをまとめつつあります.)
 
 ここでは,NetBeansIDEとJava FX Scene Builerを用いた画像ビューワのアプリ構築の例を紹介します.
 
1. 新規プロジェクトの作成(FXMLappl01)
FXMLappl01
 
「Java FX FXMLアプリケーション」を選択します.
FXMLappl02
 
「プロジェクト名」と「FXML名」を設定します.
FXMLappl03
 
空のFXMLを追加します.
FXMLappl04
 
FXMLファイルの名前を指定します.
FXMLappl05
 
ここでは既存のFXMLコントローラを使うことにします.
FXMLappl06
 
FXMLのコード:FXML1.fxml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
 
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
 
<AnchorPane id="AnchorPane" prefHeight="92.0" prefWidth="243.0"
 xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8"
 fx:controller="fxmlappl01.FXML1Controller">
<children>
  <Button fx:id="btn1" layoutX="36.0" layoutY="33.0" mnemonicParsing="false"
   onAction="#handleButton_btn1" prefHeight="26.0" prefWidth="172.0"
   text="Open Another Window" />
</children>
</AnchorPane>

 
FXMLのコード:FXML2.fxml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
 
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
 
<AnchorPane id="AnchorPane" prefHeight="482.0" prefWidth="600.0"
 xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8"
 fx:controller="fxmlappl01.FXML1Controller">
<children>
  <Button fx:id="btn21" layoutX="14.176322937011719" layoutY="1.0"
   mnemonicParsing="false" onAction="#handleButton_btn21" text="image 1" />
  <Button fx:id="btn22" layoutX="88.17632293701172" layoutY="1.0"
   mnemonicParsing="false" onAction="#handleButton_btn22" text="image 2" />
  <Button fx:id="btn23" layoutX="163.17632293701172" layoutY="1.0"
   mnemonicParsing="false" onAction="#handleButton_btn23" text="erase" />
  <ImageView fx:id="iv1" fitHeight="437.0" fitWidth="574.0" layoutX="14.0"
   layoutY="35.0" pickOnBounds="true" preserveRatio="true" />
</children></AnchorPane>

 
ファイル:FXMLappl01.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package fxmlappl01;
 
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
 
public class FXMLappl01 extends Application {
 
    public static Stage stage2;
 
    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("FXML1.fxml"));
 
        Scene scene = new Scene(root);
 
        stage.setTitle("Main Window");
        stage.setScene(scene);
        stage.show();
 
 
        /* Another Window */
        stage2 = new Stage();
        stage2.initOwner(stage);
 
        Parent root2 = FXMLLoader.load(getClass().getResource("FXML2.fxml"));
 
        Scene scene2 = new Scene(root2);
 
        stage2.setTitle("Picture Window");
        stage2.setScene(scene2);
        stage2.show();
 
        /* image from "http://www.ashinari.com/" */
        Share.img1 = new Image(getClass().getResourceAsStream("1.jpg"));
        Share.img2 = new Image(getClass().getResourceAsStream("2.jpg"));
    }
 
    public static void main(String[] args) {
        launch(args);
    }
 
}

 
ファイル:Share.java

1
2
3
4
5
6
7
package fxmlappl01;
 
import javafx.scene.image.*;
 
public class Share {
    public static Image img1, img2;
}

 
ファイル:FXML1Controller.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package fxmlappl01;
 
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.image.*;
 
public class FXML1Controller implements Initializable {
 
    @FXML
    private Button btn1, btn21, bnt22, btn23;
    @FXML
    private ImageView iv1;
 
    @FXML
    private void handleButton_btn1(ActionEvent ev) {
        System.out.println("Open Another Window!");
        FXMLappl01.stage2.show();
    }
 
    @FXML
    private void handleButton_btn21(ActionEvent ev) {
        iv1.setImage(Share.img1);
    }
 
    @FXML
    private void handleButton_btn22(ActionEvent ev) {
        iv1.setImage(Share.img2);
    }
 
    @FXML
    private void handleButton_btn23(ActionEvent ev) {
        iv1.setImage(null);
    }
 
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }    
 
}

 
このアプリを実行したところ:
FXMLappl01_exe
 
プロジェクト全体(Zip圧縮):FXMLappl01.zip

まず最初に(C/C++ 超入門)

C言語では「関数」を定義することでプログラミングします.
すなわち,関数 f(x,y,z) を評価すると,その定義として記述されたプログラムを実行します.

もう少しわかりやすく説明します.

tasu(x,y) := x + y

として関数 tasu を定義しますと,

a = tasu(1,2)

を計算(評価)することで変数 a に 3 が格納されます.
これをC言語で記述すると

int tasu(x,y)
int x,y;
{
	return(x+y);
}

となります.

C言語ではメインのプログラム本体も1つの関数 main として記述します.
例えば

int main()
{
	int a,b,c;
 
	a = 1;
	b = 2;
	c = a + b;
}

と記述して,これをコンパイルして実行すると,変数 c に 3 が格納されます.

先に定義した関数 tasu を main から呼び出すこともでき,

int main()
{
	int a,b,c;
 
	a = 1;
	b = 2;
	c = tasu(a,b);
}

と書くと a+b の結果が c に格納されます.

【ポインタと値】

C言語の初心者がまずはじめに悩むのが「ポインタ」です.
コンピュータ上のデータは変数などの記憶に格納されます.
ということは当然ですが,そのデータを格納している記憶域の「場所」があります.
また,コンピュータの記憶は1バイトづつ一直線に並んだ構造をしているので,
記憶の場所は「先頭から〜番目」という形で表現されます.

このように,記憶の「〜番目」を意味するものが「ポインタ」だと理解するとわかりやすいです.
言い換えると「記憶域のアドレス」の値がポインタであると言うこともできます.

変数のポインタ(アドレス)の値を得るには ‘&’ を使います.
すなわち,変数 a の格納場所の番地を求めるには &a とします.

例.記憶域の中での変数の場所(アドレス)を調べる
次のようなプログラムを作って実行してみましょう.

#include	<stdio.h>
 
int main()
{
	int	a = 3;
 
	printf("a = %d, address = %u\n",a,&amp;a);
}</stdio.h>

これを実行すると次のような表示になります.

a = 3, address = 1352710956

これはどういう意味かというと,
「変数 a には値 3 が入っており,それを格納している記憶域の番地(アドレス)は 1352710956 である」
ということです.

「ポインタ」はどんな場合に使うのか?
一言で「ポインタは〜に使う」とは言えないですが,よくある使用例を紹介します.
プログラムで扱うデータは,変数として扱うだけでは不便な場合があります.
例えば「データレコード」のような概念がありますが,それは複数の変数たちをまとめて1つの意味ある情報として扱う考え方です.C言語では「構造体」,C++では「クラス」というものがありますが,それらは「データレコード」を実現するものと考えることができます.

現実的なプログラミングでは,1つのアプリケーションをつくるために,幾つものサブルーチン(C/C++では関数)に分割して開発するのが普通です.分割された関数にデータレコードを引き渡す際にこのポインタが便利です.
どういうことかというと,関数にデータを渡す際に「データは記憶のこの番地においてある」という情報を相手関数に知らせるだけでよいということになり,データレコードの中身の全てを取り出して関数に送りつける必要がなくなるわけです.(わかります?)

ポインタの活用方法については,実際にプログラミングをしながら身につけて行きましょう.

【構造体】

C言語でデータレコードを実現するものとして構造体があります.
例えば次のようなプログラムを見てみましょう.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include	<stdio.h>
#include	<string.h>
 
typedef	struct {
	char	name[32];
	int	age;
	int	gender;	// 1:male, 2:female
	char	tel[24];
} PersonalInfo;
 
int main()
{
	PersonalInfo	db[100];
 
	strcpy( db[0].name, "Sato Taro" );
	db[0].age    = 29;
	db[0].gender = 1;
	strcpy( db[0].tel,  "123-4567" );
 
	printf("size of PersonalInfo:%lu, size of db:%lu bytes\n",
		sizeof(PersonalInfo),sizeof(db));
}</string.h></stdio.h>

このプログラムは個人情報を保持する簡単なデータベースを実現するものです.
氏名(name),年齢(age),性別(gender),電話番号(tel)を1つのまとまりとする構造体を記述し,それを PersonalInfo という型として定義しています.
main の中では PersonalInfo 型のレコードの配列 db を定義しています.また,PersonalInfo と db のデータサイズを出力しています.
実行例

size of PersonalInfo:64, size of db:6400 bytes

このように,構造体を用いると複数の変数からなるデータのまとまりを1つのレコードとして扱うことができます.

構造体の要素(メンバ)へのアクセス
上のプログラム例のように,ドット ‘.’ を使って構造体の要素(メンバ)にアクセスすることができます.

■■■ C++ ■■■

さて C++ ですが,基本的には C 言語の文法がベースになります.
なので「Cは勉強せずに,C++だけ学ぶ」というのはできません.(念のため)

ファイルの所有者・グループの設定

UNIXにおいてファイルの所有者や所属グループを変更するには chown 関数を呼び出します.
 
使い方: chown(ファイルのパス, ユーザID, グループID)
 
例えば,対象ファイルのパス名を格納する記憶へのポインタを char *p, ユーザIDが uid_t u に,グループIDが gid_t g に格納されているとき chown( p, u, g ) として実行します.
 
処理が正常に終了した場合,戻り値は0となります.
 
サンプルプログラム ファイル a の所有者・グループを設定する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include	<stdio.h>
#include	<sys/types.h>
#include	<unistd.h>
 
int main()
{
	char	p[] = "a";
//	uid_t	uid = 501;
	uid_t	uid = 503;
	gid_t	gid = 20;
 
	if ( chown(p,uid,gid) != 0 ) {
		fprintf(stderr,"chown failed.\n");
	}
}

シンボリックリンクの作成と削除

 「シンボリックリンク」はUNIX独特のものです.
 
大抵のOSでは,ファイルの別名を意味するアイコンを作ることができます.
Microsoft Windowsでは「ショートカット」,
Apple OS Xでは「エイリアス」というものを作って,
ファイル本体とは別のものとして別名のアイコンを作ることがあります.
 
UNIX独自のファイルの別名として「シンボリックリンク」を理解してください.
 
シンボリックリンクを作成するための関数に symlink というものがあります.
使い方は簡単です.
 
元のファイルのパス名を文字列として格納した記憶へのポインタを char *p1,
リンク(別名)のパス名を文字列として格納した記憶へのポインタを char *p2,
として symlink(p1,p2) として関数を呼び出すことでシンボリックリンクが作成されます.
正常に実行が終了した場合の戻り値は 0 です.
 
サンプルプログラム1: ファイル s_symlink.c のリンク(別名)を s_symlink_l として作成する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include	<stdio.h>
#include	<unistd.h>
 
int main()
{
	int	r;
	char	p1[] = "s_symlink.c", p2[] = "s_symlink_l", lnk[256];
 
	r = symlink(p1,p2);
	if ( r == 0 ) {
		r = readlink(p2,lnk,256);
		fprintf(stderr,"symlnk success!: %s -> %s\n",p2,lnk);
 
	} else {
		fprintf(stderr,"symlnk failure.\n");
	}
}

 
サンプルプログラム2: リンク s_symlink_l を解除する

1
2
3
4
5
6
7
8
9
10
11
12
13
#include	<stdio.h>
#include	<unistd.h>
 
int main()
{
	int	r;
	char	p[] = "s_symlink_l";
 
	r = unlink(p);
	if ( r != 0 ) {
		fprintf(stderr,"unlnk failure: %d\n",r);
	}
}

ディレクトリの作成/削除/移動

【ディレクトリの作成】
 ディレクトリを作成するための関数 mkdir の使い方について説明します.
 
使い方: mkdir( 作成するディレクトリのパス名 , アクセス権 )
 
ディレクトリを作成する際には,誰に対して読み書き・実行を許可するかという「アクセス権」を設定します.
 
アクセス権は
 1) ユーザに対する読み書き・実行
 2) グループに対する読み書き・実行
 3) 他人に対する読み書き・実行
の3種類を設定します.
 
アクセス権を意味する記号(定義)は下記の通りで,それらを論理和として組み合わせ,整数型の値にして mkdir の引数にします.

S_IRWXU	00700	ファイル所有者のアクセス許可用のビットマスク
S_IRUSR	00400	所有者の読み込み許可
S_IWUSR	00200	所有者の書き込み許可
S_IXUSR	00100	所有者の実行許可
 
S_IRWXG	00070	グループのアクセス許可用のビットマスク
S_IRGRP	00040	グループの読み込み許可
S_IWGRP	00020	グループの書き込み許可
S_IXGRP	00010	グループの実行許可
 
S_IRWXO	00007	他人 (others) のアクセス許可用のビットマスク
S_IROTH	00004	他人の読み込み許可
S_IWOTH	00002	他人の書き込み許可
S_IXOTH	00001	他人の実行許可

 
サンプルプログラム: アクセス権を設定してディレクトリ s_mkdir_d をつくる

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include	<stdio.h>
#include	<sys/stat.h>
 
int main()
{
	const char	dname[] = "s_mkdir_d";
	int		r;
	mode_t		mode;
 
	/*--- mode ---- read -- write - execute --------*
	 |   user	  1	  1	  1		|
	 |   group	  1	  0	  1		|
	 |   other	  1	  0	  1		|
	 *----------------------------------------------*/
	mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
 
	r = mkdir(dname,mode);
	printf("result: %d\n",r);
}

 
【ディレクトリの削除】
 ディレクトリを削除するための関数 rmdir の使い方について説明します.
 
使い方: rmdir( 削除するディレクトリのパス名 )
 
サンプルプログラム ディレクトリ s_mkdir_d を削除する

1
2
3
4
5
6
7
8
9
10
11
#include	<stdio.h>
#include	<unistd.h>
 
int main()
{
	const char	dname[] = "s_mkdir_d";
	int		r;
 
	r = rmdir(dname);
	printf("result: %d\n",r);
}

 
【ディレクトリの移動】
 ディレクトリを移動(カレントディレクトリを変更)するための関数 cd の使い方について説明します.
 
使い方: chdir( ディレクトリのパス名 )
 これを実行することで,カレントディレクトリを「ディレクトリのパス名」にすることができます.
 
サンプルプログラム ディレクトリ s_mkdir_d2 を作成した後そこに移動し,更に同じ名前のディレクトリ s_mkdir_d2 を作成する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include	<stdio.h>
#include	<unistd.h>
#include	<sys/stat.h>
 
int main()
{
	const char	dname[] = "s_mkdir_d2";
	int		r;
	mode_t		mode;
 
	/*--- mode ---- read -- write - execute --------*
	 |   user	  1	  1	  1		|
	 |   group	  1	  0	  1		|
	 |   other	  1	  0	  1		|
	 *----------------------------------------------*/
	mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
 
	r = mkdir(dname,mode);
	printf("result: %d\n",r);
 
	if ( r == 0 ) {
		r = chdir(dname);
		if ( r == 0 ) {
			r = mkdir(dname,mode);
			printf("result: %d\n",r);
		} else {
			fprintf(stderr,"chdir failure: %s\n",dname);
		}
	} else {
		fprintf(stderr,"mkdir failure(1): %s[%d]\n",dname,r);
	}
}

ファイルのタイムスタンプの変更

指定したファイルのタイムスタンプを変更する方法について説明します.
 
UNIX ではファイルの時間に関する情報には次の3つのものがあります.
1) 最終アクセス時刻: atime
2) 最終更新時刻  : mtime
3) 最終属性変更時刻: ctime
 
この内 atime と mtime を,関数 utime を使って変更することができます.
 
utime を実行するに先立って,atime, mtime の値を utimbuf 構造体に格納しておく必要があります.
この構造体の内容に従って,指定したファイルのタイムスタンプを変更します.
 
utimbuf 構造体の定義

struct utimbuf {
	time_t actime;	/* atime : access time */
	time_t modtime;	/* mtime : modification time */
};

 
char *fname で示されるパスのファイルのタイムスタンプを struct utimbuf utb の内容にする

utime(fname,&utb)

処理が正常に終了すると戻り値は0となる.
 
サンプルプログラム s_utime.c:ファイル s_utime.out のタイムスタンプを1年後に設定する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include	<stdio.h>
#include	<time.h>
#include	<sys/types.h>
#include	<utime.h>
 
int main()
{
	FILE	*f;
	time_t	t;
	char	ftime[128], fname[128];;
	struct	tm	*tstamp;
	struct	utimbuf	utb;
 
	/* file generation */
	sprintf(fname,"s_utime.out");
	f = fopen(fname,"w");
	fclose(f);
 
	/* setting 1 year later */
	t = time(NULL) + 86400 * 365;
	tstamp = gmtime(&t);
 
	strftime(ftime,sizeof(ftime),"%Y/%m/%d(%a) %H:%M:%S",tstamp);
	printf("%s\n",ftime);
 
	utb.actime = t;
	utb.modtime = t;
 
	/* changing time stamp */
	if ( utime(fname,&utb) != 0 ) {
		fprintf(stderr,"utime failure!\n");
	}
}

実行例

$ date			← 現在の日付を調べる
2015年 3月28日 土曜日 18時11分16秒 JST
$ s_utime		← 1年後の日付にする
2016/03/27(Sun) 09:11:24

この後 “ls -la” コマンドで s_utime.out のタイムスタンプを調べる

-rwxr-xr-x    1 user1  staff    9056  3 28 17:57 s_utime
-rw-r--r--    1 user1  staff     585  3 28 17:57 s_utime.c
-rw-r--r--    1 user1  staff       0  3 27  2016 s_utime.out

ディレクトリを開く

ディレクトリの配下には,いくつかのファイルやサブディレクトリが配置されています.
 
ここでは,ディレクトリに登録されているそれらの項目の名前を取得する方法について説明します.
 
1. ディレクトリを開く
 指定した名前のディレクトリを開くには opendir 関数を呼び出します.
この関数はディレクトリに関する情報を収めた DIR 構造体へのポインタを戻り値として返します.
処理が失敗すると NULL を返します.
 
ディレクトリを開いた後は,そのポインタが指し示す構造体のメンバにアクセスすることでディレクトリに関する情報を取得することができます.
 
例 char *path に与えられたディレクトリを開く

DIR	*dr;
dr = opendir(path);

 
2. ディレクトリ配下の項目を取得する
 readdir 関数を呼び出すことで開いたディレクトリの配下の項目を1つづつ取得することができます.
この関数は,項目の情報を格納する dirent 構造体へのポインタを戻り値として返します.
(項目を全部取得してしまった後は戻り値は NULL となります)
 
例 dr として開いたディレクトリから項目を取得する

struct	dirent	*de;
de=readdir(dr)

 
dirent 構造体の定義

struct dirent {
    ino_t          d_ino;       /* inode 番号 */
    off_t          d_off;
    unsigned short d_reclen;    /* このレコードの長さ */
    unsigned char  d_type;      /* ファイル種別 */
    char           d_name[256]; /* ファイル名 */
};

de->d_name を参照することで項目のファイル名を取得できる.
 
3. ディレクトリを閉じる
 ディレクトリへのアクセスが終われば,閉じる必要があります.
開いたディレクトリを閉じるには関数 closedir を呼び出します.
 
例 dr として開いたディレクトリを閉じる

closedir(dr);

 
サンプルプログラム: 指定したディレクトリ配下の項目を全てリストアップする

#include	<stdio.h>
#include	<sys/types.h>
#include	<dirent.h>
 
int main(ac,av)
int  ac;
char **av;
{
	char	*path;
	DIR	*dr;
	struct	dirent	*de;
	int	i = 0;
 
	path = av[1];
	dr = opendir(path);
	if ( dr == NULL ) {
		fprintf(stderr,"Can not open directory: %s\n",path);
		return(-1);
	}
 
	while ( -1 ) {
		if ( (de=readdir(dr)) == NULL ) {
			break;
		}
		i++;
		printf("item %03d: %s\n",i,de->d_name);
	}
 
	closedir(dr);
}

 
実行例: 上のサンプルを s_opendir.c として作って実行する.
プログラム本体が次のようなディレクトリにあるものとする.

$ ls -la
total 1200
drwxr-xr-x   16 user1  staff     544  3 27 19:47 .
drwxr-xr-x+ 166 user1  staff    5644  2 28 15:04 ..
-rw-------    1 user1  staff   12288  3 27 19:47 .s_opendir.c.swp
-rwxr-xr-x    1 user1  staff     369  6  1  2014 cmd1
-rw-r--r--    1 user1  staff     360  6  1  2014 inp
-rwxr-xr-x    1 user1  staff    8936  3 15 16:55 s_fstat
-rw-r-----    1 user1  staff    1488  3 15 16:55 s_fstat.c
-rwxr-xr-x    1 user1  staff    8780  3 27 19:47 s_opendir
-rw-r--r--    1 user1  staff     423  3 27 19:47 s_opendir.c
-rwxr-xr-x    1 user1  staff    8688  3 16 19:29 s_time
-rw-r--r--    1 user1  staff     450  3 16 19:29 s_time.c
-rwxr-xr-x    1 user1  staff    8568  3 15 21:49 s_timeb
-rw-r--r--    1 user1  staff     333  3 16 20:08 s_timeb.c
lrwxr-xr-x    1 user1  staff       9  3 15 16:22 sl -> s_fstat.c
-rw-r--r--@   1 user1  staff  258640  3 15 16:26 sl2
-rw-r--r--@   1 user1  staff  258640  3 15 20:57 sl3

ここでプログラムを実行して,このディレクトリ自身 “.” の中身をリストアップする.

$ s_opendir .
item 001: .
item 002: ..
item 003: .s_opendir.c.swp
item 004: cmd1
item 005: inp
item 006: s_fstat
item 007: s_fstat.c
item 008: s_opendir
item 009: s_opendir.c
item 010: s_time
item 011: s_time.c
item 012: s_timeb
item 013: s_timeb.c
item 014: sl
item 015: sl2
item 016: sl3

ファイルの属性の取得

ファイルシステムにはファイルディレクトリリンクといった異なる種類の実体があります.また,それらにはアクセスされた時刻の情報も属性として記録されています.
 
ここでは,指定したパスの実体の属性を調べる方法について説明します.
 
指定したパスの属性を取得するには stat という関数を呼び出します.
また,stat の呼び出しで得られた属性の情報は stat 構造体に格納されます.
 
例.ポインタ cahr *path によって示されるパス名の文字列があるとき,そのパスの属性を得る方法

struct	stat	buf;
r = stat(path,&buf);

(int r は戻り値で,stat の処理が正常に終了した場合は 0 となる)
これにより,構造体 buf にパスの各種の属性が格納される.
 
指定したパスがシンボリックリンクである場合,そのリンク先の実体の属性を求めるのか,あるいはリンクそのものの属性を求めるかは全く意味が異なります.
「リンクであるかどうか」の情報が必要な場合は stat ではなく lstat を用います.
 
構造体 stat の定義

struct stat {
	dev_t     st_dev;     /* ファイルがあるデバイスの ID */
	ino_t     st_ino;     /* inode 番号 */
	mode_t    st_mode;    /* アクセス保護 */
	nlink_t   st_nlink;   /* ハードリンクの数 */
	uid_t     st_uid;     /* 所有者のユーザー ID */
	gid_t     st_gid;     /* 所有者のグループ ID */
	dev_t     st_rdev;    /* デバイス ID (特殊ファイルの場合) */
	off_t     st_size;    /* 全体のサイズ (バイト単位) */
	blksize_t st_blksize; /* ファイルシステム I/O での
					ブロックサイズ */
	blkcnt_t  st_blocks;  /* 割り当てられた 512B のブロック数 */
	struct timespec st_atim;  /* 最終アクセス時刻 */
	struct timespec st_mtim;  /* 最終修正時刻 */
	struct timespec st_ctim;  /* 最終状態変更時刻 */
};
#define st_atime st_atim.tv_sec
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec

 
この構造体のメンバにファイルに関する各種の情報が格納されています.
特に st_mode には,それがファイルなのかディレクトリなのか,
あるいはシンボリックリンクなのかという情報が格納されており,
実体の種別を識別するのに使うことができます.
 
ファイル/ディレクトリ/シンボリックリンクの判別
 st_mode から種別を判定する下記のような関数があります.
S_ISREG : 通常のファイルであることを判定
S_ISDIR : ディレクトリであることを判定
S_ISLNK : シンボリックリンクであることを判定
 
サンプルプログラム : 指定したパスの情報を表示するプログラム

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include	<stdio.h>
#include	<unistd.h>
#include	<time.h>
#include	<sys/types.h>
#include	<sys/stat.h>
 
struct	stat	buf;
struct	tm	*ts;
 
int main(ac,av)
int	ac;
char	**av;
{
	int	r, size, mode;
	char	*path, tf[128];
 
	if ( ac < 2 ) {
		fprintf(stderr,"No arguments.\n");
		return(-1);
	}
 
	path = av[1];	// パス名を取得
	fprintf(stderr,"path: %s\n",path);
 
//	r = stat(path,&buf);	// パスの属性を取得
	r = lstat(path,&buf);	// パスの属性を取得
	if ( r != 0 ) {		// エラー処理
		fprintf(stderr,"error: stat = %d\n",r);
		return(-1);
	}
 
//	ts = localtime(&(buf.st_atime));	// 最終アクセス時刻を取得
	ts = gmtime(&(buf.st_atime));		// 最終アクセス時刻を取得
//	strftime(tf,sizeof(tf),"%Y/%m/%d(%a) %H:%M:%S(%z)",ts);
	strftime(tf,sizeof(tf),"%Y/%m/%d(%a) %H:%M:%S",ts);
	printf("Last access(st_atime)       = %s\n",tf);	// 表示
 
//	ts = localtime(&(buf.st_mtime));	// 最終修正時刻を取得
	ts = gmtime(&(buf.st_mtime));		// 最終修正時刻を取得
//	strftime(tf,sizeof(tf),"%Y/%m/%d(%a) %H:%M:%S(%z)",ts);
	strftime(tf,sizeof(tf),"%Y/%m/%d(%a) %H:%M:%S",ts);
	printf("Last modified(st_mtime)     = %s\n",tf);	// 表示
 
//	ts = localtime(&(buf.st_ctime));	// 最終状態変更時刻を取得
	ts = gmtime(&(buf.st_ctime));		// 最終状態変更時刻を取得
//	strftime(tf,sizeof(tf),"%Y/%m/%d(%a) %H:%M:%S(%z)",ts);
	strftime(tf,sizeof(tf),"%Y/%m/%d(%a) %H:%M:%S",ts);
	printf("Last state change(st_ctime) = %s\n",tf);	// 表示
 
	size = (int)(buf.st_size);	// サイズを取得
	printf("size: %d (bytes)\n",size);	// 表示
 
	mode = (int)(buf.st_mode);	// アクセス属性の取得
	printf("mode: %o\n",mode);	// 表示
 
	// ファイル/ディレクトリ/シンボリックリンクの判定
	printf("type: /");
	if ( S_ISREG(buf.st_mode) ) {
		printf("regular file/");
	}
	if ( S_ISDIR(buf.st_mode) ) {
		printf("directory/");
	}
	if ( S_ISLNK(buf.st_mode) ) {
		printf("simlink/");
	}
	printf("\n");
}

このプログラムを s_fstat という名前で作成して実行した例を次に示します.
 
実行例1 ディクレイトリ “.” の属性を調べる例

$ s_fstat .
path: .
Last access(st_atime)       = 2015/03/27(Fri) 10:28:37
Last modified(st_mtime)     = 2015/03/16(Mon) 11:08:31
Last state change(st_ctime) = 2015/03/16(Mon) 11:08:31
size: 442 (bytes)
mode: 40755
type: /directory/
$

 
実行例2 ソースファイル “s_fstat.c” の属性を調べる例

$ s_fstat s_fstat.c
path: s_fstat.c
Last access(st_atime)       = 2015/03/23(Mon) 10:15:09
Last modified(st_mtime)     = 2015/03/15(Sun) 07:55:09
Last state change(st_ctime) = 2015/03/15(Sun) 07:55:09
size: 1488 (bytes)
mode: 100640
type: /regular file/
$

 
実行例3 シンボリックリンク “sl” の属性を調べる例

$ s_fstat sl
path: sl
Last access(st_atime)       = 2015/03/15(Sun) 07:22:56
Last modified(st_mtime)     = 2015/03/15(Sun) 07:22:56
Last state change(st_ctime) = 2015/03/15(Sun) 07:22:56
size: 9 (bytes)
mode: 120755
type: /simlink/
$

時刻の扱い(1)

 UNIX系システムの時刻情報の考え方はとても単純です.
それはどのようなものかというと,
 
「”西暦1970年1月1日0時0分0秒”を基準として,その後の秒数で時刻を表現する」
 
というものです.そして各種の関数を呼び出すことで,
秒数で表現された時刻情報から,
年,月,日,曜日,時,分,秒などの情報を取得することになります.
 
また,日付や時,分,秒の値を保持するための各種の構造体も
提供されています.
 
■ システムの現在時刻の取得(秒単位)
 OSの現在時刻(秒単位)を取得するには time 関数を使います.
 
例.

time_t    t;
t = time(NULL);

上の例のようにすると,t の中に現在時刻が秒数として得られます.
 
日付や時分秒の情報を格納する構造体として tm があり,
localtime 関数や gmtime 関数を使用することで
time_t 型のデータから tm の各メンバに情報を与えることができます.
 
例.

time_t    t;
struct tm *jst;
t = time(NULL);
jst = localtime(&t);

上の例のようにすることで,t の値から日付や時分秒の数値を算出して
それを jst の各メンバに格納します.
localtime 関数はOSのタイムゾーンに合った形で日付と時刻を取得します.
また類似の関数に gmtime というものがあり,これを用いると
グリニッジ標準時の形式で日付と時刻を取得することができます.
 
ちなみに,構造体 tm の中身(定義)は下記のようなものです.

struct tm {
	int tm_sec;        /* 秒 (0-60) */
	int tm_min;        /* 分 (0-59) */
	int tm_hour;       /* 時間 (0-23) */
	int tm_mday;       /* 月内の日付 (1-31) */
	int tm_mon;        /* 月 (0-11) */
	int tm_year;       /* 年 - 1900 */
	int tm_wday;       /* 曜日 (0-6, 日曜 = 0) */
	int tm_yday;       /* 年内通算日 (0-365, 1 月 1 日 = 0) */
	int tm_isdst;      /* 夏時間 */
};

この後,jst->tm_year を参照することで,西暦年(下2桁)の数値を得ることができます.
 
便利な関数として strftime というものがあり,これを使用することで,
日付や時刻を表現する文字列を得ることができます.
例.現在の日付と時刻を1秒感覚で表示するプログラム

#include	<stdio.h>
#include	<time.h>
 
int main()
{
	time_t	t;
	struct	tm	*gmt, *jst;
	int	s1, s2;
	char	fgmt[128], fjst[128];
 
	s2 = 0;
	while ( -1 ) {
//		t = time(NULL);
		time(&t);
		gmt = gmtime( &t );
		jst = localtime( &t );
		s1 = gmt->tm_sec;
		if ( s1 != s2 ) {
			strftime(fgmt,sizeof(fgmt),"%Y/%m/%d(%a) %H:%M:%S",gmt);
			strftime(fjst,sizeof(fjst),"%Y/%m/%d(%a) %H:%M:%S(%a)",jst);
			printf("%s [%s]\n",fgmt,fjst);
			s2 = s1;
		}
	}
}

実行結果の例.

$ s_time
2015/03/16(Mon) 10:56:34 [2015/03/16(Mon) 19:56:34(Mon)]
2015/03/16(Mon) 10:56:35 [2015/03/16(Mon) 19:56:35(Mon)]
2015/03/16(Mon) 10:56:36 [2015/03/16(Mon) 19:56:36(Mon)]
2015/03/16(Mon) 10:56:37 [2015/03/16(Mon) 19:56:37(Mon)]
2015/03/16(Mon) 10:56:38 [2015/03/16(Mon) 19:56:38(Mon)]
2015/03/16(Mon) 10:56:39 [2015/03/16(Mon) 19:56:39(Mon)]
^C
$

 
■ システムの現在時刻の取得(ミリ秒単位)
 OSの現在時刻(ミリ秒単位)を取得するには ftime 関数を使います.
この関数を使用すると,秒とミリ秒の情報が構造体 timeb のメンバに格納されます.
 
例.10分の1秒毎に時刻の秒数を表示するプログラム

#include	<stdio.h>
#include	<sys/timeb.h>
 
struct	timeb	tb;
 
int main()
{
	int	sec,sec2, msec,msec2;
 
	ftime( &tb );
	sec2 = tb.time;
	msec2 = tb.millitm / 100;
	while ( -1 ) {
		ftime( &tb );
		sec = tb.time;
		msec = tb.millitm / 100;
		if ( msec != msec2 ) {
			printf("%d.%d\n",sec,msec);
			sec2 = sec;
			msec2 = msec;
		}
	}
}

 
localtime の逆関数
 tm 構造体の内容から,その時刻に対応する time_t の値を求めるには mktime 関数を使います.
 
例1.localtime で変換した tm 構造体の内容を time_t に逆変換する

#include	<stdio.h>
#include	<time.h>
 
int main()
{
	time_t	t;
	struct	tm	*jst;
	char	fjst[128];
 
//	t = time(NULL);
	time(&t);
	printf("Now, time_t is %ld\n",t);
 
	jst = localtime( &t );
	strftime(fjst,sizeof(fjst),"%Y/%m/%d(%a) %H:%M:%S(%a)",jst);
	printf("%s\n",fjst);
 
	t = mktime( jst );
	printf("mktime is      %ld\n",t);
}

実行例

$ s_mktime
Now, time_t is 1427529755
2015/03/28(Sat) 17:02:35(Sat)
mktime is      1427529755

 
例2.コマンドラインから入力した日付と時刻から time_t を求める

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include	<stdio.h>
#include	<time.h>
 
int main(ac,av)
int	ac;
char	**av;
{
	int	year, month, day, hour, min, sec;
	time_t	t;
	struct	tm	jst, *jst2;
	char	fjst[128];
 
	sscanf(av[1],"%d",&year);
	sscanf(av[2],"%d",&month);
	sscanf(av[3],"%d",&day);
	sscanf(av[4],"%d",&hour);
	sscanf(av[5],"%d",&min);
	sscanf(av[6],"%d",&sec);
	year  -= 1900;
	month -= 1;
 
	jst.tm_year   = year;
	jst.tm_mon    = month;
	jst.tm_mday   = day;
	jst.tm_hour   = hour;
	jst.tm_min    = min;
	jst.tm_sec    = sec;
	jst.tm_isdst  = -1;
 
	t = mktime(&jst);
	printf("%04d/%02d/%02d %02d:%02d:%02d\n",
			year+1900,month+1,day,hour,min,sec);
	printf("time_t is %ld\n",t);
 
	jst2 = localtime( &t );
	strftime(fjst,sizeof(fjst),"%Y/%m/%d(%a) %H:%M:%S",jst2);
	printf("%s\n",fjst);
 
	t = mktime( jst2 );
	printf("mktime is %ld\n",t);
}

実行結果の例

$ s_mktime2 2015 3 29 13 16 00
2015/03/29 13:16:00
time_t is 1427602560
2015/03/29(Sun) 13:16:00
mktime is 1427602560

アプリケーションプログラムを作るには

プログラミング言語の最終的な目的は,アプリケーションプログラムの作成です.
いわゆる「アプリ」を作るのが目的です.
 
ここではJavaで実現するアプリにはどのような形があるのかを紹介します.

● コマンドとしてアプリを作る

 Windowsのコマンドプロンプトウィンドウ(Macの場合はターミナルウィンドウ)で実行するプログラムで,基本的にはグラフィックスは扱いません.これの実現は最も手軽で,標準入力(System.inなど)からユーザの操作を受付,標準出力(System.outなど)に対してメッセージを表示するスタイルです.

● アプレットを作る

 Webブラウザ上で実行するプログラムで,HTMLコンテンツの中に埋め込んで使います.

● GUIアプリを作る (1) : Swingの利用
● GUIアプリを作る (2) : SWTの利用
● GUIアプリを作る (3) : FXの利用

応用作品

 GMPもMPFRもとても有用なライブラリですが,使い方に関して言うと「ちょっと煩わしい」感じがします.そこで,当ゼミではこれらライブラリをちょっと使いやすくするための一種の「ラッパー」みたいなものをC++言語で記述して使っています.
 
これはC++で高精度演算をするための関数群を提供するヘッダファイル “bignum.h” として実装したもの(下記)です.

作品:bignum.h
 まだまだツッコミどころのあるコードですが,計算が便利になっています.(^^)
 
【bignum.hの使い方】
 bignum.hは高精度演算のための2つのクラス(下記)を提供します.
 
1) BigQ : 計算精度を落とさずに算術演算(加減乗除)を行うためのクラス
2) BigF : 指定した精度(ビット長)で算術演算と各種関数の計算を行うためのクラス
 
基本的な使い方を例を挙げて説明します.

Step-1: オブジェクトの宣言
例: BigF pi(332), c3(332), x(332), y(332);
 これで332ビット(10進数で約100桁)の精度を持つ4つの変数(オブジェクト)pi,c3,x,yが生成されます.
 
Step-2: 値の設定
例: c3 = 3;
 これでc3に3が代入されます.オブジェクトを宣言する時に値を代入することもできます.
 (例えば,BigF c3(3,332); )
 
Step-3: 計算の実行
例: pi.setPi();
 これでpiに円周率が代入されます.
 
Step-4: 値の出力
例: pi.toString(s);
   printf(“pi: %s\n\n”,s);
 これでpiの内容が文字列としsに格納されます.
 
プログラム例: π,cos(π),π/3,cos(π/3)を求めるプログラム

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include	<iostream>
#include	"bignum.h"
 
int main()
{
	char	*s;
	s = (char*)malloc(1048576);
 
	BigF	pi(332), c3(332), x(332), y(332);
 
	c3 = 3;
 
	pi.setPi();
	pi.toString(s);
	printf("pi: %s\n\n",s);
 
	y.setCos(pi);
	y.toString(s);
	printf("y=cos(pi): %s\n\n",s);
 
	x.setDiv(pi,c3);
	x.toString(s);
	printf("pi/3: %s\n\n",s);
 
	y.setCos(x);
	y.toString(s);
	printf("y=cos(pi/3): %s\n",s);
}

実行結果

pi: 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170678
 
y=cos(pi): -1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
 
pi/3: 1.0471975511965977461542144610931676280657231331250352736583148641026054687620696662093449417807056892
 
y=cos(pi/3): 0.50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011

※ 末の桁の誤差に注意してください.
 
=== 簡易リファレンス ===

【有理数クラス:BigQ】
■ オブジェクトの生成
BigQ x 初期値なし
BigQ x(値) 生成時に初期値(値)を設定する.
■ オブジェクトの廃棄
x.Free() BigQ型のオブジェクトxを廃棄する.
■ C言語の基本的な値の代入
x = 値 BigQ型のオブジェクトxに値を代入する.
■ C言語の変数への変換
x.toInt() BigQ型のオブジェクトxをint型の値に変換したものを返す.
x.toLong() BigQ型のオブジェクトxをlong型の値に変換したものを返す.
x.toDouble() BigQ型のオブジェクトxをdouble型の値に変換したものを返す.
x.toString(s) BigQ型のオブジェクトxを文字列(char *s)に変換する.
■ 演算
x.setAdd(v1,v2) v1+v2(共にBigQ型のオブジェクト)の値をxに代入する.
x.setSub(v1,v2) v1-v2(共にBigQ型のオブジェクト)の値をxに代入する.
x.setMul(v1,v2) v1*v2(共にBigQ型のオブジェクト)の値をxに代入する.
x.setDiv(v1,v2) v1/v2(共にBigQ型のオブジェクト)の値をxに代入する.
x.setAdd(v) BigQ型のオブジェクトxにBigQ型のオブジェクトvの値を加算する.(計算結果はxの値になる)
x.setSub(v) BigQ型のオブジェクトxからBigQ型のオブジェクトvの値を引く.(計算結果はxの値になる)
x.setMul(v) BigQ型のオブジェクトxにBigQ型のオブジェクトvの値を掛ける.(計算結果はxの値になる)
x.setDiv(v) BigQ型のオブジェクトxをBigQ型のオブジェクトvの値で割る.(計算結果はxの値になる)
x.setNeg(v) BigQ型のオブジェクトvの符号を反転した値をxに代入する.
x.setInv(v) BigQ型のオブジェクトvの逆数をxに代入する.
x.setPow(v,p) BigQ型のオブジェクトvのp乗をxに代入する.(unsigned long p)
x.setInc() xの値を1増やす.
x.setDec() xの値を1減らす.
x.setFact(n) nの階乗をxに代入する.(unsigned long n)
■ 述語(比較など)
x == y BigQ型のオブジェクトx,yの値が等しければtrue,それ以外はfalseを返す.
x != y BigQ型のオブジェクトx,yの値が異なればtrue,それ以外はfalseを返す.
x > y BigQ型のオブジェクトx,yの値を比較し,x>yならばtrue,それ以外はfalseを返す.
x < y BigQ型のオブジェクトx,yの値を比較し,x
x >= y BigQ型のオブジェクトx,yの値を比較し,x>=yならばtrue,それ以外はfalseを返す.
x <= y BigQ型のオブジェクトx,yの値を比較し,x<=yならばtrue,それ以外はfalseを返す.

 

【浮動小数点数クラス:BigF】
■ オブジェクトの生成
BigF x デフォルト精度で生成する.
BigF x(精度) 生成時に精度(ビット長)を設定する.
BigF x(値,精度) 生成時に初期値(値)と精度(ビット長)を設定する.
■ オブジェクトの精度の変更
x.setPrec(精度) BigF型オブジェクトxの精度(ビット長)を変更(再設定)する.
■ オブジェクトの廃棄
x.Free() BigF型のオブジェクトxを廃棄する.
■ C言語の基本的な値の代入
x = 値 BigF型のオブジェクトxに値を代入する.
■ C言語の変数への変換
x.toInt() BigF型のオブジェクトxをint型の値に変換したものを返す.
x.toLong() BigF型のオブジェクトxをlong型の値に変換したものを返す.
x.toDouble() BigF型のオブジェクトxをdouble型の値に変換したものを返す.
x.toString(s) BigF型のオブジェクトxを文字列(char *s)に変換する.
■ C言語の基本的な値の代入
x = 値 BigF型のオブジェクトxに値を代入する.
■ 特殊な値の代入
x.setZero(符号) BigF型のオブジェクトxに0を代入する.符号はint型で,正なら+0を,負なら-0を,0なら0を設定する.
x.setInf(符号) BigF型のオブジェクトxに無限大を代入する.符号はint型で,正なら+∞を,負なら-∞を,0なら∞を設定する.
x.setNan() BigF型のオブジェクトxにNan(Not a number)を設定する.
■ 基本的な演算
x.setAdd(v1,v2) v1+v2(共にBigF型のオブジェクト)の値をxに代入する.
x.setSub(v1,v2) v1-v2(共にBigF型のオブジェクト)の値をxに代入する.
x.setMul(v1,v2) v1*v2(共にBigF型のオブジェクト)の値をxに代入する.
x.setDiv(v1,v2) v1/v2(共にBigF型のオブジェクト)の値をxに代入する.
x.setAdd(v) BigF型のオブジェクトxにBigF型のオブジェクトvの値を加算する.(計算結果はxの値になる)
x.setSub(v) BigF型のオブジェクトxからBigF型のオブジェクトvの値を引く.(計算結果はxの値になる)
x.setMul(v) BigF型のオブジェクトxにBigF型のオブジェクトvの値を掛ける.(計算結果はxの値になる)
x.setDiv(v) BigF型のオブジェクトxをBigF型のオブジェクトvの値で割る.(計算結果はxの値になる)
x.setNeg(v) BigF型のオブジェクトvの符号を反転した値をxに代入する.
x.setInv(v) BigF型のオブジェクトvの逆数をxに代入する.
x.setAbs(v) BigF型のオブジェクトvの絶対値をxに代入する.
x.setPow(v,p) BigF型のオブジェクトvのp乗をxに代入する.(unsigned long p)
x.setFact(n) nの階乗をxに代入する.(nはint,long,unsigned long)
■ 関数
x.setSqrt(v) BigF型のオブジェクトvの平方根をxに代入する.
x.setPi() 円周率をxに代入する.
x.setExp(v) e^v(vはBigF型)の値をxに代入する.
x.setExp2(v) 2^v(vはBigF型)の値をxに代入する.
x.setExp10(v) 10^v(vはBigF型)の値をxに代入する.
x.setLog(v) BigF型のオブジェクトvの対数(底e)をxに代入する.
x.setLog2(v) BigF型のオブジェクトvの対数(底2)をxに代入する.
x.setLog10(v) BigF型のオブジェクトvの対数(底10)をxに代入する.
x.setSin(v) 正弦関数sin(v)(vはBigF型)の値をxに代入する.
x.setCos(v) 余弦関数cos(v)(vはBigF型)の値をxに代入する.
x.setTan(v) 正接関数tan(v)(vはBigF型)の値をxに代入する.
x.setSec(v) 正割関数sin(v)(vはBigF型)の値をxに代入する.
x.setCsc(v) 余割関数cos(v)(vはBigF型)の値をxに代入する.
x.setCot(v) 余接関数tan(v)(vはBigF型)の値をxに代入する.
x.setAsin(v) 逆正弦関数asin(v)(vはBigF型)の値をxに代入する.
x.setAcos(v) 逆余弦関数acos(v)(vはBigF型)の値をxに代入する.
x.setAtan(v) 逆正接関数atan(v)(vはBigF型)の値をxに代入する.
x.setSinh(v) 双曲線関数sinh(v)(vはBigF型)の値をxに代入する.
x.setCosh(v) 双曲線関数cosh(v)(vはBigF型)の値をxに代入する.
x.setTanh(v) 双曲線関数tanh(v)(vはBigF型)の値をxに代入する.
x.setSech(v) 双曲線関数sech(v)(vはBigF型)の値をxに代入する.
x.setCsch(v) 双曲線関数csch(v)(vはBigF型)の値をxに代入する.
x.setCoth(v) 双曲線関数coth(v)(vはBigF型)の値をxに代入する.
x.setAsinh(v) 逆双曲線関数sinh(v)(vはBigF型)の値をxに代入する.
x.setAcosh(v) 逆双曲線関数cosh(v)(vはBigF型)の値をxに代入する.
x.setAtanh(v) 逆双曲線関数tanh(v)(vはBigF型)の値をxに代入する.
x.setGamma(v) ガンマ関数Γ(v)(vはBigF型)の値をxに代入する.
x.setZeta(v) ゼータ関数Ζ(v)(vはBigF型)の値をxに代入する.
■ 述語(比較など)
x == y BigF型のオブジェクトx,yの値が等しければtrue,それ以外はfalseを返す.
x != y BigF型のオブジェクトx,yの値が異なればtrue,それ以外はfalseを返す.
x > y BigF型のオブジェクトx,yの値を比較し,x>yならばtrue,それ以外はfalseを返す.
x < y BigF型のオブジェクトx,yの値を比較し,x
x >= y BigF型のオブジェクトx,yの値を比較し,x>=yならばtrue,それ以外はfalseを返す.
x <= y BigF型のオブジェクトx,yの値を比較し,x<=yならばtrue,それ以外はfalseを返す.
x.isZero(符号) BigF型のオブジェクトxがゼロならばtrue,それ以外はfalseを返す.符号はint型で,正ならば+0,負ならば-0,0ならば0であることを判定する.
x.isInf(符号) BigF型のオブジェクトxが無限大ならばtrue,それ以外はfalseを返す.符号はint型で,正ならば+∞,負ならば-∞,0ならば∞であることを判定する.

MPFRの利用

 GMP(Gnu MP)は基本的には算術(加減乗除)の演算のみを提供しますが,各種の高度な関数(指数関数,対数関数,三角関数など)の値を計算するための機能はありません.そこで,GMPを利用して高度な関数を計算するためのライブラリ MPFR が作られました.
 
GNU MPFRのサイト: http://www.mpfr.org/
 
 MPFRの使い方はGMPに倣っており,mpfr_t 型のオブジェクトを用いて計算処理を実行します.MPFR用の各種関数もGMPのものと類似しており,同じような使い方ができます.
 
【各種計算のための関数】 (一部の代表的なもの)

算術演算 書式 意味
加算 mpfr_add(x,a,b,丸め指定) x = a + b
減算 mpfr_sub(x,a,b,丸め指定) x = a – b
乗算 mpfr_mul(x,a,b,丸め指定) x = a * b
除算 mpfr_div(x,a,b,丸め指定) x = a / b
べき乗 mpfr_pow(x,a,b,丸め指定) x = a ^ b
指数・対数関数 書式 意味
e^n mpfr_exp(x,n,丸め指定) x = e ^ n
2^n mpfr_exp2(x,n,丸め指定) x = 2 ^ n
10^n mpfr_exp10(x,n,丸め指定) x = 10 ^ n
log e n mpfr_log(x,n,丸め指定) x = log e n
log 2 n mpfr_log2(x,n,丸め指定) x = log 2 n
log 10 n mpfr_log10(x,n,丸め指定) x = log 10 n
三角関数 書式 意味
正弦関数 mpfr_sin(y,x,丸め指定) y = sin(x)
余弦関数 mpfr_cos(y,x,丸め指定) y = cos(x)
正接関数 mpfr_tan(y,x,丸め指定) y = tan(x)
逆正弦関数 mpfr_asin(y,x,丸め指定) y = asin(x)
逆余弦関数 mpfr_acos(y,x,丸め指定) y = acos(x)
逆正接関数 mpfr_atan(y,x,丸め指定) y = atan(x)

GMP利用の流れ

1) 値を保持するオブジェクトの宣言
 値を保持するオブジェクトには mpz_t(整数型)mpq_t(有理数型)mpf_t(浮動小数点数型)の3つがあり,必要に応じてそれらの型のオブジェクトを宣言します.
 
例.有理数型のオブジェクトの宣言: mpq_t a, b, c;
 
2) オブジェクトの初期化
 GMPのオブジェクトは計算に使用する前(値を格納する前)に初期化処理をする必要があります.
 
例.有理数型オブジェクトの初期化:
 mpq_init(a);
 mpq_init(b);
 mpq_init(c);

同様に mpz_init, mpf_init 関数があります.
 
3) オブジェクトへの値の格納(代入)
■ mpz_t(整数)オブジェクト x への値の格納
 mpz_set_ui( mpz_t x, unsigned long v ) : 符号なしlong型のvを代入
 mpz_set_si( mpz_t x, long v ) : long型のvを代入
 mpz_set_str( mpz_t x, const char *v, inv base ) :
   base進法の基数で表現された文字列としての整数vを解釈して代入
 
■ mpq_t(有理数)オブジェクト x への値の格納
 mpq_set_ui( mpz_t x, unsigned long v1, unsigned long v2 ) :
   符号なしlong型で表現された有理数 v1/v2 を代入
 mpq_set_si( mpz_t x, long v1, unsigned long v2 ) :
   同じく v1/v2 を代入
 mpq_set_d( mpz_t x, double v ) : double型の v を代入
 mpq_set_str( mpz_t x, const char *v, inv base ) :
   base進法の基数で表現された文字列としての有理数vを解釈して代入

同様に mpf_t 型のオブジェクトにも値を格納する関数があります.
 
4) 計算処理
■ 加算: r = v1 + v2
 mpz_add(r,v1,v2), mpq_add(r,v1,v2), mpf_add(r,v1,v2)
■ 減算: r = v1 – v2
 mpz_sub(r,v1,v2), mpq_sub(r,v1,v2), mpf_sub(r,v1,v2)
■ 乗算: r = v1 * v2
 mpz_mul(r,v1,v2), mpq_mul(r,v1,v2), mpf_mul(r,v1,v2)
■ 除算: r = v1 / v2
 mpz_div(r,v1,v2), mpq_div(r,v1,v2), mpf_div(r,v1,v2)
その他…
 
5) 出力(変換)
■ 文字列への変換
例.mpz_t(整数型)のオブジェクト x を char *s に変換する
 mpz_get_str( char *s, int base, mpz_t x )
同様に mpq_t, mpf_t 型のオブジェクトを文字列に変換することができます.
 
その他にも,long, unsigned long, double 型に変換する関数もあります.

日付と時間(2)

「日付と時刻」をデータとして扱う方法です.Date クラスのオブジェクトは生成時にその時点の日付&時刻を取得しますが,ここで紹介する Calendar クラスのオブジェクトは日付&時刻を1つのデータと見て日数計算(「〜日あと」とか「〜週間前」,「〜時間後」とかの計算)をするためのものです.
 下のサンプルプログラム “CalendarTest1.java” では最初に「2014/01/01,00:00:00」の日付をデータとして用意して「〜日後」「〜時間後」のような計算をしている例です.
 set() メソッドで日付や時刻を設定し,add() メソッドで日数や時間を加算し,get() メソッドで日付や時刻を取り出します.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import java.util.*;
 
class CalendarTest1 {
	public static void main( String argv[] ) {
 
		int y, m, d, wd2, h, min, sec;
		Calendar cal = Calendar.getInstance();
		String wd[] = { "日", "月", "火", "水", "木", "金", "土" };
 
		/* 2014/01/01, 00:00:00 */
		cal.set(Calendar.YEAR,2012);
		cal.set(Calendar.MONTH,1-1);
		cal.set(Calendar.DATE,1);
		cal.set(Calendar.HOUR_OF_DAY,0);
		cal.set(Calendar.MINUTE,0);
		cal.set(Calendar.SECOND,0);
 
		/* after 86,400 seconds */
		cal.add(Calendar.SECOND,86400);
		y = cal.get(Calendar.YEAR);
		m = cal.get(Calendar.MONTH) + 1;
		d = cal.get(Calendar.DATE);
		wd2 = cal.get(Calendar.DAY_OF_WEEK) - 1;
		System.out.printf("%d/%02d/%02d(%s)\n",y,m,d,wd[wd2]);
 
		/* after 12 Months */
		cal.add(Calendar.MONTH,12);
		y = cal.get(Calendar.YEAR);
		m = cal.get(Calendar.MONTH) + 1;
		d = cal.get(Calendar.DATE);
		wd2 = cal.get(Calendar.DAY_OF_WEEK) - 1;
		System.out.printf("%d/%02d/%02d(%s)\n",y,m,d,wd[wd2]);
 
		/* after 28 Days */
		cal.add(Calendar.DATE,28);
		y = cal.get(Calendar.YEAR);
		m = cal.get(Calendar.MONTH) + 1;
		d = cal.get(Calendar.DATE);
		wd2 = cal.get(Calendar.DAY_OF_WEEK) - 1;
		System.out.printf("%d/%02d/%02d(%s)\n",y,m,d,wd[wd2]);
 
		/* after 24 Hours */
		cal.add(Calendar.HOUR_OF_DAY,24);
		y = cal.get(Calendar.YEAR);
		m = cal.get(Calendar.MONTH) + 1;
		d = cal.get(Calendar.DATE);
		wd2 = cal.get(Calendar.DAY_OF_WEEK) - 1;
		System.out.printf("%d/%02d/%02d(%s)\n",y,m,d,wd[wd2]);
 
		/* after 31,536,000 Seconds */
		cal.add(Calendar.SECOND,31536000);
		y = cal.get(Calendar.YEAR);
		m = cal.get(Calendar.MONTH) + 1;
		d = cal.get(Calendar.DATE);
		wd2 = cal.get(Calendar.DAY_OF_WEEK) - 1;
		System.out.printf("%d/%02d/%02d(%s)\n",y,m,d,wd[wd2]);
	}
}

 このプログラムを実行すると,次のような内容が表示されます.

2012/01/02(月)
2013/01/02(水)
2013/01/30(水)
2013/01/31(木)
2014/01/31(金)

文字列⇔数値の変換

int, long, double といった数値の型の変数と文字列(String)オブジェクトの間で値の変換をすることは,実際のプログラミングでよく行われます.
 
数値から文字列に変換するには valueOf() メソッドを使います.また逆に文字列として表現されている数値を解釈して int, long, double などの型の変数に値を入れるには parse型名() メソッドを用います.
 
これらのメソッドを用いたサンプルを “valueConv1.java” に示します.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class valueConv1 {
	public static void main( String argv[] ) {
		int i = 1;
		long l = 2;
		double f = 3.4;
		String is, ls, fs;
 
		is = String.valueOf(i); //    int -> String
		ls = String.valueOf(l); //   long -> String
		fs = String.valueOf(f); // double -> String
		System.out.printf("\'%s\' , \'%s\' , \'%s\'\n",is,ls,fs);
 
		i = Integer.parseInt(is);   // String -> int
		l = Long.parseLong(ls);	    // String -> long
		f = Double.parseDouble(fs); // String -> double
		System.out.printf("%d , %d , %.1f\n",i,l,f);
	}
}

これを実行すると次のような表示になります.

'1' , '2' , '3.4'
1 , 2 , 3.4

オブジェクトのクラスを調べる方法

オブジェクトが属するクラスを調べる方法です.

getClass() メソッドでクラス情報を取得して,それに対して getName() メソッドをを実行することで,オブジェクトが属するクラスの名前を文字列(String)オブジェクトとして取得することができます.

次のサンプルプログラム “ClassCheck1.java” はそれを実行する例です.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class TestClass {
}
 
class ClassCheck1 {
	public static void main( String argv[] ) {
		String name = "test";
 
		TestClass o = new TestClass();
		name = o.getClass().getName();
		System.out.println(name);
 
		name = name.getClass().getName();
		System.out.println(name);
	}
}

このプログラムを実行すると,次のような表示になります.

TestClass
java.lang.String

ファイルへの出力:テキストファイル

ファイルへの出力の方法です.
ここでは,テキストファイルとしてデータを出力する方法を紹介します.
 

【基本】

次のプログラム “FileWrite1.java” はファイル “text2.txt” に対してテキストデータを出力する例です.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.io.*;
 
class FileWrite1 {
	public static void main( String argv[] ) {
 
		FileWriter fw;
 
		try {
			fw = new FileWriter("text2.txt");
			fw.write("This is an output data from\n");
			fw.write("FileWrite1.\n");
			fw.write("日本語の出力です.\n");
			fw.close();
		} catch( IOException e ) {
		}
	}
}

ファイルを FileWriter というクラスのオブジェクトとして生成しています.これを実行すると,ファイル “text2.txt” に次のような内容が書き込まれます.

This is an output data from
FileWrite1.
日本語の出力です.

 

【便利な方法】

 FileWriter を元に PrintWriter というクラスのオブジェクトを生成すると,それに対して print, println, printf といった出力用のメソッドを用いて内容を出力することができます.次のプログラム “FileWrite2.java” は printf メソッドを用いて書式を指定して正弦関数の定義域と値域を出力する例です.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.io.*;
 
class FileWrite2 {
	public static void main( String argv[] ) {
 
		FileWriter fw;
		PrintWriter pw;
 
		try {
			fw = new FileWriter("text3.txt");
			pw = new PrintWriter(fw);
			double x, y;
			for ( x = 0.0; x < 6.3; x += 0.1 ) {
				y = Math.sin(x);
				pw.printf("sin(%.1f) = %.10f\n",x,y);
			}
			fw.close();
		} catch( IOException e ) {
		}
	}
}

これを実行すると,ファイル “text3.txt” に次のような内容が出力されます.

sin(0.0) = 0.0000000000
sin(0.1) = 0.0998334166
sin(0.2) = 0.1986693308
sin(0.3) = 0.2955202067
sin(0.4) = 0.3894183423
 (以下省略)

日付と時間

Javaには日付と時間(時刻)のデータを扱うための高度な機能があります.

ただ,初心者には理解し難いものもあるので,ここでは素朴な例を挙げます.

Javaのクラスライブラリに Date というクラスがあり,このクラスのインスタンスを new で生成すると,現在の日付と時刻に関するデータを保持するオブジェクトができます.

下の例 “DateTest1.java” では年,月,日,曜日,時,分,秒を手軽に取り出すメソッドを備えたクラス Date2(Dateクラスの拡張)を実装しています.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import java.util.*;
import java.text.*;
 
class Date2 extends Date {
	/*--------------------------------------*
	 * constructor				*
	 *--------------------------------------*/
	Date2(int year, int month, int day) {
	}
	Date2() {
	}
 
	/*--------------------------------------*
	 * methods				*
	 *--------------------------------------*/
	/* Date2 -> Year */
	public int Date2Year() {
		int y;
		SimpleDateFormat f;
		f = new SimpleDateFormat("yyyy");
		y = Integer.parseInt(f.format(this));
		return( y );
	}
	/* Date2 -> Month */
	public int Date2Month() {
		int m;
		SimpleDateFormat f;
		f = new SimpleDateFormat("MM");
		m = Integer.parseInt(f.format(this));
		return( m );
	}
	/* Date2 -> Day */
	public int Date2Day() {
		int d;
		SimpleDateFormat f;
		f = new SimpleDateFormat("dd");
		d = Integer.parseInt(f.format(this));
		return( d );
	}
	/* Date2 -> Week day */
	public String Date2WDay() {
		String wd;
		SimpleDateFormat f;
		f = new SimpleDateFormat("E");
		wd = f.format(this);
		return( wd );
	}
	/* Date2 -> Hour */
	public int Date2Hour() {
		int h;
		SimpleDateFormat f;
		f = new SimpleDateFormat("hh");
		h = Integer.parseInt(f.format(this));
		return( h );
	}
	/* Date2 -> Minute */
	public int Date2Min() {
		int m;
		SimpleDateFormat f;
		f = new SimpleDateFormat("mm");
		m = Integer.parseInt(f.format(this));
		return( m );
	}
	/* Date2 -> Second */
	public int Date2Sec() {
		int s;
		SimpleDateFormat f;
		f = new SimpleDateFormat("ss");
		s = Integer.parseInt(f.format(this));
		return( s );
	}
}
 
class DateTest1 {
	public static void main( String argv[] ) {
		int y,m,day,h,min,sec;
		String wd;
 
		Date2 d = new Date2();	// 現在の日付,時刻の取得
		y = d.Date2Year();	// 年の取得
		m = d.Date2Month();	// 月の取得
		day = d.Date2Day();	// 日の取得
		wd = d.Date2WDay();	// 曜日の取得
		h = d.Date2Hour();	// 時の取得
		min = d.Date2Min();	// 分の取得
		sec = d.Date2Sec();	// 秒の取得
		System.out.printf("%d/%d/%d (%s), %s:%s:%s\n",
					y,m,day,wd,h,min,sec);
	}
}

このプログラムを実行すると,その時の日付と時刻を表示します.

ファイルの読込み:テキストファイル

テキストファイルを読み込む方法です.
 
基本的にファイルは入力ストリームなので,内容は先頭から順番に読み込まれます.
ここでは次の3つの方法を順番に説明します.

1) ファイルから「1バイトづつ」読み込む方法
2) ファイルから「1文字(多国語含む)づつ」読み込む方法
3) ファイルから「1行づつ」読み込む方法
 
次ような内容のファイル “text1.txt” があるものとして,この内容を読み込む方法を説明します.
 

1
2
3
Alphabet
日本語
English and 日本語 混在

 

【ファイルから「1バイトづつ」読み込む方法】

 ファイルを FileInputStream として開き,それに対して read() メソッドを実行すると1バイトづつ読み込むことができます.読み取ったデータは int 型整数として与えられます.(下記:”FileRead1.java”)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.io.*;
 
class FileRead1 {
	public static void main( String argv[] ) {
 
		FileInputStream fi;
		int c, i = 0;
 
		try {
			fi = new FileInputStream("text1.txt");
			while ( (c = fi.read()) != -1 ) {
				i++;
				System.out.println( i+":"+(char)c );
			}
			fi.close();
		} catch( IOException e ) {
			System.out.println("ファイルがオープンできません\n");
			System.exit(-1);
		}
	}
}

 この方法は最も基本的ですが,1バイトづつ読むため能率がよくありません.また多バイトからなる多国語文字を認識しないため実行すると文字化けが起こります.実行結果の表示を下に示します. 

1:A
2:l
3:p
4:h
5:a
6:b
7:e
8:t
9:
 
10:æ
11:—
12:¥
13:æ
14:œ
15:¬
16:è
17:ª
18:ž
19:
 
20:E
21:n
22:g
23:l
24:i
25:s
26:h
27: 
28:a
29:n
30:d
31: 
32:æ
33:—
34:¥
35:æ
36:œ
37:¬
38:è
39:ª
40:ž
41:ã
42:€
43:€
44:æ
45:·
46:·
47:å
48:œ
49:¨
50:

 

【ファイルから「1文字(多国語含む)づつ」読み込む方法】

 入力するデータを「文字データ」として認識して1文字づつ読み取る方法です.ファイルを FileInputStream として開き,更にそれを元にして InputStreamReader というオブジェクトを生成し,それに対して read() メソッドを実行すると「1文字づつ」読み込むことができます.読み取ったデータは int 型整数として与えられます.(下記:”FileRead2.java”)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.io.*;
 
class FileRead2 {
	public static void main( String argv[] ) {
 
		FileInputStream fi;
		InputStreamReader isr;
		int c, i = 0;
 
		try {
			fi = new FileInputStream("text1.txt");
			isr = new InputStreamReader(fi,"UTF-8");
			while ( (c = isr.read()) != -1 ) {
				i++;
				System.out.println( i+":"+(char)c );
			}
			fi.close();
		} catch( IOException e ) {
			System.out.println("ファイルがオープンできません\n");
			System.exit(-1);
		}
	}
}

 この方法では多バイトからなる多国語文字を認識するため,文字化けは起こりません.実行結果の表示を下に示します.

1:A
2:l
3:p
4:h
5:a
6:b
7:e
8:t
9:
 
10:日
11:本
12:語
13:
 
14:E
15:n
16:g
17:l
18:i
19:s
20:h
21: 
22:a
23:n
24:d
25: 
26:日
27:本
28:語
29: 
30:混
31:在
32:

 また,ファイルを FileReader として開いてそれに対して read() メソッドを実行する方法(下記;”FileRead3.java”)もあり,同じ結果を得ることができます.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.io.*;
 
class FileRead3 {
	public static void main( String argv[] ) {
 
		FileReader fr;
		int c, i = 0;
 
		try {
			fr = new FileReader("text1.txt");
			while ( (c = fr.read()) != -1 ) {
				i++;
				System.out.println( i+":"+(char)c );
			}
			fr.close();
		} catch( IOException e ) {
			System.out.println("ファイルがオープンできません\n");
			System.exit(-1);
		}
	}
}

 

【ファイルから「1行づつ」読み込む方法】

 おそらく一番実用的な方法かと思います.テキストファイルを「1行づつ」読み取って String クラスの文字列オブジェクトとして取り出す方法です.(下記:”FileRead4.java”)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.io.*;
 
class FileRead4 {
	public static void main( String argv[] ) {
 
		FileReader fr;
		int i = 0;
		String b;
 
		try {
			fr = new FileReader("text1.txt");
			BufferedReader br = new BufferedReader(fr);
			while ( (b = br.readLine()) != null ) {
				i++;
				System.out.println( i+":"+b );
			}
			fr.close();
		} catch( IOException e ) {
			System.out.println("ファイルがオープンできません\n");
			System.exit(-1);
		}
	}
}

 これを実行すると次のようになります.

1:Alphabet
2:日本語
3:English and 日本語 混在

 

【コンマ区切りの文字列(CSVデータ)の分離】

 コンマ区切りデータ(CSVデータ)を1行づつ読み取った場合に,その行をコンマ毎に区切ってバラバラの文字列にする方法を説明します.今回例に使用するのは,総務省が配布する「標準地域コード」です.このデータは次のように8つの項目からなり,それをCSVデータにしたファイル “ChiikiCode.csv” を読み込む例です.
 1. 都道府県コード
 2. 市町村コード
 3. 地域コード
 4. 都道府県名
 5. 市町村名1
 6. 市町村名2
 7. 市町村名3
 8. 読みがな
このファイルの内容は次のようなものです.

1,0,1000,北海道,,,,ほっかいどう
1,100,1100,北海道,札幌市,,,さっぽろし
1,101,1101,北海道,札幌市,,中央区,ちゅうおうく
1,102,1102,北海道,札幌市,,北区,きたく
  (以下省略)

このデータを読み取って,3〜8の項目を表示するプログラム “CSVtest1.java” を下に示します.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.io.*;
 
class CSVtest1 {
	public static void main( String argv[] ) {
 
		FileReader fr;
		int i = 0;
		String b;
		String csv[] = new String[20];
 
		try {
			fr = new FileReader("ChiikiCode.csv");
			BufferedReader br = new BufferedReader(fr);
			while ( (b = br.readLine()) != null ) {
				i++;
				csv = b.split(",");
				System.out.print("("+i+")");
				System.out.printf("\t地域コード: %s\n",csv[2]);
				System.out.printf("\t%s%s%s%s",csv[3],csv[4],csv[5],csv[6]);
				System.out.printf("(%s)\n",csv[7]);
			}
			fr.close();
		} catch( IOException e ) {
			System.out.println("ファイルがオープンできません\n");
			System.exit(-1);
		}
	}
}

このプログラムを実行した様子を下に示します.

(1)     地域コード: 1000
        北海道(ほっかいどう)
(2)     地域コード: 1100
        北海道札幌市(さっぽろし)
(3)     地域コード: 1101
        北海道札幌市中央区(ちゅうおうく)
(4)     地域コード: 1102
        北海道札幌市北区(きたく)
  (以下省略)

JavaFX GUIアプリ構築入門(NetBeans IDE)

マニュアルをまとめつつあります.)
 
 実用的なGUIアプリを構築するにはボタンやメニューを始めとする各種のコントロール(GUI部品)を多数使用しますが,それらを全て手作業でコーディング(プログラムのソースコードの手入力)するのはとても煩わしく,生産的ではありません.
 
 統合開発環境(IDE)と呼ばれるツールを用いることで直感的にGUIを構築することができ,それに対応するコースコードを自動的に生成することができます.ここでは NetBeans IDE というツールを用いて手軽にGUIアプリを構築する手順を紹介します.
 
NetBeans IDEはこのサイトからダウンロードできます.
 
またGUIを直感的に構築・編集するためには JavaFX SceneBuilder も入手してインストールしておく必要があります.(入手はこちら)
 

【プログラム作成手順】

 NetBeans IDEを起動して「ファイル」→「新規プロジェクト」を選びます.(下図参照)
NetBeans01
 次に,下のような表示になるので,「カテゴリ」から「JavaFX」を選択し,「プロジェクト」から「JavaFX FXMLアプリケーション」を選んで「次へ」ボタンをクリックします.
NetBeans02
 次に,下のような表示になるので,プロジェクト名やプロジェクトに関連するファイル群を保存する場所などを設定して「終了」ボタンをクリックします.
NetBeans03
 プロジェクトとはプログラム開発作業に関連するファイルや設定などをまとめたものだと考えてください.1つの開発単位は1つのプロジェクトとして1つのフォルダにまとめて保存されます.この例では “JavaFXMLApplication1” という名前のプロジェクトを作成しています.
 
 以上の作業で新規プロジェクトの作成が完了してプログラムの開発作業が可能になります.(下のような表示となります)
NetBeans04

プロジェクトを作成して開発準備が整うと最初の段階で次のようなファイル群が生成されます.

  1. mainメソッドを収めたアプリケーションの最上位のソースコード
     プロジェクト名と同じ名前のソースファイルが生成されます.上の例では “JavaFXMLApplication1.java” というソースファイルが生成されます.

  2. GUIを記述するFXMLファイル
     JavaFXではXML形式(FXML形式)でGUIを構築することができ,デフォルトでは “FXMLDocument.fxml” という名前のファイルが生成されます.

  3. GUIのイベントハンドリングのためのソースコード
     GUIからのイベントを受けて起動するメソッド群を記述するソースコードで,デフォルトでは “FXMLDocumentController.java” という名前のファイルが生成されます.

 
 プロジェクト生成直後は,サンプルとして1つのボタンのみを備えたGUIのアプリケーションのためのソースコードになっており,これを改造して独自のアプリケーションに仕上げていきます.
 
GUIの追加とイベントハンドリングの記述:
 NetBeans IDEの「プロジェクト」タブからFXMLファイルをダブルクリックすると JavaFX SceneBuilder が起動してGUIの編集が始まります.(下図)
SceneBuilder01
 
 例えばこのインターフェースにメニューバーを取り付け,「File」メニューの「Close」を選択するとプログラムが終了するようなアプリケーションに改造してみます.

  • ステップ1: メニューバーの取り付け
     SceneBuilderウィンドウの左端の「Control」の中から「MenuBar」を選び,これをGUIの上にドラッグ&ドロップするとメニューバーが設置できます.(下図)
    SceneBuilder03

  • ステップ2: メニューとメニュー項目の取り付け
     ウィンドウ左端の「Menu」から「Menu」や「MenuItem」を選んでメニューバーに取り付けていきます.この例では,予め登録されているメニュー項目「Close」があるので,取り付け作業の説明は省略します.

  • ステップ3: GUIへのイベントハンドリングの登録
     GUIのメニューバーを選択しておき,ウィンドウ左端の「Hierarchy」の中から「MenuItem Close」を選択します.次にウィンドウ右端の「Code : MenuItem」の中にある該当イベントの部分(この例では「OnAction」)に,そのイベントが起こったときに起動するメソッドの名前を入力します.この例では「Close」を選択したときに “QuitAction” というメソッドが起動するように設定しています.

  • ステップ4: ソースコードの追加
     ”FXMLDocumentController.java” の中に,イベントに対応して起動するメソッドを記述します.この例では「QuitAction」というメソッドの記述を追加しています.

 
 以上の作業で出来上がったコードを下に示します.
 
ソースコード “JavaFXMLApplication1.java”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package javafxmlapplication1;
 
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
 
public class JavaFXMLApplication1 extends Application {
 
    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
 
        Scene scene = new Scene(root);
 
        stage.setScene(scene);
        stage.show();
    }
 
    public static void main(String[] args) {
        launch(args);
    }
 
}

 
FXMLのコード “FXMLDocument.fxml”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?xml version="1.0" encoding="UTF-8"?>
 
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
 
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="javafxmlapplication1.FXMLDocumentController">
    <children>
        <Button fx:id="button" layoutX="126" layoutY="90" onAction="#handleButtonAction" text="Click Me!" />
        <Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
      <MenuBar layoutY="2.0" prefHeight="25.0" prefWidth="320.0">
        <menus>
          <Menu mnemonicParsing="false" text="File">
            <items>
              <MenuItem mnemonicParsing="false" onAction="#QuitAction" text="Close" />
            </items>
          </Menu>
          <Menu mnemonicParsing="false" text="Edit">
            <items>
              <MenuItem mnemonicParsing="false" text="Delete" />
            </items>
          </Menu>
          <Menu mnemonicParsing="false" text="Help">
            <items>
              <MenuItem mnemonicParsing="false" text="About" />
            </items>
          </Menu>
        </menus>
      </MenuBar>
    </children>
</AnchorPane>

 
イベントハンドリングのためのソースコード “FXMLDocumentController.java”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package javafxmlapplication1;
 
import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
 
public class FXMLDocumentController implements Initializable {
 
    @FXML
    private Label label;
 
    @FXML
    private void handleButtonAction(ActionEvent event) {
        System.out.println("You clicked me!");
        label.setText("Hello World!");
    }
 
    @FXML
    private void QuitAction(ActionEvent event) {
        System.out.println("You Selected Quit from menu.");
        Platform.exit();
    }
 
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }    
 
}

 
 上のコードに追加したイベント用のメソッド「QuitAction」の中の Platform.exit(); という記述はアプリケーションの終了処理を行うものです.
 
注意: FXMLで構築したコントロール(GUI部品)はこのクラス内のオブジェクトとして宣言する必要があり,宣言文の直前にはアノテーション「@FXML」を記述する必要があります.
 

【プログラムの実行】

 作成したプログラムを実行するには,NetBeans IDEのメニュー「実行」から「プロジェクト…を実行」を選びます.(下図)
NetBeans05
するとプログラムがコンパイルされて実行されます.(下図)
NetBeans08
 

【アプリケーションのビルド】

 作成したプログラムを,単体で実行できるパッケージにビルドするには,NetBeans IDEのメニュー「実行」から「プロジェクト…をビルド」を選びます.(下図)
NetBeans09
 
この操作によって,ビルドされたパッケージが “.jar” という拡張子のついたファイルとして,プロジェクトフォルダ内の “dist” フォルダの中に生成されます.(下図)
NetBeans10
 
 このjarファイルはダブルクリックで実行を開始することができます.

——————————————————-
FXMLアプリケーション構築例(NetBeans IDE & Java FX Scene Builder)
 画像ビューワ(複数ウィンドウを持つアプリ)