Lecture

Java プログラミング入門

このページは、学部2年生向け授業である、「マルチメディアプログラミング実習」 のために用意しました。

(Wikiの仕様で大文字小文字が混在した英単語に疑問符?が追加されるところがありますが、無視してください。)

第11章 入出力

Javaの入出力は、ファイル、ネットワーク、キーボード、ディスプレイを対象としています。C言語に比べて、高機能な上に、ネットワークへの入出力も標準装備されているところが便利です。

(ファイル、ネットワーク、キーボード)
    |
    | 入力ストリーム
    |
    V
(Javaプログラム)
    |
    | 出力ストリーム
    |
    V
(ファイル、ネットワーク、ディスプレイ)

バイトストリーム

データを入出力するのがバイトストリームです。 ここでは、

  • File Output Stream
  • Data Output Stream
  • File Input Stream
  • Data Input Stream

を使ってみます。

File Output Streamを使ってバイト単位で書き出し

こちらで機能を確認しましょう。

https://docs.oracle.com/javase/jp/8/docs/api/index.html

基本的なインスタンスメソッドは、writeとcloseです。writeには1バイトの書き込み、バイト配列の書き込みがあります。IOExceptionを投げるので、キャッチします。

write(int b)

は、int型の引数の下位1バイトを書き出します。以下のプログラムでファイルに1バイト書き出すことができます。

import java.io.*;

public class FoutTest {
	public static void main(String[] args) {
		try {
			FileOutputStream fout = new FileOutputStream("fout.dat");
			fout.write(1234);
			fout.close();
		}
		catch (IOException e) {
			System.out.println(e);
		}
	}
}

これでfout.datという名前のファイルができあがるはずです。 作ったファイルを

hexdump fout.dat

してみてください

$ hexdump fout.dat 
0000000 d2                                             
0000001

1234は0x4d2だったのでその下1バイトが書き込まれました。

Data Output StreamでJava整数型データを出力する

こちらで機能を確認しましょう。

https://docs.oracle.com/javase/jp/8/docs/api/index.html

Javaのいろいろなデータ型を書き出すことができます。 int, long, short, float, double, booleanなどのデータを書き出します。 以下では、int型データを書き出しています。 なお、Data Output StreamはFile Output Streamの機能を利用しています。 Data Output Streamのコンストラクトには、File Output Streamのインスタンスが必要です。 なので2段階のコンストラクト作業になります。

import java.io.*;

public class DoutTest {
	public static void main (String[] args) {
		try {
			FileOutputStream fout = new FileOutputStream("dout.dat");
			DataOutputStream dout = new DataOutputStream(fout);
			dout.writeInt(100);
			dout.close();
			
		}catch (Exception e) {
			System.out.println(e);
		}
	}
}

これでdout.datという名前のファイルができあがるはずです。 作ったファイルを

hexdump dout.dat

してみてください

e100:java siio$ hexdump dout.dat 
0000000 00 00 00 64                                    
0000004

int型は4バイトなので4バイトのファイルが出来上がっています。100は0x000064なので、その内容のファイルです。

整数を入出力する例

File/Data Output Streamにはそれぞれ対応したFile/Data Input Streamがあります。 こちらで機能を確認しましょう。

https://docs.oracle.com/javase/jp/8/docs/api/index.html

Javaのint型のデータで100をファイルに書いて、これを読み込む例です。

import java.io.*;

public class DoutTest {
	public static void main (String[] args) {
		try {
			FileOutputStream fout = new FileOutputStream("dout.dat");
			DataOutputStream dout = new DataOutputStream(fout);
			dout.writeInt(100);
			dout.close();
			
			FileInputStream finput = new FileInputStream("dout.dat");
			DataInputStream dinput = new DataInputStream(finput);
			System.out.println(dinput.readInt());
			dinput.close();
			
		}catch (Exception e) {
			System.out.println(e);
		}
	}
}

演習

1から100までのint型の数値をwirteIntメソッドでファイルに書き出すプログラムを書いてください。また、そのファイルをreadIntメソッドで読み込み、表示してください。

作ったファイルを

hexdump dout.dat

してみてください

解答例

import java.io.*;

public class DoutTest {
	public static void main (String[] args) {
		int i;
		try {
			FileOutputStream fout = new FileOutputStream ("dout.dat");
			DataOutputStream dout = new DataOutputStream(fout);
			for(i=1;i<101;i++) dout.writeInt(i);
			dout.close();
			
			FileInputStream fin = new FileInputStream ("dout.dat");
			DataInputStream din = new DataInputStream(fin);
			
			for(i=1;i<101;i++) System.out.println(din.readInt());
			din.close();
			
		} catch (FileNotFoundException e) {
			System.out.println(e);
		} catch (IOException e) {
			System.out.println(e);
		}
	}
}

文字ストリーム

文字を読み書きするのが文字ストリームです。文字に適した処理が用意されています。 ReaderとWriterというクラスのグループがあります。

文字列の書き出し

File Writerを使うと文字列を書き出すことができます。 close, flush, writeなどのメソッドがあります。 こちらで機能を確認しましょう。

https://docs.oracle.com/javase/jp/8/docs/api/index.html

File Writerにはwrite()メソッドで、文字や、文字配列や、Stringを書き出すことができます。 以下ではStringを書き出しています。

import java.io.*;

public class PrintWriterTest{
	public static void main(String[] args) {
		try {
		//writer.txtというファイルを作って文字を書き込む
			FileWriter fwriter = new FileWriter("writer.txt");
			fwriter.write("Multimedia Programming 実習");
			fwriter.close();	
		}
		catch (IOException e) {
			System.out.println(e);
		}
	}
}

また、Print Writerというクラスでは、System Out Printlnのようにprintlnに相当する機能が使えます。 Javaのいろいろなデータを書き出すのに便利です。

printlnで書き出すプログラム

writer.txtというファイルに、

int x = 2020;
String s = "Multimedia Programming 実習";

というJavaの変数を、printlnで書き出すプログラムを作ってください。

import java.io.*;

public class PrintWriterTest{
	public static void main(String[] args) {
		try {
		//writer.txtというファイルを作って文字を書き込む
			PrintWriter pwriter = new PrintWriter("writer.txt");
			pwriter.println(2020);
			pwriter.println("Multimedia Programming 実習");
			pwriter.close();	
		}
		catch (IOException e) {
			System.out.println(e);
		}
	}
}

作ったファイルを hexdump してみてください

$ hexdump writer.txt 
0000000 32 30 32 30 0a 4d 75 6c 74 69 6d 65 64 69 61 20
0000010 50 72 6f 67 72 61 6d 6d 69 6e 67 20 e5 ae 9f e7
0000020 bf 92 0a                                       
0000023

hexdump -cでキャラクタ表示にもなります。

$ hexdump -c writer.txt 
0000000   2   0   2   0  \n   M   u   l   t   i   m   e   d   i   a    
0000010   P   r   o   g   r   a   m   m   i   n   g       ?   ? 237   ?
0000020   ? 222  \n                                                    
0000023

2020という数値は、int型なのですが、ASCII文字列に変換されて文字として書き出されていることがわかります。 「Multimedia Programming 実習」は、もともとが文字列なので、そのまま文字列として書き出されています。0x0Aは改行コードです。 int型などのデータを文字に自動変換してくれるところが、Print Writerの特徴です。 Stringだけでしたら、File Writerの機能を使っても同様に書き出すことが可能です。

read Lineで改行コードまでを読み込む

File ReaderはFile Writerと同様に文字列を読み込みます。 読み込む文字数を指定して読み込むことも可能です。 さらに便利なクラスがBuffered Readerで、こちらは改行文字までを読み込んでくれます。 こちらで機能を確認しましょう。

https://docs.oracle.com/javase/jp/8/docs/api/index.html

Buffered ReaderもFile Readerのインスタンスから作りますので、2段階のコンストラクションになります。

writer.txtというテキストファイルがあるとして、これから1行ずつ読み込んで画面表示するプログラムは以下のようになります。

public class BufferedReaderTest{
	public static void main(String[] args) {
		try {
			FileReader freader = new FileReader("writer.txt");
			BufferedReader breader = new BufferedReader(freader);
			String tmp;
			while( (tmp=breader.readLine() ) != null) {
				System.out.println(tmp);
			}
			breader.close();
		}
		catch (IOException e) {
			System.out.println(e);
		}
	}
}

このプログラムを参考にして、 先のPrint Writer Testに書き足して、 書き込んだデータを読み出して画面に表示するプログラムを作ってください。

ヒント:

import java.io.*;

public class PrintWriterTest{
	public static void main(String[] args) {
		try {
		//writer.txtというファイルを作って文字を書き込む
			PrintWriter pwriter = new PrintWriter("writer.txt");
			pwriter.println(2020);
			pwriter.println("Multimedia Programming 実習");
			pwriter.close();	
			 
			 
			 ここに書き足す
			 
			 
		}
		catch (IOException e) {
			System.out.println(e);
		}
	}
}

解答例:

import java.io.*;

public class PrintWriterTest{
	public static void main(String[] args) {
		try {
		//writer.txtというファイルを作って文字を書き込む
			PrintWriter pwriter = new PrintWriter("writer.txt");
			pwriter.println(2020);
			pwriter.println("Multimedia Programming 実習");
			pwriter.close();			
		//writer.txtのファイルの中身をSystem.out.printlnで表示する
			FileReader freader = new FileReader("writer.txt");
			BufferedReader breader = new BufferedReader(freader);
			String tmp;
			while( (tmp=breader.readLine() ) != null) {
				System.out.println(tmp);
			}
			breader.close();
		}
		catch (IOException e) {
			System.out.println(e);
		}
	}
}

標準入出力

標準入出力には、

  • キーボードからプログラムへの標準入力
  • プログラムからディスプレイへの標準出力
  • エラー出力

の3種類があります。これらはJavaのクラス変数として定義されています。

  • System.in キーボードからプログラムへの標準入力
  • System.out プログラムからディスプレイへの標準出力
  • System.err エラー出力

それぞれの型は、

  • System.in は Input Stream型
  • System.out は Print Stream型
  • System.err は Print Stream型

です。使えるメソッドはこちらで確認できます。

https://docs.oracle.com/javase/jp/8/docs/api/index.html

標準入力から読み込んだ文字列をそのままディスプレイに表示するプログラム

import java.io.*;

public class StandardIOTest {
	public static void main(String[] args) {
	
		try {
			//System.inからInputStreamReaderを作り、それからBufferedReaderを作る
			InputStreamReader ireader = new InputStreamReader (System.in);
			BufferedReader breaderK = new BufferedReader(ireader);
			
			System.out.println("文字列を入力してリターンを押してください");
			String line = breaderK.readLine();
			System.out.println("あなたが入力した文字列" + line);
			}
		catch(IOException e) {
				System.out.println(e);
			}
	}
}

演習

キーボードから1行入力された文字列から writer.txtという名前のテキストファイルを作るプログラムを作ってください。

e100:java siio$ java KeyToFile 
Hello, これはテストです。
Hello, これはテストです。
e100:java siio$ cat writer.txt 
Hello, これはテストです。

ヒント

 import java.io.*;
 
 public class KeyToFile {
 	public static void main(String[] args) {
 	
 		try {


ここにプログラムを書く
 		
 			}
		catch(IOException e) {
 				System.out.println(e);
  			}
    }
 }

解答例

import java.io.*;

public class KeyToFile {
	public static void main(String[] args) {
	
		try {
			InputStreamReader ireader = new InputStreamReader (System.in);
			BufferedReader breaderK = new BufferedReader(ireader);
			String line = breaderK.readLine();
			
			PrintWriter pwriter = new PrintWriter("writer.txt");
			pwriter.println(line);
			pwriter.close();
			
			FileReader freader = new FileReader("writer.txt");
			BufferedReader breaderF = new BufferedReader(freader);
			
			String tmp=null;		
			while(  (tmp=breaderF.readLine())  != null)
				System.out.println(tmp);
			
			breaderF.close();
		
			}
			catch(IOException e) {
				System.out.println(e);
			}
	}
}

http://www.ocha.ac.jp/の内容を表示するプログラムを書いてみよう

http://gyazo.com/13044fdd9d372118a1f6fe93896eadb3.png

ヒント1

以下のリンクからURLクラスを選択して、調べましょう。

https://docs.oracle.com/javase/jp/8/docs/api/index.html

ヒント2

import java.net.*;

が必要です。

URL targetURL = new URL("http://www.ocha.ac.jp/");

でURLクラスのインスタンスが得られる。

InputStream istream = targetURL.openStream();

でこれからInputStream?のインスタンスが得られる。

InputStreamReader isreader = new InputStreamReader(istream);

でこれからInputStreamReader?のインスタンスが得られる。

BufferedReader breader = new BufferedReader(  isreader );

でこれからBufferedReader? のインスタンスが得られる。

ヒント3

import java.io.*;
import java.net.*;

public class URLTest {
	public static void main (String argv[]) {
		try {
			
			 
			 ここにプログラムを書く
			 
			 
		} catch (IOException e) {
			System.out.println("error...");
		}
	}
}

ヒント4:

import java.io.*;
import java.net.*;

public class URLTest {
	public static void main (String argv[]) {
		try {
			URL targetURL = new URL("http://www.ocha.ac.jp/");
			InputStream istream = targetURL.openStream();
			InputStreamReader isreader = new InputStreamReader(istream);
			BufferedReader breader = new BufferedReader(  isreader );
		
ここで一行ずつ読み込む

		} catch (IOException e) {
			System.out.println("error...");
		}
	}
}

解答例:

import java.io.*;
import java.net.*;

public class URLTest {
	public static void main (String argv[]) {
		try {
			URL targetURL = new URL("http://www.ocha.ac.jp/");
			InputStream istream = targetURL.openStream();
			InputStreamReader isreader = new InputStreamReader(istream);
			BufferedReader breader = new BufferedReader(  isreader );
		
			String line;
			while((line=breader.readLine()) != null) System.out.println(line);
		
		} catch (IOException e) {
			System.out.println("error...");
		}
	}
}

写真ファイルのダウンロード

http://siio.jp/cat.jpg 

をダウンロードして、cat.jpgというファイルを作るプログラムを作ってください。 データはテキストじゃなくて、バイナリーです。

ヒント1:

InputStream?のインスタンスに対してread()メソッドを使うと1バイトのデータが得られます。読み終わると-1になります。 1バイトのデータを書き出すなら、FileOutputStream?だけで可能です。

ヒント2:

import java.io.*;
import java.net.*;

public class URLJpeg {
	public static void main (String argv[]) {
		try {
			URL targetURL = new URL("http://siio.jp/cat.jpg");
			InputStream istream = targetURL.openStream();
			
			FileOutputStream fout = new FileOutputStream("cat.jpg");

というインスタンスを作って、

istream.read()

で読んで、

fout.write(1バイト)

で書き出します。

解答例

import java.io.*;
import java.net.*;

//http://siio.jp/cat.jpg
//をダウンロードして、cat.jpgというファイルを作るプログラム

public class URLJpeg {
	public static void main (String argv[]) {
		try {
			URL targetURL = new URL("http://siio.jp/cat.jpg");
			InputStream istream = targetURL.openStream();
			
			FileOutputStream fout = new FileOutputStream("cat.jpg");
			
			int aData;
			while((aData  = istream.read()) != -1) fout.write(aData);
			
			istream.close();
			fout.close();
			
			
		} catch (IOException e) {
			System.out.println("error...");
		}
	}
}

本日のレポート

上記のプログラム(URLJpeg.java, URLJpeg.class) を、出席番号+名前のフォルダにいれて、ZIP圧縮して提出してください。`

写真読み込みの高速化

上記の例では写真データを1バイトずつ読み書きしていました。 InputStream?のメソッドを調べると、複数バイト単位で読み込むメソッドがあります。 たとえば、1024バイトずつ読み書きすることで、処理速度が向上すると期待できます。 そこで、複数バイト読み書きするよう、上記のプログラムを変更して、 実際にどの程度(実行速度にして何倍くらい)性能向上するか確認してみましょう。

read

public int read(byte[] b)
         throws IOException
入力ストリームから配列長さだけのバイト数を読み込もうとし、それをバッファ配列 b に格納します。
実際に読み込まれたバイト数は整数として返されます。
戻り値は、バッファに読み込まれたバイトの合計数。ストリームの終わりに達してデータがない場合は -1

を使って読みこみ、

write

public void write(byte[] b,
                  int off,
                  int len)
           throws IOException
指定された byte 配列の、オフセット位置 off から始まる len バイトを出力ストリームに書き込みます。

を使ってください。

  • ヒント
byte[] data = new byte[1024];

という配列を用意して、

	int datalength;
	while(( datalength=istream.read(data)) != -1) fout.write(data, 0, datalength);

とします。

  • 解答例
import java.io.*;
import java.net.*;

//http://siio.jp/cat.jpg
//をダウンロードして、cat.jpgというファイルを作るプログラムを作ってください。
//データはテキストじゃなくて、バイナリーです。

public class URLJpeg2 {
	public static void main (String argv[]) {
		byte[] data = new byte[1024];
		try {
			URL targetURL = new URL("http://siio.jp/cat.jpg");
			InputStream istream = targetURL.openStream();
			
			FileOutputStream fout = new FileOutputStream("cat.jpg");
			
			int datalength;
			while(( datalength=istream.read(data)) != -1) fout.write(data, 0, datalength);
			
			istream.close();
			fout.close();
			
			
		} catch (IOException e) {
			System.out.println("error...");
		}
	}
}

ここでは1024バイトを読み込むことにしました。でも、InputStream?のメソッドを見ると、available()というのがあります。

available()
この入力ストリームのメソッドの次の呼出しによって、ブロックせずにこの入力ストリームから読み込むことができる(またはスキップできる)推定バイト数を返します。

これを使えば、適切な長さを見積もれるかもしれません。

引数のURLをファイルにするプログラムを考えてみましょう

curlというコマンドがあります。

curl http://ocha.ac.jp/

などとすると、htmlが見られますし、

curl http://siio.jp/cat.jpg > cat.jpg

などとすると、ファイルとして保存できます。これに近いプログラムを作ってみましょう。

宿題

上記の引数のURLをファイルにするプログラムを作ってください。 また、cat.jpgのファイル取得でまとめて読むことでどれくらい速度が改善したかを、 レポートにしてください。レポートの書式は任意です。(テキストファイルでかまいません)

これらのjava, class, レポートのファイルをまとめて、出席番号+名前のフォルダに入れて、圧縮して、12月10日の授業の開始時間に提出してください。


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-11-28 (木) 18:40:41 (15d)