JAva new IOの概要

6175 ワード

Java New I/Oの役割我々のJAVAプログラムは大量のI/O操作を使用するが、プログラム性能の大部分がI/Oの影響を受けると、NIOを使って古いI/Oを書き換えることが考えられる~いわゆるNIOとは、JAVA類のjavaである.nioこのバッグ~J 2 SE 1です.4以降のバージョンならではのパッケージ~従来のI/O操作とは異なるソリューションを提供し、I/O操作が多い場合にプログラム性能を大幅に向上させることができます.
古いI/Oベースの従来のネットワークプログラムは以下のように記述されている:1)サーバSocketリスニングポートを開く2)プログラムはここでブロックされ,接続要求がある3)読み取り要求,送信要求4)接続を閉じる5)まで2~4ステップ繰り返す.
これが従来のブロックI/O動作であり,スレッドはcupを有効に利用せず,I/Oのブロックに多くの時間を費やすため,このスレッドは非効率である.
ブロックI/Oではなく新しい方法でブロック問題を解決し,システムの効率を向上させることができる.
NIO(new I/O)は4つの概念を導入した:・線形配列のデータバッファ、読み書き可能バッファ・1バイトコードとUnicode文字の文字セットマッピング・双方向チャネルChannels・セレクタSelectors
まずデータバッファBufferについてお話しします.1つのBufferでは、positionは現在のBufferの最初の読み書き可能なバイトの位置を表し、limitは最初の読み書きできないバイトの位置を表し、Capacityは容量を表しています(ここでは読みにくいのは、Bufferが双方向なので、読者が一気に理解できない場合は、後述の解釈を見ることができます).初期化されたBufferにとってpositionは0、limit=capacityです.
NIOでは、チャンネルでBufferのデータを読み書きします.1つのBufferのデータをChannelに書き込む場合、Bufferオブジェクトのflip()メソッドを呼び出す必要があります(ここでは、BufferがChannelと対話する場合にflipメソッドが必要であり、Buffer内部の自己操作であれば不要であることを明らかにする必要があります).例えば、ByteBuffer bb=ByteBuffer.allcateDirect(1024);bb.put(“this is a test”.getBytes()); 容量1024の直接的なByteBufferを割り当て、put(byte[]b)法によりこのバッファbbに文字列を格納する.FileOutputStreamout=new FileOutputStream("test.txt");FileChannel channel = out.getChannel(); このとき、ByteBufferオブジェクトのデータをtestに書き込むとします.txtの場合、FileChannelのwrite(ByteBuffer)メソッドを呼び出すことができるが、その前に必ずbbを実行する.flip()を呼び出し、channelを呼び出します.write(bb); flip()メソッドは、バッファのpositionを0、limitを既存データの最後の値に設定します.flip()を先に呼び出すなければtest.txtに書かれているものは空です~.
ByteBufferはBufferのサブクラスでjavaにあります.Nioパケットの下には、他の基本データ型のbufferもカプセル化されており、ByteBufferのasCharBuffer()などの方法で他の基本型のBufferを得ることができる.
java.Nioパッケージは、ByteOrderバイト順のタイプセキュリティ列挙です.Bufferは、特定の基本タイプのデータに使用されるコンテナです.ByteBufferバイトバッファ.CharBuffer文字バッファ.DoubleBuffer doubleバッファ.FloatBuffer floatバッファ.IntBuffer intバッファ.LongBuffer longバッファ.MappedByteBufferダイレクトバイトバッファは、ファイルのメモリマッピング領域です.ShortBuffer shortバッファ.
二)バイトコードとUnicode文字の文字セットマッピング
CharBufferの格納データをByteBufferに符号化し、ByteBufferに格納データをCharBufferに復号する必要がある場合にjavaが用いられる.nio.charset.CharsetEncoderとjava.nio.charset.CharsetDecoderになりました~~(実はByteBufferにはasCharBufferがあり、ByteBufferのバイトデータを直接文字データに変換することができますが、Charsetクラスはutf-8、iso-8895-1などの文字セットのマッピングを提供し、CharBufferのデータを様々なフォーマットの符号化に符号化し、CharsetDecoderで復号することができます)!以下は完全なプログラムコードで、簡単にCを示していますharBufferとByteBuffer間の符号化の変換:
package app.imo;
import java.nio.; import java.nio.charset.; public class CharsetTest {
    private ByteBuffer bb = null;
    private String s = "this is a test";
    public ByteBuffer encoder(){
            CharBuffer cb = CharBuffer.wrap(s);
            Charset cs = Charset.forName("UTF-8");
            CharsetEncoder ce = cs.newEncoder();
            try {
                    bb = ce.encode(cb); // CharBuffer   ByteBuffer
            } catch (CharacterCodingException e) {
                    e.printStackTrace();
            }
            return bb;
    }
    public static void main(String[] args){
            CharsetTest ct = new CharsetTest();
            ByteBuffer bb = ct.encoder();
            Charset c = Charset.forName("UTF-8");
            CharsetDecoder cd = c.newDecoder();
            CharBuffer cb = null;
            try {
                    cb = cd.decode(bb);
            } catch (CharacterCodingException e) {
                    e.printStackTrace();
            }
            System.out.println(cb);
    }
}
三)NIOの核心技術:Selector、SelectableChannel、SelectionKeyは上の3つのクラスがNIOの核心技術だと言っています.バッファ技術、文字セットマッピングがjavaに用意されているからといって、少しも過言ではないと思います.nio.チャンネルこのカバンの中
Selectorセレクタは、すべてのI/O操作をリスニングし、select()ブロッキングメソッドを使用して、チャネルにデータストリームがいつ処理されるかを決定します.Selectorクラスの静的方法Selector.Open()はSelectorインスタンスを取得します.SelectorオブジェクトとSelectableChannelオブジェクトは互いにマルチプレクサです.既存のセレクタSelectorには、チャネルのregister()メソッドで登録できます.register()メソッドの宣言は、public final SelectionKey register(Selector sel,int ops):指定されたセレクタにこのチャネルを登録し、選択キーを返します.ここで、sel-このチャネルを登録するセレクタ、ops-得られたキーの使用可能なアクションセット.opsには4つの選択肢があります.SelectionKey.OP_ACCEPT:ソケットが操作を受け入れるための操作セットビット.SelectionKey.OP_CONNECT:ソケット接続操作用の操作セットビット.SelectionKey.OP_READ:読み出し操作用の操作セットビット.SelectionKey.OP_WRITE:書き込み操作用の操作セットビット.
register()はSelectableChannelで定義された方法であり、SelectableChannelは抽象クラスであり、そのサブクラスを実現するにはDatagramChannel,Pipeがある.SinkChannel, Pipe.SourceChannel, ServerSocketChannel, SocketChannel. SelecableChannelインスタンスを生成するには、そのサブクラスの静的メソッドopen()を呼び出すことができ、例えば、ServerSocketChannelインスタンスを生成するには、ServerSocketChannel ssc=ServerSocketChannelを呼び出すことができる.open(); さらにsscを呼び出す.socket().Bind(InetSocketAddress)は、sscを指定したサーバSocketにバインドします.SelectableChannelのconfigureBlocking(boolean b)メソッドは、falseに設定すると、チャネルが非ブロックに構成されます.Selectorに登録するには、チャネルをブロックしないように構成する必要があります:ssc.configureBlocking(false); SelectionKey sk = ssc.register(selector,SelectionKey.OP_ACCEPT); 登録するとselectorを呼び出すことができます.select()メソッドは、対応するチャネルのセットがI/O操作に準備されているキーを選択します.
以下に2組のコードがあり、1組はNIOベースで、もう1組は古いI/Oで、皆さんは比較して参考することができます:古いI/Oクライアント:Socket s=new Socket("localhost",1111);BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream())); String str; while((str=in.readLine())!=null){
    System.out.println(str);
}旧I/Oサービス側:ServerSocket ss=new ServerSocket(1111);Socket c = ss.accept();//ここでブロックは、各サーバSocketがPrintWriter out=new PrintWriter(c.getOutputStream()、true)をブロックする必要があることを示す.out.write(“hello,client”.getBytes());
NIOクライアント:SocketChannel channel=SocketChannel.open(); channel.connect(new InetSocketAddress(“localhost”,1111)); ByteBuffer buffer = ByteBuffer.allocateDirect(512); channel.read(buffer);
NIOサービス:Selector selector=Selector.open(); ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.socket().bind(new InetSocketAddress(1111)); ssc.configureBlocking(false); ssc.register(selector,SelectionKey.OP_ACCEPT); ssc.select();//ここでブロックされているのは、すべてのサーバSocketChannelがブロックを共有できることを示しています.java.util.Set keys = ssc.selectedKeys(); java.util.Iterator i = keys.iterator(); while(i.hasNext()){ SelectionKey key = i.next; i.remove();
ServerSocketChannel serverSocket = (ServerSocketChannel)key.channel(); SocketChannel socket = serverSocket.accept(); ByteBuffer buf = ByteBuffer.wrap(“hello,client”.getBytes()); socket.write(buf); }