- PR -

write()メソッドについて

1
投稿者投稿内容
未記入
会議室デビュー日: 2006/05/16
投稿数: 6
投稿日時: 2006-05-16 18:17
初心者ですが、宜しくお願いします。

FileWriter fw = new FileWriter(ファイルのパス);
fw.write(書き出す文字列);

このwrite()メソッドについて質問があります。
FileWriterは出力のキャラクターストリームであるため、
BufferedWriterのようにバッファリングをして書き込むのではなく
一文字ずつファイルにアクセスし書き込まれるのではないのですか?
にもかかわらず、fw.flush()などをつかってフラッシュしないとファイルに
書き込まれないのは、FileWriterもバッファリングして書き込んでるのでしょうか?
FileWriterはバッファリングをしないものだと教わったので良く分かりません。
ご教授お願いします。
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2006-05-16 18:42
FileWriterはOutputStreamWriterを拡張しています。
http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/io/OutputStreamWriter.html

ここに書いてあるとおり、基本となる出力ストリーム(FileOutputStream)に対しては
バッファリングされて出力されますが、これはOutputStreamWriterのバッファではなく、
エンコーディングコンバータ側のものです。

write()する度にFileOutputStreamに出力されるわけではありませんが、
エンコーディングコンバータへの出力がwrite()の度に発生することを防ぐために
BufferedWriterでラップした方が効率が良くなると書いてあります。

バッファ -> エンコーディングコンバータ -> バッファ -> ファイル
このような二階層のバッファを使うことになるわけです。
未記入
会議室デビュー日: 2006/05/16
投稿数: 6
投稿日時: 2006-05-16 20:43
早速の回答ありがとうございます。
こんなに早く回答をもらえるとは思ってもいませんでした。
回答の内容、自分にとってはかなり高度なので、回答を基に調べながら意味するところを理解したいと思います。
ありがとう。
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2006-05-16 22:09
それではもう少し踏み込んで、、、
引用:
FileWriterは出力のキャラクターストリームであるため、
BufferedWriterのようにバッファリングをして書き込むのではなく
一文字ずつファイルにアクセスし書き込まれるのではないのですか?


Javaのキャラクタ(char)を、例えばUTF-8として出力したとすると、
1文字につき1〜3バイトがバイトストリームに出力されるわけです。

仮にエンコーディングコンバータにバッファに類するものが全くなかったと
すると、3バイトの出力にバイトストリームのwrite()が3回呼ばれるわけです。
1文字出力するのに何回もwrite()を呼んだのではメソッド呼び出しや引数検査、
内部状態の検査等のオーバーヘッドが無駄にかかりすぎてしまうでしょう?

もちろんそんなお粗末な実装にするわけはないので、最低1文字を出力するのに
必要な分のバッファが必要になりますし、確保するからにはもっと溜め込める
ようにしても大差ないのでもっと大きく確保することになるわけです。

#エンコーディングによってはバッファ無しで実装できないものもあるかも?

これがエンコーディングコンバータ側のバッファです。

FileWriterがバッファリングしないというのは、write()では何もせずに、
そのままエンコーディングコンバータに丸投げしている、という意味です。

エンコーディングコンバータも頻繁にwrite()されると、以前の変換状態の
検査等でオーバーヘッドがあるので、バッファするのがベターですよ、と。
まぁ、こちらが有効なのはwrite(int)で毎回1文字ずつ出力をするような
作りのプログラムくらいのものだとは思いますけど。

ちなみに、オーバーヘッドにも大小があって、FileOutputStreamの先は
JNI経由でOSのシステムコール(もしくは類似品)が発生するので、
エンコーディング変換と較べるとこちらの方が遙かに大きいです。
未記入
会議室デビュー日: 2006/05/16
投稿数: 6
投稿日時: 2006-05-17 14:12
再度の詳しい回答ありがとうございます。

FileWriterは、エンコーディングコンバータ -> バッファ -> ファイル
BufferedWriterは、バッファ -> エンコーディングコンバータ -> バッファ -> ファイル という解釈でいいのでしょうか。
エンコーディングコンバータという言葉も始めて聞き、学校の勉強の浅はかさを思いしらされました。。
ありがとうございました。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2006-05-17 14:28
気になったので自分なりに調べてみました。

まず、FileWriter は、すなわち FileWriter extends OutputStreamWriter ですが、
http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/io/OutputStreamWriter.html
によると、
引用:

write() メソッドを呼び出すたびに、指定された文字に対してエンコーディングコンバータが呼び出されます。結果として生成されたバイトは、バッファに蓄積されてから基本となる出力ストリームに書き込まれます。このバッファのサイズは指定できますが、ほとんどの場合、デフォルトのサイズで十分です。write() メソッドに渡される文字はバッファに入らないので注意してください。


とあります。このバッファーのサイズはコンストラクターの引数で指定された CharsetEncoder を介して指定することになると思います。
そして、CharsetEncoder は、
http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/nio/charset/CharsetEncoder.html
によると、
引用:

導入されたバージョン:
1.4


となっていて、新しい仕様です。
一方 OutputStreamWriter は 1.1 から登場したクラスです。
結局は、OutputStreamWriter のバッファーサイズというのは、内部的な実装の仕様であり、将来も変わりうるものではないでしょうか。だから、結局は FileWriter がバッファーをどう使っているかは現時点のバーションのソースコードを見ないことには分からない、というのが本当のところだと思います。

--
unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86}
未記入
会議室デビュー日: 2006/05/16
投稿数: 6
投稿日時: 2006-05-17 22:35
違う方からも回答いただき感謝です。
質問内容が教科書的な内容で、回答の方も大変なのにありがとうでした。
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2006-05-18 02:15
引用:

unibonさんの書き込み (2006-05-17 14:28) より:
となっていて、新しい仕様です。
一方 OutputStreamWriter は 1.1 から登場したクラスです。
結局は、OutputStreamWriter のバッファーサイズというのは、内部的な実装の仕様であり、将来も変わりうるものではないでしょうか。だから、結局は FileWriter がバッファーをどう使っているかは現時点のバーションのソースコードを見ないことには分からない、というのが本当のところだと思います。



エンコーディング変換系のクラスが表に出たのはNIOが登場した1.4系からですが、
実際は内部的にはどのみち必要になるので、昔から実装上はあったと思いますよ。

#もちろん、仕様にはないので確かな話ではないですけどね。
1

スキルアップ/キャリアアップ(JOB@IT)