Java-nio-quick-guide

提供:Dev Guides
移動先:案内検索

Java NIO-概要

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

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

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

  • データ、文字セット、および関連するデコーダーとエンコーダーのコンテナーであるバッファー。バイトとUnicode文字の間で変換します。
  • I/O操作を実行できるエンティティへの接続を表すさまざまなタイプのチャネル
  • セレクタと選択キーは、選択可能なチャネルとともに、多重化された非ブロッキングI/O機能を定義します。

Java NIO-環境設定

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

Java SEは、https://java.sun.com/javase/downloads/index_jdk5.jsp [Javaのダウンロード]リンクから無料で入手できます。 そのため、オペレーティングシステムに基づいてバージョンをダウンロードします。

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

Windows 2000/XPのパスのセットアップ

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

  • 「マイコンピュータ」を右クリックして、「プロパティ」を選択します。
  • 「詳細」タブの下の「環境変数」ボタンをクリックします。
  • 「Path」変数を変更して、Java実行可能ファイルへのパスも含まれるようにします。 たとえば、パスが現在「C:\ WINDOWS \ SYSTEM32」に設定されている場合、パスを「C:\ WINDOWS \ SYSTEM32; c:\ Program Files \ java \ jdk \ bin」に変更します。

Windows 95/98/MEのパスのセットアップ

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

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

Linux、UNIX、Solaris、FreeBSDのパスのセットアップ

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

たとえば、_bash_をシェルとして使用する場合、次の行を '.bashrcの最後に追加します。export PATH =/path/to/java:$ PATH'

人気のあるJavaエディター

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

Java NIOとIO

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

Java NIOとJava IOの違いは次のように説明することができます-

  • NIOバッファーの以前の投稿で述べたように、I/O操作と比較してより高速な実行とパフォーマンスを提供するI/O操作用のチャネル指向のデータフロー。また、NIOは従来のI/Oタスクにオペレーティングシステムを使用するため、効率が向上します。
  • NIOとIOの違いの他の側面は、このIOはストリームラインデータフロー、すなわち一度に1バイトを使用し、NIOがバイトの塊であるデータブロックを処理する間、データオブジェクトをバイトに、またはその逆に変換することに依存していることです。
  • Java IOのストリームオブジェクトは単方向ですが、NIOのチャネルは双方向です。つまり、チャネルはデータの読み取りと書き込みの両方に使用できます。
  • IOのストリームラインデータフローでは、データを前後に移動することはできません。ストリームから読み取ったデータを前後に移動する必要がある場合は、最初にバッファにキャッシュする必要があります。NIOの場合、バッファ指向を使用します。キャッシュを必要とせずにデータにアクセスできます。
  • NIO APIはマルチスレッドもサポートしているため、IO操作の実行中に現在のスレッドがブロックされないようにデータを非同期に読み書きできます。これにより、従来のJava IO APIよりも効率的になります。
  • マルチスレッドの概念は、非同期または非ブロック方式でIOイベントの複数のチャネルをリッスンできるJava NIOの Selectors の導入で導入されました。
  • NIOのマルチスレッド化により、ブロックされないため、データが利用可能な場合にのみスレッドの読み取りまたは書き込みが要求され、そうでない場合は他のタスクでスレッドを平均的に使用できますが、従来のJava IOではマルチスレッド化ができないため、これは不可能ですサポートされており、ブロッキングとして機能します。
  • NIOでは、単一のスレッドのみを使用して複数のチャネルを管理できますが、コストは、データの解析がJava IOの場合にブロッキングストリームからデータを読み取る場合よりも多少複雑になる可能性があることです。一度に大量のデータを送信すると、この場合はJava IO APIが最適です。

Java NIO-チャンネル

説明

名前が示すように、チャネルは一方から他方へのデータフローの平均として使用されます。ここでは、Java NIOチャネルはバッファと反対側のエンティティの間で同じように動作します。

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

チャネルの実装

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

  • FileChannel -ファイルからデータを読み取るために、ファイルチャネルを使用します。 ファイルチャネルのオブジェクトは、ファイルオブジェクトを直接作成できないため、ファイルオブジェクトでgetChannel()メソッドを呼び出すことによってのみ作成できます。
  • DatagramChannel -データグラムチャネルは、UDP(User Datagram Protocol)を介してネットワーク経由でデータを読み書きできます。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-ファイルチャネル

説明

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

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

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

  • * getChannel()*-FileInputStream、FileOutputStream、またはRandomAccessFileのいずれかのメソッド。
  • * open()*-デフォルトでチャネルを開くFileチャネルのメソッド。

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

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

次の例では、* 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 finddevguides".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 finddevguides

Java NIO-データグラムチャネル

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

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

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

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

  • * bind(SocketAddress local)*-このメソッドは、データグラムチャネルのソケットを、このメソッドのパラメーターとして提供されるローカルアドレスにバインドするために使用されます。
  • * connect(SocketAddress remote)*-このメソッドは、ソケットをリモートアドレスに接続するために使用されます。
  • * disconnect()*-このメソッドは、リモートアドレスへのソケットを切断するために使用されます。
  • * getRemoteAddress()*-このメソッドは、チャネルのソケットが接続されているリモートロケーションのアドレスを返します。
  • * isConnected()*-すでに述べたように、このメソッドはデータグラムチャネルの接続状態、つまり接続されているかどうかを返します。
  • * open()およびopen(ProtocolFamilyファミリ)*-プロトコルファミリとして表される複数のアドレスのパラメータ化されたオープンメソッドオープンチャネルに対して、オープンメソッドは単一アドレスのデータグラムチャネルを開きます。
  • * read(ByteBuffer dst)*-このメソッドは、データグラムチャネルを介して指定されたバッファからデータを読み取るために使用されます。
  • * receive(ByteBuffer dst)*-このメソッドは、このチャネルを介してデータグラムを受信するために使用されます。
  • * send(ByteBuffer src、SocketAddress target)*-このメソッドは、このチャネルを介してデータグラムを送信するために使用されます。

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

サーバー: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-ソケットチャネル

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 NIO SocketChannelからデータを送信する方法を示しています。

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-ServerSocketチャネル

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 NIO ServerSocketChannelからデータを送信する方法を示しています。

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 NIOは、従来のJavaのIO APIと比較して、データIO操作用に最適化されたAPIであることがわかっているため、Java NIOが提供するもう1つの追加サポートは、複数のバッファーからチャネルへのデータの読み取り/書き込みです。書き込みサポートはScatter and Gatherと呼ばれ、データは読み取りデータの場合は単一チャネルから複数のバッファーに分散され、データは書き込みデータの場合は複数のバッファーから単一チャネルに収集されます。

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

ScatteringByteChannel

複数のチャネルからの読み取り-これでは、単一のチャネルから複数のバッファにデータを読み取ります。このため、複数のバッファが割り当てられ、バッファタイプの配列に追加されます。配列内でバッファが発生する順序でチャネルからデータを書き込むメソッド。バッファがいっぱいになると、チャネルは次のバッファを満たすために移動します。

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

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 NIOは、従来のJavaのIO APIと比較して、データIO操作用に最適化されたAPIであることがわかっているため、Java NIOが提供するもう1つの追加サポートは、複数のバッファーからチャネルへのデータの読み取り/書き込みです。書き込みサポートはScatter and Gatherと呼ばれ、データは読み取りデータの場合は単一チャネルから複数のバッファーに分散され、データは書き込みデータの場合は複数のバッファーから単一チャネルに収集されます。

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

GatheringByteChannel

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

次の例は、Java NIOでのデータ収集の実行方法を示しています

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-バッファー

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

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

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

Java NIOバッファを定義する主なパラメータは、次のように定義できます-

  • 容量-バッファに保存できるデータ/バイトの最大量。バッファの容量は変更できません。バッファがいっぱいになると、書き込む前にクリアする必要があります。
  • 制限-制限には、バッファのモードごとに意味があります。 バッファ制限の書き込みモードでは、バッファに書き込むことができる最大データを意味する容量に等しくなります。バッファ制限の読み取りモードでは、バッファから読み取ることができるデータ量の制限を意味します。
  • 位置-バッファ内のカーソルの現在の位置を指します。バッファの作成時に最初に0に設定されます。つまり、get()によって自動的に更新される、読み取りまたは書き込みが行われる次の要素のインデックスです。およびput()メソッド。
  • マーク-バッファ内の位置のブックマークをマークします。mark()メソッドが呼び出されると、現在の位置が記録され、reset()が呼び出されると、マークされた位置が復元されます。

バッファタイプ

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

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

バッファの重要な方法

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

  • * allocate(int capacity)*-このメソッドは、パラメータとして容量を持つ新しいバッファを割り当てるために使用されます。Allocateメソッドは、渡された容量が負の整数である場合にIllegalArgumentExceptionをスローします。
  • * read()およびput()*-チャネルの読み取りメソッドは、チャネルからバッファにデータを書き込むために使用されますが、putは、バッファにデータを書き込むために使用されるバッファのメソッドです。
  • * flip()*-flipメソッドは、Bufferのモードを書き込みモードから読み取りモードに切り替えます。また、位置を0に戻し、書き込み時の位置の制限を設定します。
  • * write()およびget()*-チャネルの書き込みメソッドは、バッファからチャネルにデータを書き込むために使用されますが、getは、バッファからデータを読み取るために使用されるバッファのメソッドです。
  • * rewind()*-位置をゼロに戻し、limitの値を変更しないため、再読み込みが必要な場合にrewindメソッドが使用されます。
  • * clear()およびcompact()-読み取りモードから書き込みモードへのバッファーの作成には、両方のメソッドを使用してclearおよびcompactを使用します。 clear()メソッドは、位置をゼロにし、このメソッドでの容量に等しい制限を行います。バッファーはクリアされず、マーカーのみが再初期化されます。 +一方、 compact()*メソッドは、未読データが残っている場合に使用し、この場合もバッファの書き込みモードを使用します。この場合、compactメソッドはすべての未読データをバッファの先頭にコピーし、最後の未読要素。limitプロパティはまだcapacityに設定されています。
  • * mark()およびreset()*-名前が示すように、markメソッドを使用して、バッファー内の特定の位置をマークし、リセット位置をマークされた位置に戻します。

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

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-セレクター

私たちが知っているように、Java NIOはチャネルとバッファからの複数のトランザクションをサポートしているため、1つ以上のNIOチャネルを調べ、どのチャネルがデータトランザクションの準備ができているか、つまりJava NIOがセレクタを読み書きするかを判断します。

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()*-このメソッドは、少なくとも1つのチャネルが登録されたイベントの準備ができるまで、現在のスレッドをブロックします。
  • * select(long timeout)*-このメソッドはselect()と同じですが、最大タイムアウトミリ秒(パラメーター)スレッドをブロックします。
  • * selectNow()*-このメソッドはまったくブロックせず、準備ができているチャンネルをすぐに返します。

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

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

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-パイプ

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

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

データの書き込みおよび読み取り中は、データがパイプに書き込まれるのと同じ順序でデータを読み取る必要があるため、データの同期は順序どおりに保持されます。

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

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

Pipeクラスのメソッド

  • * open()*-このメソッドはPipeのインスタンスを取得するために使用されるか、このメソッドを呼び出すことでパイプが作成されたと言うことができます。
  • * sink()*-このメソッドは、書き込みメソッドを呼び出すことでデータを書き込むために使用されるパイプのシンクチャネルを返します。
  • * source()*-このメソッドは、そのreadメソッドを呼び出すことでデータを読み取るために使用されるPipeのソースチャネルを返します。

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

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 NIO-パス

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

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

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

Pathのインスタンスを取得するには、java.nio.file.Pathsクラスの静的メソッド* get()*を使用できます。このメソッドは、パス文字列、またはパス文字列から結合されたときに文字列のシーケンスを変換します。パスインスタンス。このメソッドは、渡された引数に無効な文字が含まれている場合、ランタイム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);
   }
}

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

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

  • * getFileName()*-このオブジェクトを作成したファイルシステムを返します。
  • * getName()*-このパスの名前要素をPathオブジェクトとして返します。
  • * getNameCount()*-パス内の名前要素の数を返します。
  • * subpath()*-このパスの名前要素のサブシーケンスである相対パスを返します。
  • * getParent()*-親パスを返します。このパスに親がない場合はnullを返します。
  • * getRoot()*-このパスのルートコンポーネントをPathオブジェクトとして返します。このパスにルートコンポーネントがない場合はnullを返します。
  • * toAbsolutePath()*-このパスの絶対パスを表すPathオブジェクトを返します。
  • * toRealPath()*-既存のファイルの実際のパスを返します。
  • * toFile()*-このパスを表すFileオブジェクトを返します。
  • * normalize()*-冗長な名前要素が削除されたこのパスであるパスを返します。
  • * compareTo(Path other)*-2つの抽象パスを辞書式に比較します。引数がこのパスに等しい場合、このメソッドは0を返します。このパスが辞書式に引数よりも小さい場合は0未満の値、またはpathは、引数より辞書的に大きくなっています。
  • * endsWith(Path other)*-このパスが指定されたパスで終了するかどうかをテストします。指定されたパスにN個の要素があり、ルートコンポーネントがなく、このパスにN個以上の要素がある場合、このパスは指定されたパスで終了しますルートから最も遠い要素から始まる各パスの最後のN個の要素は等しい。
  • * endsWith(String other)*-このパスが、endsWith(Path)メソッドで指定された方法で、指定されたパス文字列の変換によって構築された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-ファイル

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

Pathチュートリアルで述べたように、PathインターフェースはJava 7バージョンのファイルパッケージでJava NIOパッケージに導入されるため、このチュートリアルは同じFileパッケージ用です。

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

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

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

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

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

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値として返します。 −
  • COPY_ATTRIBUTES -属性を新しいファイルにコピーします。 最終変更時刻属性。
  • 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)*-このメソッドは、指定されたパスにファイルが存在するかどうかを確認するために使用されます。
  • * 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-AsynchronousFileChannel

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

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

非同期では、要求はスレッドによってオペレーティングシステムのカーネルに渡され、スレッドが別のジョブの処理を続行している間に実行されます。カーネルのジョブが完了すると、スレッドに信号を送り、スレッドは信号に応答して現在のジョブを中断し、処理します必要に応じてI/Oジョブ。

並行性を実現するために、このチャネルは、* java.util.concurrent.Futureオブジェクト*を返す方法と、 java.nio.channels.CompletionHandler 型のオブジェクトを操作に渡す方法の2つの方法を提供します。

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

  • Future Object -これには、チャネルからFuture Interfaceのインスタンスが返されます。FutureInterfaceには、他のタスクのさらなる実行に基づいて非同期的に処理される操作のステータスを返す* 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?
  • 完了ハンドラ- +このアプローチは非常に簡単です。CompletionHandlerインターフェースを使用し、I/O操作が正常に完了したときに呼び出される* completed()メソッドと、次の場合に呼び出される failed()*メソッドの2つのメソッドをオーバーライドします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 NIO-CharSet

Javaには、すべての文字に対して、JVMによって内部的に処理される適切に定義されたUnicodeコード単位があります。したがって、Java NIOパッケージは、主に文字セットと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-FileLock

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

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

このようなロックを提供または適用するには、FileChannelまたはAsynchronousFileChannelを使用する必要があります。これは、この目的のために2つのメソッド* lock()*およびtryLock()を提供します。

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

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

  • * lock()*-FileChannelまたはAsynchronousFileChannelのこのメソッドは、指定されたチャネルに関連付けられたファイルの排他ロックを取得します。このメソッドの戻り値の型は、取得したロックの監視にさらに使用されるFileLockです。
  • * lock(long position、long size、boolean shared)*-このメソッドもロックメソッドのオーバーロードメソッドであり、ファイルの特定の部分をロックするために使用されます。
  • * tryLock()*-ロックを取得できなかった場合、このメソッドはFileLockまたは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.