JavaNIO-クイックガイド

Java.nioパッケージはJava1.4で導入されました。JavaNIOのJavaI / Oとは対照的に、I / O操作用のバッファーおよびチャネル指向のデータフローが導入され、その結果、実行が高速化され、パフォーマンスが向上します。

また、NIO APIは、非同期または非ブロッキングの方法でIOイベントの複数のチャネルをリッスンする機能を導入するセレクターを提供します。NIOでは、速度が向上するオペレーティングシステムへのバッファーの充填と排出を含む最も時間のかかるI / Oアクティビティ。

NIOAPIの中心的な抽象化は次のとおりです-

  • データ、文字セット、およびそれらに関連するデコーダーとエンコーダーのコンテナーであるバッファー。バイトとUnicode文字の間で変換されます。

  • I / O操作を実行できるエンティティへの接続を表すさまざまなタイプのチャネル

  • セレクターと選択キー。これらは、選択可能なチャネルとともに、多重化された非ブロッキングI / O機能を定義します。

このセクションでは、マシンにJavaをダウンロードしてセットアップする方法について説明します。以下の手順で環境を設定してください。

Java SEは、Javaのダウンロードリンクから無料で入手できます。したがって、オペレーティングシステムに基づいたバージョンをダウンロードします。

指示に従ってJavaをダウンロードし、 .exeマシンにJavaをインストールします。マシンにJavaをインストールしたら、正しいインストールディレクトリを指すように環境変数を設定する必要があります-

Windows 2000 / XPのパスを設定する

Javaをc:\ Program Files \ java \ jdkディレクトリにインストールしたと仮定します-

  • 「マイコンピュータ」を右クリックし、「プロパティ」を選択します。

  • [詳細設定]タブの下にある[環境変数]ボタンをクリックします。

  • 次に、「Path」変数を変更して、Java実行可能ファイルへのパスも含まれるようにします。たとえば、パスが現在「C:\ WINDOWS \ SYSTEM32」に設定されている場合は、パスを「C:\ WINDOWS \ SYSTEM32; c:\ ProgramFiles \ java \ jdk \ bin」に変更します。

Windows 95/98 / MEのパスを設定する

Javaをc:\ Program Files \ java \ jdkディレクトリにインストールしたと仮定します-

  • 'C:\ autoexec.bat'ファイルを編集し、最後に次の行を追加します。
    'SET PATH =%PATH%; C:\ Program Files \ java \ jdk \ bin'

Linux、UNIX、Solaris、FreeBSDのパスを設定する

環境変数PATHは、Javaバイナリがインストールされている場所を指すように設定する必要があります。これを行うのに問題がある場合は、シェルのドキュメントを参照してください。

たとえば、シェルとしてbashを使用する場合は、 '。bashrcの末尾に次の行を追加します。exportPATH= / path / to / java:$ PATH'

人気のあるJavaエディター

Javaプログラムを作成するには、テキストエディタが必要です。市場にはさらに洗練されたIDEがあります。しかし今のところ、あなたは次のいずれかを考えることができます-

  • Notepad − Windowsマシンでは、メモ帳(このチュートリアルに推奨)、TextPadなどの単純なテキストエディターを使用できます。

  • Netbeans −はオープンソースで無料のJava IDEであり、からダウンロードできます。 http://www.netbeans.org/index.html。

  • Eclipse −これもEclipseオープンソースコミュニティによって開発されたjava IDEであり、からダウンロードできます。 https://www.eclipse.org/。

Java NIOは、従来のJava IO APIの進歩のために導入されました。NIOをIOよりも効率的にする主な機能強化は、NIOで使用されるチャネルデータフローモデルと、従来のIOタスクでのオペレーティングシステムの使用です。

JavaNIOとJavaIOの違いは、次のように説明できます。

  • 以前の投稿で述べたように、I / O操作用のNIOバッファーおよびチャネル指向のデータフローは、IOと比較してより高速な実行と優れたパフォーマンスを提供します。また、NIOは従来のI / Oタスクにオペレーティングシステムを使用するため、効率が向上します。

  • NIOとIOの違いの他の側面は、このIOがストリームラインデータフローを使用することです。つまり、一度に1バイトずつ、データオブジェクトをバイトに変換することに依存します。NIOはバイトのチャンクであるデータブロックを処理します。

  • JavaではIOストリームオブジェクトは単方向ですが、NIOではチャネルは双方向です。つまり、チャネルはデータの読み取りと書き込みの両方に使用できます。

  • IOの合理化されたデータフローでは、データを前後に移動できません。ストリームから読み取ったデータを前後に移動する必要がある場合は、最初にデータをバッファにキャッシュする必要があります。NIOの場合は、バッファ指向を使用します。これにより、キャッシュを必要とせずにデータにアクセスできます。

  • NIO APIはマルチスレッドもサポートしているため、IO操作の実行中に現在のスレッドがブロックされないように、データを非同期で読み書きできます。これにより、従来のJava IOAPIよりも効率的になります。

  • マルチスレッドの概念は、 Selectors Java NIOでは、非同期または非ブロッキング方式でIOイベントの複数のチャネルをリッスンできます。

  • NIOのマルチスレッドはそれをノンブロッキングにします。つまり、スレッドはデータが利用可能な場合にのみ読み取りまたは書き込みを要求されます。それ以外の場合、スレッドは他のタスクでしばらく使用できますが、マルチスレッドがないため、従来のJavaIOの場合は不可能です。ブロッキングとしてサポートされています。

  • NIOでは、単一のスレッドのみを使用して複数のチャネルを管理できますが、Java IOの場合、ブロッキングストリームからデータを読み取る場合よりもデータの解析がやや複雑になる可能性があるため、必要な接続が非常に少ない場合は一度に大量のデータを送信する場合は、この場合よりもJava IOAPIが最適な場合があります。

説明

名前が示すように、チャネルは一方の端からもう一方の端へのデータフローの平均として使用されます。ここでは、Java NIOチャネルは、バッファともう一方の端のエンティティ間で同じように機能します。つまり、チャネルは、バッファへのデータの読み取りと、バッファからのデータの書き込みに使用されます。

従来のJavaIOチャネルで使用されるストリームとは異なり、読み取りと書き込みの両方が可能です。JavaNIOチャネルは、ブロッキングモードと非ブロッキングモードの両方でデータの非同期フローをサポートします。

チャネルの実装

Java NIOチャネルは、主に次のクラスで実装されます-

  • FileChannel−ファイルからデータを読み取るために、ファイルチャネルを使用します。ファイルオブジェクトを直接作成することはできないため、ファイルチャネルのオブジェクトは、ファイルオブジェクトに対してgetChannel()メソッドを呼び出すことによってのみ作成できます。

  • DatagramChannel −データグラムチャネルは、UDP(ユーザーデータグラムプロトコル)を介してネットワーク経由でデータを読み書きできます。DataGramchannelのオブジェクトは、ファクトリメソッドを使用して作成できます。

  • SocketChannel− SocketChannelチャネルは、TCP(Transmission Control Protocol)を介してネットワーク経由でデータを読み書きできます。また、ファクトリメソッドを使用して新しいオブジェクトを作成します。

  • ServerSocketChannel− ServerSocketChannelは、Webサーバーと同じように、TCP接続を介してデータを読み書きします。着信接続ごとに、SocketChannelが作成されます。

次の例は、からのテキストファイルから読み取ります C:/Test/temp.txt コンテンツをコンソールに出力します。

temp.txt

Hello World!

ChannelDemo.java

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class ChannelDemo {
   public static void main(String args[]) throws IOException {
      RandomAccessFile file = new RandomAccessFile("C:/Test/temp.txt", "r");
      FileChannel fileChannel = file.getChannel();
      ByteBuffer byteBuffer = ByteBuffer.allocate(512);
      while (fileChannel.read(byteBuffer) > 0) {
         // flip the buffer to prepare for get operation
         byteBuffer.flip();
         while (byteBuffer.hasRemaining()) {
            System.out.print((char) byteBuffer.get());
         }
      }
      file.close();
   }
}

出力

Hello World!

説明

すでに述べたように、Java NIOチャネルのFileChannel実装は、作成、変更、サイズなどを含むファイルのメタデータプロパティにアクセスするために導入されています。これに加えて、ファイルチャネルはマルチスレッドであり、JavaNIOをJavaIOよりも効率的にします。

一般に、FileChannelは、ファイルからデータを読み取ったり、ファイルにデータを書き込んだりできるファイルに接続されたチャネルであると言えます。FileChannelのその他の重要な特性は、非ブロッキングモードに設定できないことです。常にブロッキングモードで実行されます。

ファイルチャネルオブジェクトを直接取得することはできません。ファイルチャネルのオブジェクトは次のいずれかによって取得されます。

  • getChannel() − FileInputStream、FileOutputStream、またはRandomAccessFileのいずれかのメソッド。

  • open() −デフォルトでチャネルを開くファイルチャネルのメソッド。

ファイルチャネルのオブジェクトタイプは、オブジェクト作成から呼び出されたクラスのタイプによって異なります。つまり、FileInputStreamのgetchannelメソッドを呼び出してオブジェクトを作成した場合、ファイルチャネルは読み取り用に開かれ、書き込みを試みるとNonWritableChannelExceptionがスローされます。

次の例は、Java NIOFileChannelからデータを読み書きする方法を示しています。

次の例は、からのテキストファイルから読み取ります C:/Test/temp.txt コンテンツをコンソールに出力します。

temp.txt

Hello World!

FileChannelDemo.java

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.HashSet;
import java.util.Set;

public class FileChannelDemo {
   public static void main(String args[]) throws IOException {
      //append the content to existing file 
      writeFileChannel(ByteBuffer.wrap("Welcome to TutorialsPoint".getBytes()));
      //read the file
      readFileChannel();
   }
   public static void readFileChannel() throws IOException {
      RandomAccessFile randomAccessFile = new RandomAccessFile("C:/Test/temp.txt",
      "rw");
      FileChannel fileChannel = randomAccessFile.getChannel();
      ByteBuffer byteBuffer = ByteBuffer.allocate(512);
      Charset charset = Charset.forName("US-ASCII");
      while (fileChannel.read(byteBuffer) > 0) {
         byteBuffer.rewind();
         System.out.print(charset.decode(byteBuffer));
         byteBuffer.flip();
      }
      fileChannel.close();
      randomAccessFile.close();
   }
   public static void writeFileChannel(ByteBuffer byteBuffer)throws IOException {
      Set<StandardOpenOption> options = new HashSet<>();
      options.add(StandardOpenOption.CREATE);
      options.add(StandardOpenOption.APPEND);
      Path path = Paths.get("C:/Test/temp.txt");
      FileChannel fileChannel = FileChannel.open(path, options);
      fileChannel.write(byteBuffer);
      fileChannel.close();
   }
}

出力

Hello World! Welcome to TutorialsPoint

Java NIOデータグラムは、コネクションレス型プロトコルを介してUDPパケットを送受信できるチャネルとして使用されます。デフォルトでは、データグラムチャネルはブロックされていますが、非ブロックモードで使用できます。非ブロックにするために、configureBlocking( false)method.DataGramチャネルは、次の名前の静的メソッドの1つを呼び出すことで開くことができます。 open() IPアドレスをパラメータとして使用できるため、マルチキャストに使用できます。

FileChannelと同様のデータグラムチャネルは、接続するためにデフォルトでは接続されません。ただし、connect()メソッドを明示的に呼び出す必要があります。ただし、データグラムチャネルは、接続する必要があるときに送信メソッドと受信メソッドを使用するために接続する必要はありません。読み取りメソッドと書き込みメソッドを使用するため。これらのメソッドはソケットアドレスを受け入れたり返したりしないためです。

データグラムチャネルを呼び出すことで、データグラムチャネルの接続ステータスを確認できます。 isConnected() データグラムチャネルは、接続されると、切断または閉じられるまで接続されたままになります。データグラムチャネルはスレッドセーフであり、マルチスレッドと同時実行性を同時にサポートします。

データグラムチャネルの重要な方法

  • bind(SocketAddress local) −このメソッドは、データグラムチャネルのソケットをこのメソッドのパラメータとして提供されるローカルアドレスにバインドするために使用されます。

  • connect(SocketAddress remote) −この方法は、ソケットをリモートアドレスに接続するために使用されます。

  • disconnect() −この方法は、ソケットをリモートアドレスに切断するために使用されます。

  • getRemoteAddress() −このメソッドは、チャネルのソケットが接続されているリモートロケーションのアドレスを返します。

  • isConnected() −すでに述べたように、このメソッドはデータグラムチャネルの接続ステータス、つまり接続されているかどうかを返します。

  • open() and open(ProtocolFamily family) −オープンメソッドは、単一アドレスのデータグラムチャネルを開くために使用され、パラメータ化されたオープンメソッドは、プロトコルファミリとして表される複数のアドレスのチャネルを開きます。

  • read(ByteBuffer dst) −このメソッドは、データグラムチャネルを介して指定されたバッファからデータを読み取るために使用されます。

  • receive(ByteBuffer dst) −この方法は、このチャネルを介してデータグラムを受信するために使用されます。

  • send(ByteBuffer src, SocketAddress target) −このメソッドは、このチャネルを介してデータグラムを送信するために使用されます。

次の例は、Java NIODataGramChannelからデータを送信する方法を示しています。

サーバー:DatagramChannelServer.java

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;

public class DatagramChannelServer {
   public static void main(String[] args) throws IOException {
      DatagramChannel server = DatagramChannel.open();
      InetSocketAddress iAdd = new InetSocketAddress("localhost", 8989);
      server.bind(iAdd);
      System.out.println("Server Started: " + iAdd);
      ByteBuffer buffer = ByteBuffer.allocate(1024);
      //receive buffer from client.
      SocketAddress remoteAdd = server.receive(buffer);
      //change mode of buffer
      buffer.flip();
      int limits = buffer.limit();
      byte bytes[] = new byte[limits];
      buffer.get(bytes, 0, limits);
      String msg = new String(bytes);
      System.out.println("Client at " + remoteAdd + "  sent: " + msg);
      server.send(buffer,remoteAdd);
      server.close();
   }
}

出力

Server Started: localhost/127.0.0.1:8989

クライアント:DatagramChannelClient.java

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;

public class DatagramChannelClient {
   public static void main(String[] args) throws IOException {
      DatagramChannel client = null;
      client = DatagramChannel.open();

      client.bind(null);

      String msg = "Hello World!";
      ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
      InetSocketAddress serverAddress = new InetSocketAddress("localhost",
        8989);

      client.send(buffer, serverAddress);
      buffer.clear();
      client.receive(buffer);
      buffer.flip();
    
      client.close();
   }
}

出力

クライアントを実行すると、サーバーに次の出力が出力されます。

Server Started: localhost/127.0.0.1:8989
Client at /127.0.0.1:64857  sent: Hello World!

Java NIOソケットチャネルは選択可能なタイプのチャネルです。つまり、セレクタを使用して多重化でき、ソケットを接続するストリーム指向のデータフローに使用されます。ソケットチャネルは、静的なものを呼び出すことで作成できます。 open() メソッド、既存のソケットを提供することはまだ存在していません。ソケットチャネルはopenメソッドを呼び出すことによって作成されますが、まだ接続されていません。ソケットチャネルを接続するために connect() ここで言及する1つのポイントは、チャネルが接続されておらず、I / O操作が試行された場合、このチャネルによってNotYetConnectedExceptionがスローされるため、IOを実行する前にチャネルが接続されていることを確認する必要があります。チャネルが接続されると、閉じられるまで接続されたままになります。ソケットチャネルの状態は、チャネルを呼び出すことによって判別できます。 isConnected 方法。

ソケットチャネルの接続は、そのを呼び出すことによって終了することができます finishConnect() 接続操作が進行中であるかどうかは、isConnectionPendingメソッドを呼び出すことで判別できます。デフォルトでは、ソケットチャネルは非ブロッキング接続をサポートします。また、Channelクラスで指定された非同期クローズ操作と同様の非同期シャットダウンもサポートします。

ソケットチャネルは、複数の同時スレッドで安全に使用できます。これらは同時読み取りと書き込みをサポートしますが、任意の時点で最大1つのスレッドが読み取りを行い、最大1つのスレッドが書き込みを行うことができます。connectメソッドとfinishConnectメソッドは相互に同期されており、これらのメソッドのいずれかの呼び出しの進行中に読み取りまたは書き込み操作を開始しようとすると、その呼び出しが完了するまでブロックされます。

ソケットチャネルの重要な方法

  • bind(SocketAddress local) −このメソッドは、このメソッドのパラメータとして提供されるローカルアドレスにソケットチャネルをバインドするために使用されます。

  • connect(SocketAddress remote) −この方法は、ソケットをリモートアドレスに接続するために使用されます。

  • finishConnect() −この方法は、ソケットチャネルを接続するプロセスを終了するために使用されます。

  • getRemoteAddress() −このメソッドは、チャネルのソケットが接続されているリモートロケーションのアドレスを返します。

  • isConnected() −すでに述べたように、このメソッドはソケットチャネルの接続ステータス、つまり接続されているかどうかを返します。

  • open() and open((SocketAddress remote) − openメソッドは、指定されたアドレスに対してソケットチャネルを開くために使用され、パラメータ化されたopenメソッドは指定されたリモートアドレスに対してチャネルを開き、それに接続します。この便利なメソッドは、open()メソッドを呼び出し、結果としてconnectメソッドを呼び出すかのように機能します。ソケットチャネル、それをリモートに渡し、次にそのチャネルを返します。

  • read(ByteBuffer dst) −このメソッドは、ソケットチャネルを介して指定されたバッファからデータを読み取るために使用されます。

  • isConnectionPending() −このメソッドは、このチャネルで接続操作が進行中であるかどうかを示します。

次の例は、Java NIOSocketChannelからデータを送信する方法を示しています。

C:/Test/temp.txt

Hello World!

クライアント:SocketChannelClient.java

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;

public class SocketChannelClient {
   public static void main(String[] args) throws IOException {
      ServerSocketChannel serverSocket = null;
      SocketChannel client = null;
      serverSocket = ServerSocketChannel.open();
      serverSocket.socket().bind(new InetSocketAddress(9000));
      client = serverSocket.accept();
      System.out.println("Connection Set:  " + client.getRemoteAddress());
      Path path = Paths.get("C:/Test/temp1.txt");
      FileChannel fileChannel = FileChannel.open(path, 
         EnumSet.of(StandardOpenOption.CREATE, 
            StandardOpenOption.TRUNCATE_EXISTING,
            StandardOpenOption.WRITE)
         );      
      ByteBuffer buffer = ByteBuffer.allocate(1024);
      while(client.read(buffer) > 0) {
         buffer.flip();
         fileChannel.write(buffer);
         buffer.clear();
      }
      fileChannel.close();
      System.out.println("File Received");
      client.close();
   }
}

出力

クライアントを実行すると、サーバーが起動するまで何も出力されません。

サーバー:SocketChannelServer.java

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import java.nio.file.Paths;

public class SocketChannelServer {
   public static void main(String[] args) throws IOException {
      SocketChannel server = SocketChannel.open();
      SocketAddress socketAddr = new InetSocketAddress("localhost", 9000);
      server.connect(socketAddr);

      Path path = Paths.get("C:/Test/temp.txt");
      FileChannel fileChannel = FileChannel.open(path);
      ByteBuffer buffer = ByteBuffer.allocate(1024);
      while(fileChannel.read(buffer) > 0) {
         buffer.flip();
         server.write(buffer);
         buffer.clear();
      }
      fileChannel.close();
      System.out.println("File Sent");
      server.close();
   }
}

出力

サーバーを実行すると、次のように出力されます。

Connection Set:  /127.0.0.1:49558
File Received

Java NIOサーバーソケットチャネルは、ソケットを接続するストリーム指向のデータフローに使用される選択可能なタイプのチャネルです。サーバーソケットチャネルは、静的なものを呼び出すことで作成できます。 open() メソッド、既存のソケットを提供することはまだ存在していません。サーバーソケットチャネルは、openメソッドを呼び出すことによって作成されますが、まだバインドされていません。ソケットチャネルをバインドするために bind() メソッドが呼び出されます。

ここで言及する1つのポイントは、チャネルがバインドされておらず、I / O操作が試行された場合、このチャネルによってNotYetBoundExceptionがスローされるため、IO操作を実行する前にチャネルがバインドされていることを確認する必要があります。

サーバーソケットチャネルの着信接続は、ServerSocketChannel.accept()メソッドを呼び出すことによってリッスンされます。accept()メソッドが戻ると、着信接続のあるSocketChannelを返します。したがって、accept()メソッドは着信接続が到着するまでブロックします。チャネルが非ブロッキングモードの場合、保留中の接続がない場合、acceptメソッドはすぐにnullを返します。それ以外の場合は、新しい接続が使用可能になるか、I / Oエラーが発生するまで、無期限にブロックされます。

新しいチャネルのソケットは最初はバインドされていません。接続を受け入れる前に、ソケットのバインドメソッドの1つを介して特定のアドレスにバインドする必要があります。また、新しいチャネルは、システム全体のデフォルトのSelectorProviderオブジェクトのopenServerSocketChannelメソッドを呼び出すことによって作成されます。

ソケットチャネルのようにサーバーソケットチャネルはを使用してデータを読み取ることができます read()最初に、バッファが割り当てられます。ServerSocketChannelから読み取られたデータは、バッファーに格納されます。次に、ServerSocketChannel.read()メソッドを呼び出して、ServerSocketChannelからバッファーにデータを読み取ります。read()メソッドの整数値は、バッファーに書き込まれたバイト数を返します

同様に、データはを使用してサーバーソケットチャネルに書き込むことができます write() パラメータとしてバッファを使用するメソッド。通常、バッファに書き込み可能なバイトがなくなるまでwrite()メソッドを繰り返す必要があるため、whileループでwriteメソッドを使用します。

ソケットチャネルの重要な方法

  • bind(SocketAddress local) −このメソッドは、このメソッドのパラメータとして提供されるローカルアドレスにソケットチャネルをバインドするために使用されます。

  • accept() −このメソッドは、このチャネルのソケットへの接続を受け入れるために使用されます。

  • connect(SocketAddress remote) −この方法は、ソケットをリモートアドレスに接続するために使用されます。

  • finishConnect() −この方法は、ソケットチャネルを接続するプロセスを終了するために使用されます。

  • getRemoteAddress() −このメソッドは、チャネルのソケットが接続されているリモートロケーションのアドレスを返します。

  • isConnected() −すでに述べたように、このメソッドはソケットチャネルの接続ステータス、つまり接続されているかどうかを返します。

  • open() − openメソッドは、指定されていないアドレスのソケットチャネルを開くために使用されます。この便利なメソッドは、open()メソッドを呼び出し、結果のサーバーソケットチャネルでconnectメソッドを呼び出し、リモートで渡し、そのチャネルを返すかのように機能します。

  • read(ByteBuffer dst) −このメソッドは、ソケットチャネルを介して指定されたバッファからデータを読み取るために使用されます。

  • setOption(SocketOption<T> name, T value) −このメソッドは、ソケットオプションの値を設定します。

  • socket() −このメソッドは、このチャネルに関連付けられているサーバーソケットを取得します。

  • validOps() −このメソッドは、このチャネルでサポートされている操作を識別する操作セットを返します。サーバーソケットチャネルは、新しい接続の受け入れのみをサポートするため、このメソッドはSelectionKey.OP_ACCEPTを返します。

次の例は、Java NIOServerSocketChannelからデータを送信する方法を示しています。

C:/Test/temp.txt

Hello World!

クライアント:SocketChannelClient.java

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;

public class SocketChannelClient {
   public static void main(String[] args) throws IOException {
      ServerSocketChannel serverSocket = null;
      SocketChannel client = null;
      serverSocket = ServerSocketChannel.open();
      serverSocket.socket().bind(new InetSocketAddress(9000));
      client = serverSocket.accept();
      System.out.println("Connection Set:  " + client.getRemoteAddress());
      Path path = Paths.get("C:/Test/temp1.txt");
      FileChannel fileChannel = FileChannel.open(path, 
         EnumSet.of(StandardOpenOption.CREATE, 
            StandardOpenOption.TRUNCATE_EXISTING,
            StandardOpenOption.WRITE)
         );      
      ByteBuffer buffer = ByteBuffer.allocate(1024);
      while(client.read(buffer) > 0) {
         buffer.flip();
         fileChannel.write(buffer);
         buffer.clear();
      }
      fileChannel.close();
      System.out.println("File Received");
      client.close();
   }
}

出力

クライアントを実行すると、サーバーが起動するまで何も出力されません。

サーバー:SocketChannelServer.java

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import java.nio.file.Paths;

public class SocketChannelServer {
   public static void main(String[] args) throws IOException {
      SocketChannel server = SocketChannel.open();
      SocketAddress socketAddr = new InetSocketAddress("localhost", 9000);
      server.connect(socketAddr);
      Path path = Paths.get("C:/Test/temp.txt");
      FileChannel fileChannel = FileChannel.open(path);
      ByteBuffer buffer = ByteBuffer.allocate(1024);
      while(fileChannel.read(buffer) > 0) {
         buffer.flip();
         server.write(buffer);
         buffer.clear();
      }
      fileChannel.close();
      System.out.println("File Sent");
      server.close();
   }
}

出力

サーバーを実行すると、次のように出力されます。

Connection Set:  /127.0.0.1:49558
File Received

Java NIOは、Javaの従来のIO APIと比較して、データIO操作用に最適化されたAPIであることがわかっています。JavaNIOが提供するもう1つの追加サポートは、チャネルへの複数のバッファーとの間でデータの読み取り/書き込みを行うことです。書き込みサポートはスキャッターアンドギャザーと呼ばれ、読み取りデータの場合は単一チャネルから複数のバッファーにデータが分散され、書き込みデータの場合は複数のバッファーから単一チャネルにデータが収集されます。

チャネルからのこの複数の読み取りと書き込みを実現するために、JavaNIOが以下の例に示すようにデータの読み取りと書き込みを提供するScatteringByteChannelとGatheringByteChannelAPIがあります。

ScatteringByteChannel

Read from multiple channels −これでは、単一のチャネルから複数のバッファにデータを読み取るようにしました。このために、複数のバッファが割り当てられ、バッファタイプの配列に追加されます。次に、この配列がパラメータとしてScatteringByteChannel read()メソッドに渡され、そこからデータが書き込まれます。シーケンス内のチャネルは、バッファが配列内で発生します。バッファがいっぱいになると、チャネルは次のバッファを埋めるために移動します。

次の例は、JavaNIOでデータの分散がどのように実行されるかを示しています。

C:/Test/temp.txt

Hello World!
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ScatteringByteChannel;

public class ScatterExample {	
   private static String FILENAME = "C:/Test/temp.txt";
   public static void main(String[] args) {
      ByteBuffer bLen1 = ByteBuffer.allocate(1024);
      ByteBuffer bLen2 = ByteBuffer.allocate(1024);
      FileInputStream in;
      try {
         in = new FileInputStream(FILENAME);
         ScatteringByteChannel scatter = in.getChannel();
         scatter.read(new ByteBuffer[] {bLen1, bLen2});
         bLen1.position(0);
         bLen2.position(0);
         int len1 = bLen1.asIntBuffer().get();
         int len2 = bLen2.asIntBuffer().get();
         System.out.println("Scattering : Len1 = " + len1);
         System.out.println("Scattering : Len2 = " + len2);
      } 
      catch (FileNotFoundException exObj) {
         exObj.printStackTrace();
      }
      catch (IOException ioObj) {
         ioObj.printStackTrace();
      }
   }
}

出力

Scattering : Len1 = 1214606444
Scattering : Len2 = 0

最後に、Java NIOのスキャッター/ギャザーアプローチは、適切に使用すると、最適化されたマルチタスクとして導入されたと結論付けることができます。これにより、読み取ったデータを複数のバケットに分離したり、組み立てたりするといううんざりする作業をオペレーティングシステムに委任できます。データのチャンクを全体に分散します。これにより、バッファコピーを回避することで時間を節約し、オペレーティングシステムをより効率的に使用し、書き込みとデバッグに必要なコードの量を減らすことができます。

Java NIOは、Javaの従来のIO APIと比較して、データIO操作用に最適化されたAPIであることがわかっています。JavaNIOが提供するもう1つの追加サポートは、チャネルへの複数のバッファーとの間でデータの読み取り/書き込みを行うことです。書き込みサポートはスキャッターアンドギャザーと呼ばれ、読み取りデータの場合は単一チャネルから複数のバッファーにデータが分散され、書き込みデータの場合は複数のバッファーから単一チャネルにデータが収集されます。

チャネルからのこの複数の読み取りと書き込みを実現するために、JavaNIOが以下の例に示すようにデータの読み取りと書き込みを提供するScatteringByteChannelとGatheringByteChannelAPIがあります。

GatheringByteChannel

write to multiple channels −これでは、複数のバッファから単一のチャネルにデータを書き込むようにしました。この場合も、複数のバッファが割り当てられ、バッファタイプの配列に追加されます。次に、この配列がパラメータとしてGatheringByteChannel write()メソッドに渡され、データが書き込まれます。シーケンス内の複数のバッファーから、バッファーは配列内で発生します。ここで覚えておくべき1つのポイントは、バッファーの位置と制限の間のデータのみが書き込まれることです。

次の例は、JavaNIOでデータ収集がどのように実行されるかを示しています。

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.GatheringByteChannel;

public class GatherExample {
   private static String FILENAME = "C:/Test/temp.txt";
   public static void main(String[] args) {
      String stream1 = "Gather data stream first";
      String stream2 = "Gather data stream second";
      ByteBuffer bLen1 = ByteBuffer.allocate(1024);
      ByteBuffer bLen2 = ByteBuffer.allocate(1024);
      // Next two buffer hold the data we want to write
      ByteBuffer bstream1 = ByteBuffer.wrap(stream1.getBytes());
      ByteBuffer bstream2 = ByteBuffer.wrap(stream2.getBytes());
      int len1 = stream1.length();
      int len2 = stream2.length();
      // Writing length(data) to the Buffer
      bLen1.asIntBuffer().put(len1);
      bLen2.asIntBuffer().put(len2);
      System.out.println("Gathering : Len1 = " + len1);
      System.out.println("Gathering : Len2 = " + len2);
      // Write data to the file
      try { 
         FileOutputStream out = new FileOutputStream(FILENAME);
         GatheringByteChannel gather = out.getChannel();						
         gather.write(new ByteBuffer[] {bLen1, bLen2, bstream1, bstream2});
         out.close();
         gather.close();
      }
      catch (FileNotFoundException exObj) {
         exObj.printStackTrace();
      }
      catch(IOException ioObj) {
         ioObj.printStackTrace();
      }
   }
}

出力

Gathering : Len1 = 24
Gathering : Len2 = 25

最後に、Java NIOのスキャッター/ギャザーアプローチは、適切に使用すると、最適化されたマルチタスクとして導入されたと結論付けることができます。これにより、読み取ったデータを複数のバケットに分離したり、組み立てたりするといううんざりする作業をオペレーティングシステムに委任できます。データのチャンクを全体に分散します。これにより、バッファコピーを回避することで時間を節約し、オペレーティングシステムをより効率的に使用し、書き込みとデバッグに必要なコードの量を減らすことができます。

Java NIOのバッファは、バッファがチャネルへのエンドポイントとして機能するように、チャネルへのデータの書き込みまたはチャネルからのデータの読み取りに使用できるデータチャンクの固定サイズのコンテナとして機能する単純なオブジェクトとして扱うことができます。

これは、チャネルとの間でデータを読み書きするためにメモリブロックを処理するのをより便利にする一連のメソッドを提供します。

バッファは、IOデータがデータの非同期および同時フローをサポートしないストリームの形式で処理される場合のように、従来のIOと比較してNIOパッケージをより効率的かつ高速にします。また、IOはチャンクまたはバイトのグループでのデータ実行を許可しません。

Java NIOバッファを定義するプライマリパラメータは、次のように定義できます。

  • Capacity −バッファに格納できるデータ/バイトの最大量。バッファの容量は変更できません。バッファがいっぱいになったら、書き込む前にクリアする必要があります。

  • Limit −制限は、バッファのモードに従って意味を持ちます。つまり、バッファの書き込みモードでは、制限は容量に等しく、これは、バッファに書き込むことができる最大データを意味します。バッファの読み取りモードでは、制限は、データ量の制限を意味します。バッファから読み取ります。

  • Position −バッファ内のカーソルの現在の位置を指します。バッファの作成時に最初は0に設定されます。つまり、get()およびput(()によって自動的に更新される、読み取りまたは書き込みされる次の要素のインデックスです。 )メソッド。

  • Mark −バッファ内の位置のブックマークをマークします。mark()メソッドが呼び出されると、現在の位置が記録され、reset()が呼び出されると、マークされた位置が復元されます。

バッファタイプ

Java NIOバッファーは、バッファーが処理するデータ型に基づいて、次のバリアントに分類できます。

  • ByteBuffer
  • MappedByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

バッファの重要な方法

すでに述べたように、Bufferはメモリオブジェクトとして機能し、メモリブロックの処理をより便利にする一連のメソッドを提供します。以下はBufferの重要なメソッドです。

  • allocate(int capacity) −このメソッドは、パラメーターとして容量を使用して新しいバッファーを割り当てるために使用されます。Allocateメソッドは、渡された容量が負の整数の場合、IllegalArgumentExceptionをスローします。

  • read() and put() −チャネルのreadメソッドはチャネルからバッファにデータを書き込むために使用され、putはバッファにデータを書き込むために使用されるバッファのメソッドです。

  • flip() −フリップ方式は、バッファのモードを書き込みモードから読み取りモードに切り替えます。また、位置を0に戻し、書き込み時の位置に制限を設定します。

  • write() and get() −チャネルの書き込みメソッドはバッファからチャネルにデータを書き込むために使用され、getはバッファからデータを読み取るために使用されるバッファのメソッドです。

  • rewind() −巻き戻し方法は、位置をゼロに戻し、制限の値を変更しないため、再読み取りが必要な場合に使用されます。

  • clear() and compact() −クリアとコンパクトの両方の方法を使用して、読み取りモードから書き込みモードへのバッファーを作成します。clear() メソッドは位置をゼロにし、制限は容量に等しくなります。このメソッドでは、バッファー内のデータはクリアされず、マーカーのみが再初期化されます。

    一方、 compact() メソッドは、未読データが残っている場合に使用されますが、この場合はバッファーの書き込みモードを使用します。この場合、コンパクトメソッドはすべての未読データをバッファーの先頭にコピーし、最後の未読要素の直後に位置を設定します。limitプロパティは引き続き容量に設定します。

  • mark() and reset() −名前が示すように、マークメソッドを使用してバッファ内の特定の位置をマークし、リセットして位置をマークされた位置に戻します。

次の例は、上記で定義されたメソッドの実装を示しています。

import java.nio.ByteBuffer;
import java.nio.CharBuffer;

public class BufferDemo {
   public static void main (String [] args) {
      //allocate a character type buffer.
      CharBuffer buffer = CharBuffer.allocate(10);
      String text = "bufferDemo";
      System.out.println("Input text: " + text);
      for (int i = 0; i < text.length(); i++) {
         char c = text.charAt(i);
         //put character in buffer.
		 buffer.put(c);
      }
      int buffPos = buffer.position();
      System.out.println("Position after data is written into buffer: " + buffPos);
      buffer.flip();
      System.out.println("Reading buffer contents:");
      while (buffer.hasRemaining()) {
         System.out.println(buffer.get());                   
      }
      //set the position of buffer to 5.
      buffer.position(5);
      //sets this buffer's mark at its position
      buffer.mark();
      //try to change the position
      buffer.position(6);
      //calling reset method to restore to the position we marked.
      //reset() raise InvalidMarkException if either the new position is less
      //than the position marked or merk has not been setted.
      buffer.reset();
      System.out.println("Restored buffer position : " + buffer.position());
   }
}

出力

Input text: bufferDemo
Position after data is written into buffer: 10
Reading buffer contents:
b
u
f
f
e
r
D
e
m
o
Restored buffer position : 5

Java NIOは、チャネルとバッファとの間の複数のトランザクションをサポートしていることがわかっています。したがって、1つ以上のNIOチャネルを調べて、データトランザクションの準備ができているチャネルを特定するために、JavaNIOはセレクタを提供します。

Selectorを使用すると、どのチャネルがデータの書き込みと読み取りの準備ができているかを知るためのスレッドを作成し、その特定のチャネルを処理できます。

静的メソッドを呼び出すことでセレクターインスタンスを取得できます open()セレクターを開いた後、SelectionKeyのインスタンスを返す非ブロッキングモードチャネルを登録する必要があります。

SelectionKeyは基本的に、チャネルで実行できる操作のコレクションです。または、選択キーを使用してチャネルの状態を知ることができたと言えます。

選択キーで表される主な操作またはチャネルの状態は次のとおりです。

  • SelectionKey.OP_CONNECT −サーバーに接続する準備ができているチャネル。

  • SelectionKey.OP_ACCEPT −着信接続を受け入れる準備ができているチャネル。

  • SelectionKey.OP_READ −データ読み取りの準備ができているチャネル。

  • SelectionKey.OP_WRITE −データ書き込みの準備ができているチャネル。

登録後に取得した選択キーには、以下のような重要な方法があります。

  • attach() −この方法は、キーを使用してオブジェクトをアタッチするために使用されます。オブジェクトをチャネルにアタッチする主な目的は、同じチャネルを認識することです。

  • attachment() −このメソッドは、チャネルからアタッチされたオブジェクトを保持するために使用されます。

  • channel() −このメソッドは、特定のキーが作成されるチャネルを取得するために使用されます。

  • selector() −このメソッドは、特定のキーが作成されるセレクターを取得するために使用されます。

  • isValid() −このメソッドは、キーが有効かどうかを天気予報で返します。

  • isReadable() −このメソッドは、ウェザーキーのチャネルが読み取り可能かどうかを示します。

  • isWritable() −このメソッドは、ウェザーキーのチャネルが書き込みの準備ができているかどうかを示します。

  • isAcceptable() −このメソッドは、ウェザーキーのチャネルが着信接続を受け入れる準備ができているかどうかを示します。

  • isConnectable() −このメソッドは、このキーのチャネルがソケット接続操作を終了したか、終了しなかったかをテストします。

  • isAcceptable() −このメソッドは、このキーのチャネルが新しいソケット接続を受け入れる準備ができているかどうかをテストします。

  • interestOps() −このメソッドは、このキーのインタレストセットを取得します。

  • readyOps() −このメソッドは、チャネルの準備ができている操作のセットである準備完了セットを取得します。

静的メソッドを呼び出すことにより、セレクターからチャネルを選択できます select().selectメソッドのselectが次のようにオーバーロードされます-

  • select() −このメソッドは、少なくとも1つのチャネルが登録されているイベントの準備ができるまで、現在のスレッドをブロックします。

  • select(long timeout) −このメソッドはselect()と同じように動作しますが、最大タイムアウトミリ秒(パラメーター)の間スレッドをブロックします。

  • selectNow() −このメソッドはまったくブロックしません。準備ができているチャネルがあれば、すぐに戻ります。

また、selectメソッドを呼び出すブロックされたスレッドを残すために、wakeup() メソッドはセレクターインスタンスから呼び出すことができ、その後select()内で待機しているスレッドはすぐに戻ります。

最後に、を呼び出すことでセレクターを閉じることができます close() セレクターを閉じるとともに、このセレクターに登録されているすべてのSelectionKeyインスタンスも無効にするメソッド。

import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class SelectorDemo {
   public static void main(String[] args) throws IOException {
      String demo_text = "This is a demo String";	
      Selector selector = Selector.open();
      ServerSocketChannel serverSocket = ServerSocketChannel.open();
      serverSocket.bind(new InetSocketAddress("localhost", 5454));
      serverSocket.configureBlocking(false);
      serverSocket.register(selector, SelectionKey.OP_ACCEPT);
      ByteBuffer buffer = ByteBuffer.allocate(256);
      while (true) {
         selector.select();
         Set<SelectionKey> selectedKeys = selector.selectedKeys();
         Iterator<SelectionKey> iter = selectedKeys.iterator();
         while (iter.hasNext()) {
            SelectionKey key = iter.next();
            int interestOps = key.interestOps();
            System.out.println(interestOps);
            if (key.isAcceptable()) {
               SocketChannel client = serverSocket.accept();
               client.configureBlocking(false);
               client.register(selector, SelectionKey.OP_READ);
            }
            if (key.isReadable()) {
               SocketChannel client = (SocketChannel) key.channel();
               client.read(buffer);
               if (new String(buffer.array()).trim().equals(demo_text)) {
                  client.close();
                  System.out.println("Not accepting client messages anymore");
               }
               buffer.flip();
               client.write(buffer);
               buffer.clear();
            }
            iter.remove();
         }
      }
   }
}

Javaでは、NIOパイプは、2つのスレッド間でデータを読み書きするために使用されるコンポーネントです。パイプは主に、データの伝播を担当する2つのチャネルで構成されます。

2つの構成チャネルのうち、1つは主にデータの書き込み用のシンクチャネルと呼ばれ、もう1つはシンクチャネルからデータを読み取ることを主な目的とするソースチャネルです。

データがパイプに書き込まれるのと同じ順序で読み取られる必要があるため、データの書き込みと読み取りの間、データの同期は順番に維持されます。

これはパイプ内のデータの一方向フローであることに注意する必要があります。つまり、データはシンクチャネルでのみ書き込まれ、ソースチャネルからのみ読み取ることができます。

Javaでは、NIOパイプは、主に3つのメソッドを持つ抽象クラスとして定義され、そのうち2つは抽象です。

パイプクラスのメソッド

  • open() −このメソッドは、Pipeのインスタンスを取得するために使用されます。または、このメソッドを呼び出すことによってパイプが作成されたと言えます。

  • sink() −このメソッドは、writeメソッドを呼び出してデータを書き込むために使用されるパイプのシンクチャネルを返します。

  • source() −このメソッドは、readメソッドを呼び出してデータを読み取るために使用されるパイプのソースチャネルを返します。

次の例は、JavaNIOパイプの実装を示しています。

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Pipe;

public class PipeDemo {
   public static void main(String[] args) throws IOException {
      //An instance of Pipe is created
      Pipe pipe = Pipe.open();
      // gets the pipe's sink channel
      Pipe.SinkChannel skChannel = pipe.sink();
      String testData = "Test Data to Check java NIO Channels Pipe.";
      ByteBuffer buffer = ByteBuffer.allocate(512);
      buffer.clear();
      buffer.put(testData.getBytes());
      buffer.flip();
      //write data into sink channel.
      while(buffer.hasRemaining()) {
         skChannel.write(buffer);
      }
      //gets  pipe's source channel
      Pipe.SourceChannel sourceChannel = pipe.source();
      buffer = ByteBuffer.allocate(512);
      //write data into console     
      while(sourceChannel.read(buffer) > 0){
         //limit is set to current position and position is set to zero
         buffer.flip();
         while(buffer.hasRemaining()){
            char ch = (char) buffer.get();
            System.out.print(ch);
         }
         //position is set to zero and limit is set to capacity to clear the buffer.
         buffer.clear();
      }
   }
}

出力

Test Data to Check java NIO Channels Pipe.

テキストファイルがあると仮定します c:/test.txt、次の内容が含まれています。このファイルは、サンプルプログラムの入力として使用されます。

名前が示すように、パスはファイルやファイルシステム内のディレクトリなどのエンティティの特定の場所であり、その特定の場所で検索してアクセスできます。

技術的にはJavaに関して、PathはJavaバージョン7の間にJava NIOファイルパッケージで導入されたインターフェイスであり、特定のファイルシステム内の場所を表します。パスインターフェイスはJava NIOパッケージであるため、修飾名はjavaになります。 .nio.file.Path。

一般に、エンティティのパスには2つのタイプがあります。1つは絶対パスで、もう1つは相対パスです。両方のパスの名前が示すように、絶対パスはルートからそれが配置されているエンティティまでのロケーションアドレスであり、相対パスはロケーションアドレスです。これは他のパスに関連しています。パスは、Windowsの場合は「\」、UNIXオペレーティングシステムの場合は「/」として定義に区切り文字を使用します。

Pathのインスタンスを取得するために、java.nio.file.Pathsクラスの静的メソッドを使用できます。 get()このメソッドは、パス文字列、またはパス文字列から結合されたときにパス文字列を形成する文字列のシーケンスをPathインスタンスに変換します。このメソッドは、渡された引数に不正な文字が含まれている場合にもランタイムInvalidPathExceptionをスローします。

上記のように、絶対パスはルート要素とファイルを見つけるために必要な完全なディレクトリリストを渡すことによって取得されますが、相対パスはベースパスと相対パスを組み合わせることによって取得できますが、両方のパスの取得は次の例で示されます

package com.java.nio;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.file.FileSystem;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
public class PathDemo {
   public static void main(String[] args) throws IOException {
      Path relative = Paths.get("file2.txt");
      System.out.println("Relative path: " + relative);
      Path absolute = relative.toAbsolutePath();
      System.out.println("Absolute path: " + absolute);
   }
}

これまでのところ、パスインターフェイスとは何か、なぜそれが必要なのか、どのようにアクセスできるのかがわかっています。これで、パスインターフェイスが提供する重要なメソッドは何かがわかります。

パスインターフェイスの重要なメソッド

  • getFileName() −このオブジェクトを作成したファイルシステムを返します。

  • getName() −このパスのname要素をPathオブジェクトとして返します。

  • getNameCount() −パス内の名前要素の数を返します。

  • subpath() −このパスの名前要素のサブシーケンスである相対パスを返します。

  • getParent() −親パスを返します。このパスに親がない場合はnullを返します。

  • getRoot() −このパスのルートコンポーネントをPathオブジェクトとして返します。このパスにルートコンポーネントがない場合は、nullを返します。

  • toAbsolutePath() −このパスの絶対パスを表すPathオブジェクトを返します。

  • toRealPath() −既存のファイルの実際のパスを返します。

  • toFile() −このパスを表すFileオブジェクトを返します。

  • normalize() −冗長な名前要素が削除されたこのパスであるパスを返します。

  • compareTo(Path other) − 2つの抽象パスを辞書式に比較します。このメソッドは、引数がこのパスと等しい場合はゼロを返し、このパスが辞書式に引数よりも小さい場合はゼロ未満の値を返し、このパスが辞書式に引数よりも大きい場合はゼロより大きい値を返します。 。

  • endsWith(Path other) −このパスが指定されたパスで終了するかどうかをテストします。指定されたパスにN個の要素があり、ルートコンポーネントがなく、このパスにN個以上の要素がある場合、このパスは、各パスの最後のN個の要素が指定されたパスで終了します。ルートから最も遠い要素から開始して、等しい。

  • endsWith(String other) −このパスが、endsWith(Path)メソッドで指定された方法で、指定されたパス文字列を変換することによって構築されたPathで終了するかどうかをテストします。

次の例は、上記のパスインターフェイスのさまざまな方法を示しています。

package com.java.nio;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.file.FileSystem;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
public class PathDemo {
   public static void main(String[] args) throws IOException {
      Path path = Paths.get("D:/workspace/ContentW/Saurav_CV.docx");
      FileSystem fs =  path.getFileSystem();
      System.out.println(fs.toString());
      System.out.println(path.isAbsolute());
      System.out.println(path.getFileName());
      System.out.println(path.toAbsolutePath().toString());
      System.out.println(path.getRoot());
      System.out.println(path.getParent());
      System.out.println(path.getNameCount());
      System.out.println(path.getName(0));
      System.out.println(path.subpath(0, 2));
      System.out.println(path.toString());
      System.out.println(path.getNameCount());
      Path realPath = path.toRealPath(LinkOption.NOFOLLOW_LINKS);
      System.out.println(realPath.toString());
      String originalPath = "d:\\data\\projects\\a-project\\..\\another-project";
      Path path1 = Paths.get(originalPath);
      Path path2 = path1.normalize();
      System.out.println("path2 = " + path2);
   }
}

Java NIOパッケージは、Filesという名前のもう1つのユーティリティAPIを提供します。これは、基本的に、Pathオブジェクトで主に機能する静的メソッドを使用してファイルとディレクトリを操作するために使用されます。

パスチュートリアルで述べたように、パスインターフェイスはJava7バージョンのファイルパッケージでJavaNIOパッケージに導入されるため、このチュートリアルは同じファイルパッケージを対象としています。

このクラスは、ファイル、ディレクトリ、またはその他の種類のファイルを操作する静的メソッドのみで構成されます。ほとんどの場合、ここで定義されたメソッドは、関連するファイルシステムプロバイダーに委任してファイル操作を実行します。

Filesクラスには、Java docsからも読み取ることができる多くのメソッドが定義されています。このチュートリアルでは、Java NIOFilesクラスのすべてのメソッドの中で重要なメソッドのいくつかを取り上げようとしました。

Filesクラスの重要なメソッド。

以下は、Java NIOFilesクラスで定義されている重要なメソッドです。

  • createFile(Path filePath, FileAttribute attrs) −ファイルクラスは、指定されたパスを使用してファイルを作成するためのこのメソッドを提供します。

package com.java.nio;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class CreateFile {
   public static void main(String[] args) {
      //initialize Path object
      Path path = Paths.get("D:file.txt");
      //create file
      try {
         Path createdFilePath = Files.createFile(path);
         System.out.println("Created a file at : "+createdFilePath);
      } 
      catch (IOException e) {
         e.printStackTrace();
      }
   }
}

出力

Created a file at : D:\data\file.txt
  • copy(InputStream in, Path target, CopyOption… options) −このメソッドは、指定された入力ストリームから指定されたターゲットファイルにすべてのバイトをコピーし、読み取りまたは書き込みされたバイト数をlong value.LinkOptionとして次の値で返すために使用されます。−

    • COPY_ATTRIBUTES −属性を新しいファイルにコピーします(例:last-modified-time属性)。

    • REPLACE_EXISTING −既存のファイルが存在する場合はそれを置き換えます。

    • NOFOLLOW_LINKS −ファイルがシンボリックリンクの場合、リンクのターゲットではなく、リンク自体がコピーされます。

package com.java.nio;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.List;
public class WriteFile {
   public static void main(String[] args) {
      Path sourceFile = Paths.get("D:file.txt");
      Path targetFile = Paths.get("D:fileCopy.txt");
      try {
         Files.copy(sourceFile, targetFile,
         StandardCopyOption.REPLACE_EXISTING);
      }
      catch (IOException ex) {
         System.err.format("I/O Error when copying file");
      }
      Path wiki_path = Paths.get("D:fileCopy.txt");
      Charset charset = Charset.forName("ISO-8859-1");
      try {
         List<String> lines = Files.readAllLines(wiki_path, charset);
         for (String line : lines) {
            System.out.println(line);
         }
      } 
      catch (IOException e) {
         System.out.println(e);
      }
   }	
}

出力

To be or not to be?
  • createDirectories(Path dir, FileAttribute<?>...attrs) −このメソッドは、存在しないすべての親ディレクトリを作成することにより、指定されたパスを使用してディレクトリを作成するために使用されます。

  • delete(Path path) −このメソッドは、指定されたパスからファイルを削除するために使用されます。指定されたパスにファイルが存在しない場合、またはファイルがディレクトリであり、空でなくて削除できない場合は、NoSuchFileExceptionがスローされます。

  • exists(Path path) −このメソッドは、指定されたパスにファイルが存在するかどうかを確認するために使用されます。ファイルが存在する場合はtrueを返し、そうでない場合はfalseを返します。

  • readAllBytes(Path path) −このメソッドは、指定されたパスでファイルからすべてのバイトを読み取り、ファイルから読み取られたバイトを含むバイト配列を返すために使用されます。

package com.java.nio;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class ReadFile {
   public static void main(String[] args) {
      Path wiki_path = Paths.get("D:file.txt");
      Charset charset = Charset.forName("ISO-8859-1");
      try {
         List<String> lines = Files.readAllLines(wiki_path, charset);
         for (String line : lines) {
            System.out.println(line);
         }
      } 
      catch (IOException e) {
         System.out.println(e);
      }
   }	
}

出力

Welcome to file.
  • size(Path path) −このメソッドは、指定されたパスにあるファイルのサイズをバイト単位で取得するために使用されます。

  • write(Path path, byte[] bytes, OpenOption… options) −このメソッドは、指定されたパスにあるファイルにバイトを書き込むために使用されます。

package com.java.nio;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class WriteFile {
   public static void main(String[] args) {
      Path path = Paths.get("D:file.txt");
      String question = "To be or not to be?";
      Charset charset = Charset.forName("ISO-8859-1");
      try {
         Files.write(path, question.getBytes());
         List<String> lines = Files.readAllLines(path, charset);
         for (String line : lines) {
            System.out.println(line);
         }
      } 
      catch (IOException e) {
         System.out.println(e);
      }
   }
}

出力

To be or not to be?

Java NIOは並行性とマルチスレッドをサポートしているため、異なるチャネルを同時に処理できます。したがって、Java NIOパッケージでこれを担当するAPIは、NIOチャネルパッケージで定義されているAsynchronousFileChannelです。 AsynchronousFileChannelの場合は java.nio.channels.AsynchronousFileChannel

AsynchronousFileChannelはNIOのFileChannelと似ていますが、このチャネルでは、スレッドがアクションを開始して要求が完了するまで待機する同期I / O操作とは異なり、ファイル操作を非同期で実行できる点が異なります。したがって、非同期チャネルは安全に使用できます。複数の同時スレッドによる。

非同期では、リクエストはスレッドによってオペレーティングシステムのカーネルに渡され、スレッドは別のジョブを処理し続けます。カーネルのジョブが完了すると、スレッドはその信号を確認し、現在のジョブを中断して処理します。必要に応じてI / Oジョブ。

並行性を実現するために、このチャネルは2つのアプローチを提供します。 java.util.concurrent.Future object その他は、タイプのオブジェクトを操作に渡すことです java.nio.channels.CompletionHandler

例を1つずつ使用して、両方のアプローチを理解します。

  • Future Object −この場合、FutureInterfaceのインスタンスがチャネルから返されます。Futureインターフェイスには get() 他のタスクのさらなる実行を決定するために非同期的に処理される操作のステータスを返すメソッド。タスクを呼び出すことで、タスクが完了したかどうかを確認することもできます。 isDone 方法。

次の例は、Futureオブジェクトを使用して非同期でタスクを実行する方法を示しています。

package com.java.nio;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

public class FutureObject {
   public static void main(String[] args) throws Exception {
      readFile();
   }
   private static void readFile() throws IOException, InterruptedException, ExecutionException {
      String filePath = "D:fileCopy.txt";
      printFileContents(filePath);
      Path path = Paths.get(filePath);		
      AsynchronousFileChannel channel =AsynchronousFileChannel.open(path, StandardOpenOption.READ);
      ByteBuffer buffer = ByteBuffer.allocate(400);
      Future<Integer> result = channel.read(buffer, 0); // position = 0
      while (! result.isDone()) {
         System.out.println("Task of reading file is in progress asynchronously.");
      }
      System.out.println("Reading done: " + result.isDone());
      System.out.println("Bytes read from file: " + result.get()); 
      buffer.flip();
      System.out.print("Buffer contents: ");
      while (buffer.hasRemaining()) {
         System.out.print((char) buffer.get());                
      }
      System.out.println(" ");
      buffer.clear();
      channel.close();
   }
   private static void printFileContents(String path) throws IOException {
      FileReader fr = new FileReader(path);
      BufferedReader br = new BufferedReader(fr);
      String textRead = br.readLine();
      System.out.println("File contents: ");
      while (textRead != null) {
         System.out.println("     " + textRead);
         textRead = br.readLine();
      }
   fr.close();
   br.close();
   }
}

出力

File contents: 
   To be or not to be?
   Task of reading file is in progress asynchronously.
   Task of reading file is in progress asynchronously.
   Reading done: true
   Bytes read from file: 19
   Buffer contents: To be or not to be?
  • Completion Handler

    このアプローチは非常に単純です。これは、CompletionHandlerインターフェイスを使用し、2つのメソッドをオーバーライドするためです。 completed() I / O操作が正常に完了し、その他が正常に完了したときに呼び出されるメソッド failed() I / O操作が失敗した場合に呼び出されるメソッド。この場合、タスクが完了するとハンドラーのみが実行される関数を持つため、非同期I / O操作の結果を消費するためのハンドラーが作成されます。

次の例は、CompletionHandlerを使用して非同期でタスクを実行する方法を示しています。

package com.java.nio;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class CompletionHandlerDemo {
   public static void main (String [] args) throws Exception {
      writeFile();
   }
   private static void writeFile() throws IOException {
      String input = "Content to be written to the file.";
      System.out.println("Input string: " + input);
      byte [] byteArray = input.getBytes();
      ByteBuffer buffer = ByteBuffer.wrap(byteArray);
      Path path = Paths.get("D:fileCopy.txt");
      AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
      CompletionHandler handler = new CompletionHandler() {
         @Override
         public void completed(Object result, Object attachment) {
            System.out.println(attachment + " completed and " + result + " bytes are written.");
         }
         @Override
         public void failed(Throwable exc, Object attachment) {
            System.out.println(attachment + " failed with exception:");
            exc.printStackTrace();
         }
      };
      channel.write(buffer, 0, "Async Task", handler);
      channel.close();
      printFileContents(path.toString());
   }
   private static void printFileContents(String path) throws IOException {
      FileReader fr = new FileReader(path);
      BufferedReader br = new BufferedReader(fr);
      String textRead = br.readLine();
      System.out.println("File contents: ");
      while (textRead != null) {
         System.out.println("     " + textRead);
         textRead = br.readLine();
      }
      fr.close();
      br.close();
   }
}

出力

Input string: Content to be written to the file.
Async Task completed and 34 bytes are written.
File contents: 
Content to be written to the file.

Javaには、すべての文字に対して、JVMによって内部的に処理される明確に定義されたUnicodeコードユニットがあります。したがって、Java NIOパッケージは、主にcharsetとUNICODEのエンコードとデコードに使用されるCharsetという名前の抽象クラスを定義します。

標準の文字セット

Javaでサポートされている文字セットを以下に示します。

  • US-ASCII −7ビットASCII文字。

  • ISO-8859-1 −ISOラテンアルファベット。

  • UTF-8 −これは8ビットのUCS変換フォーマットです。

  • UTF-16BE −これはビッグエンディアンバイトオーダーの16ビットUCS変換フォーマットです。

  • UTF-16LE −これは、リトルエンディアンのバイトオーダーの16ビットUCS変換です。

  • UTF-16 −16ビットUCS変換フォーマット。

Charsetクラスの重要なメソッド

  • forName() −このメソッドは、指定された文字セット名の文字セットオブジェクトを作成します。名前は正規またはエイリアスにすることができます。

  • displayName() −このメソッドは、指定された文字セットの正規名を返します。

  • canEncode() −このメソッドは、指定された文字セットがエンコードをサポートしているかどうかをチェックします。

  • decode() −このメソッドは、指定された文字セットの文字列をUnicode文字セットの文字バッファにデコードします。

  • encode() −このメソッドは、Unicode文字セットの文字バッファを指定された文字セットのバイトバッファにエンコードします。

次の例は、Charsetクラスの重要なメソッドを示しています。

package com.java.nio;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
public class CharsetExample {
   public static void main(String[] args) {
      Charset charset = Charset.forName("US-ASCII");
      System.out.println(charset.displayName());
      System.out.println(charset.canEncode());
      String str = "Demo text for conversion.";
      //convert byte buffer in given charset to char buffer in unicode
      ByteBuffer byteBuffer = ByteBuffer.wrap(str.getBytes());
      CharBuffer charBuffer = charset.decode(byteBuffer);
      //convert char buffer in unicode to byte buffer in given charset
      ByteBuffer newByteBuffer = charset.encode(charBuffer);
      while(newbb.hasRemaining()){
         char ch = (char) newByteBuffer.get();
         System.out.print(ch);
      }
      newByteBuffer.clear();
   }
}

出力

US-ASCII
Demo text for conversion.

Java NIOは同時実行性とマルチスレッドをサポートしているため、複数のファイルで同時に動作する複数のスレッドを同時に処理できますが、場合によっては、ファイルがどのスレッドでも共有されず、アクセスできなくなることが必要になります。

このような要件に対して、NIOはFileLockと呼ばれるAPIを提供します。これは、ファイル全体またはファイルの一部をロックするために使用され、ファイルまたはその一部が共有またはアクセスされないようにします。

このようなロックを提供または適用するには、FileChannelまたはAsynchronousFileChannelを使用する必要があります。これらは2つの方法を提供します。 lock() そして tryLock()この目的のために提供されるロックには2つのタイプがあります-

  • Exclusive Lock −排他ロックは、他のプログラムがいずれかのタイプの重複ロックを取得するのを防ぎます。

  • Shared Lock −共有ロックは、同時に実行されている他のプログラムが重複する排他ロックを取得するのを防ぎますが、重複する共有ロックを取得することはできます。

ロックオーバーファイルを取得するために使用されるメソッド-

  • lock() − FileChannelまたはAsynchronousFileChannelのこのメソッドは、指定されたチャネルに関連付けられたファイルに対する排他ロックを取得します。このメソッドの戻り値の型はFileLockであり、取得したロックを監視するためにさらに使用されます。

  • lock(long position, long size, boolean shared) −このメソッドも、lockメソッドのオーバーロードされたメソッドであり、ファイルの特定の部分をロックするために使用されます。

  • tryLock() −このメソッドは、ファイルロックを返すか、ロックを取得できず、このチャネルのファイルに対して明示的に排他的なロックを取得しようとした場合はnullを返します。

  • tryLock(long position, long size, boolean shared) −このメソッドは、排他的または共有タイプの可能性がある、このチャネルのファイルの指定された領域のロックを取得しようとします。

FileLockクラスのメソッド

  • acquiredBy() −このメソッドは、ファイルロックが取得されたチャネルを返します。

  • position() −このメソッドは、ロックされた領域の最初のバイトのファイル内の位置を返します。ロックされた領域は、実際の基になるファイル内に含まれる必要はなく、オーバーラップする必要もないため、このメソッドによって返される値はファイルの現在のサイズを超える可能性があります。

  • size() −このメソッドは、ロックされた領域のサイズをバイト単位で返します。ロックされた領域は、実際の基になるファイル内に含まれる必要はなく、重複する必要もないため、このメソッドによって返される値は、ファイルの現在のサイズを超える場合があります。

  • isShared() −このメソッドは、ロックが共有されているかどうかを判別するために使用されます。

  • overlaps(long position,long size) −このメソッドは、このロックが指定されたロック範囲とオーバーラップするかどうかを示します。

  • isValid() −このメソッドは、取得したロックが有効かどうかを示します。ロックオブジェクトは、解放されるか、関連するファイルチャネルが閉じられるまで、どちらか早い方まで有効です。

  • release()−取得したロックを解除します。ロックオブジェクトが有効な場合、このメソッドを呼び出すとロックが解除され、オブジェクトが無効になります。このロックオブジェクトが無効な場合、このメソッドを呼び出しても効果はありません。

  • close()−このメソッドはrelease()メソッドを呼び出します。自動リソース管理ブロック構造と組み合わせて使用​​できるように、クラスに追加されました。

ファイルロックを示す例。

次の例では、ファイルにロックを作成してコンテンツを書き込みます

package com.java.nio;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class FileLockExample {
   public static void main(String[] args) throws IOException {
      String input = "Demo text to be written in locked mode.";  
      System.out.println("Input string to the test file is: " + input);  
      ByteBuffer buf = ByteBuffer.wrap(input.getBytes());  
      String fp = "D:file.txt";  
      Path pt = Paths.get(fp);  
      FileChannel channel = FileChannel.open(pt, StandardOpenOption.WRITE,StandardOpenOption.APPEND);  
      channel.position(channel.size() - 1); // position of a cursor at the end of file       
      FileLock lock = channel.lock();   
      System.out.println("The Lock is shared: " + lock.isShared());  
      channel.write(buf);  
      channel.close(); // Releases the Lock  
      System.out.println("Content Writing is complete. Therefore close the channel and release the lock.");  
      PrintFileCreated.print(fp);  
   }  
}
package com.java.nio;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class PrintFileCreated {
   public static void print(String path) throws IOException {  
      FileReader filereader = new FileReader(path);  
      BufferedReader bufferedreader = new BufferedReader(filereader);  
      String tr = bufferedreader.readLine();    
      System.out.println("The Content of testout.txt file is: ");  
      while (tr != null) {      
         System.out.println("    " + tr);  
         tr = bufferedreader.readLine();  
      }  
   filereader.close();  
   bufferedreader.close();  
   }  
}

出力

Input string to the test file is: Demo text to be written in locked mode.
The Lock is shared: false
Content Writing is complete. Therefore close the channel and release the lock.
The Content of testout.txt file is: 
To be or not to be?Demo text to be written in locked mode.