Java NIO - คู่มือฉบับย่อ
แพ็คเกจ Java.nio ถูกนำมาใช้ใน java 1.4 ในทางตรงกันข้ามกับ java I / O ใน java NIO จะมีการนำเสนอบัฟเฟอร์และช่องทางข้อมูลสำหรับการดำเนินการ I / O ซึ่งส่งผลให้การดำเนินการเร็วขึ้นและประสิทธิภาพที่ดี
นอกจากนี้ NIO API ยังมีตัวเลือกที่แนะนำฟังก์ชันการฟังหลายช่องสัญญาณสำหรับเหตุการณ์ IO ในแบบอะซิงโครนัสหรือไม่ปิดกั้นใน NIO กิจกรรม I / O ที่ใช้เวลามากที่สุดรวมถึงการเติมและระบายบัฟเฟอร์ไปยังระบบปฏิบัติการซึ่งจะเพิ่มความเร็ว
นามธรรมกลางของ NIO API มีดังต่อไปนี้ -
บัฟเฟอร์ซึ่งเป็นที่เก็บข้อมูลชุดอักขระและตัวถอดรหัสและตัวเข้ารหัสที่เกี่ยวข้องซึ่งแปลระหว่างอักขระไบต์และอักขระ Unicode
แชนเนลประเภทต่างๆซึ่งแสดงถึงการเชื่อมต่อกับเอนทิตีที่สามารถดำเนินการ I / O ได้
ตัวเลือกและปุ่มการเลือกซึ่งร่วมกับแชนเนลที่เลือกได้จะกำหนดสิ่งอำนวยความสะดวก I / O แบบมัลติเพล็กซ์และไม่ปิดกั้น
ส่วนนี้จะแนะนำคุณเกี่ยวกับวิธีดาวน์โหลดและตั้งค่า Java บนเครื่องของคุณ โปรดทำตามขั้นตอนต่อไปนี้เพื่อตั้งค่าสภาพแวดล้อม
Java SE เป็นอิสระที่มีอยู่จากการเชื่อมโยงดาวน์โหลด Java คุณจึงดาวน์โหลดเวอร์ชันที่อิงตามระบบปฏิบัติการของคุณ
ทำตามคำแนะนำเพื่อดาวน์โหลด java และเรียกใช้ไฟล์ .exeเพื่อติดตั้ง Java บนเครื่องของคุณ เมื่อคุณติดตั้ง Java บนเครื่องของคุณคุณจะต้องตั้งค่าตัวแปรสภาพแวดล้อมเพื่อชี้ไปที่ไดเร็กทอรีการติดตั้งที่ถูกต้อง -
การตั้งค่าเส้นทางสำหรับ windows 2000 / XP
สมมติว่าคุณติดตั้ง Java ในไดเร็กทอรีc: \ Program Files \ java \ jdk -
คลิกขวาที่ 'My Computer' และเลือก 'Properties'
คลิกที่ปุ่ม "ตัวแปรสภาพแวดล้อม" ใต้แท็บ "ขั้นสูง"
ตอนนี้เปลี่ยนตัวแปร 'Path' เพื่อให้มีพา ธ ไปยังไฟล์ปฏิบัติการ Java ตัวอย่างหากเส้นทางถูกตั้งค่าเป็น 'C: \ WINDOWS \ SYSTEM32' ให้เปลี่ยนเส้นทางของคุณเป็นอ่าน 'C: \ WINDOWS \ SYSTEM32; c: \ Program Files \ 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: export PATH = / path / to / java: $ PATH'
บรรณาธิการ Java ยอดนิยม
ในการเขียนโปรแกรม Java ของคุณคุณจะต้องมีโปรแกรมแก้ไขข้อความ มี IDE ที่ซับซ้อนมากขึ้นในตลาด แต่ในตอนนี้คุณสามารถพิจารณาข้อใดข้อหนึ่งต่อไปนี้ -
Notepad - บนเครื่อง Windows คุณสามารถใช้โปรแกรมแก้ไขข้อความง่ายๆเช่น Notepad (แนะนำสำหรับบทช่วยสอนนี้), TextPad
Netbeans - เป็น Java IDE ที่เป็นโอเพ่นซอร์สและฟรีซึ่งสามารถดาวน์โหลดได้จาก http://www.netbeans.org/index.html.
Eclipse - ยังเป็น java IDE ที่พัฒนาโดยชุมชนโอเพนซอร์ส eclipse และสามารถดาวน์โหลดได้จาก https://www.eclipse.org/.
ดังที่เราทราบว่า java NIO ได้รับการแนะนำเพื่อความก้าวหน้าของ java IO API แบบเดิมการปรับปรุงหลักที่ทำให้ NIO มีประสิทธิภาพมากกว่า IO คือรูปแบบการไหลของข้อมูลช่องทางที่ใช้ใน NIO และการใช้ระบบปฏิบัติการสำหรับงาน IO ทั่วไป
ความแตกต่างระหว่าง Java NIO และ Java IO สามารถอธิบายได้ดังต่อไปนี้ -
ตามที่กล่าวไว้ในโพสต์ก่อนหน้าในบัฟเฟอร์ NIO และการไหลของข้อมูลที่มุ่งเน้นช่องสัญญาณสำหรับการดำเนินการ I / O ซึ่งให้การดำเนินการที่รวดเร็วขึ้นและประสิทธิภาพที่ดีขึ้นเมื่อเทียบกับ IO นอกจากนี้ NIO ยังใช้ระบบปฏิบัติการสำหรับงาน I / O ทั่วไปซึ่งทำให้มีประสิทธิภาพมากขึ้นอีกครั้ง
ความแตกต่างอื่น ๆ ระหว่าง NIO และ IO คือ IO นี้ใช้การไหลของข้อมูลสตรีมไลน์เช่นครั้งละหนึ่งไบต์และอาศัยการแปลงอ็อบเจ็กต์ข้อมูลเป็นไบต์และในทางกลับกันในขณะที่ NIO เกี่ยวข้องกับบล็อกข้อมูลซึ่งเป็นกลุ่มไบต์
ในอ็อบเจ็กต์สตรีม java IO เป็นแบบทิศทางเดียวในขณะที่ช่อง NIO เป็นแบบสองทิศทางหมายความว่าช่องสัญญาณสามารถใช้สำหรับทั้งการอ่านและการเขียนข้อมูล
การไหลของข้อมูลที่คล่องตัวใน IO ไม่อนุญาตให้ย้ายไปมาและย้อนกลับในข้อมูลหากกรณีจำเป็นต้องย้ายไปมาและย้อนกลับในข้อมูลที่อ่านจากสตรีมจำเป็นต้องแคชข้อมูลในบัฟเฟอร์ก่อนในขณะที่ NIO เราใช้บัฟเฟอร์เชิง ซึ่งช่วยให้สามารถเข้าถึงข้อมูลไปมาได้โดยไม่ต้องใช้แคช
NIO API ยังรองรับ multi threading เพื่อให้สามารถอ่านและเขียนข้อมูลแบบอะซิงโครนัสได้เช่นในขณะที่ดำเนินการ IO เธรดปัจจุบันจะไม่ถูกบล็อกสิ่งนี้ทำให้มีประสิทธิภาพมากกว่า java IO API ทั่วไปอีกครั้ง
มีการนำแนวคิดของเธรดหลายแบบมาใช้ด้วยการแนะนำ Selectors ใน java NIO ซึ่งอนุญาตให้ฟังหลายช่องสัญญาณสำหรับเหตุการณ์ IO ในแบบอะซิงโครนัสหรือไม่ปิดกั้น
เธรดหลายเธรดใน NIO ทำให้ไม่ใช่การปิดกั้นซึ่งหมายความว่าเธรดถูกร้องขอให้อ่านหรือเขียนเฉพาะเมื่อมีข้อมูลเท่านั้นมิฉะนั้นเธรดจะสามารถใช้ในงานอื่นได้ในเวลาเฉลี่ย แต่จะเป็นไปไม่ได้ในกรณีของ java IO แบบเดิมเนื่องจากไม่มีเธรดแบบมัลติ ได้รับการสนับสนุนซึ่งทำให้เป็นการปิดกั้น
NIO อนุญาตให้จัดการหลายช่องทางโดยใช้เธรดเดียวเท่านั้น แต่ค่าใช้จ่ายคือการแยกวิเคราะห์ข้อมูลอาจค่อนข้างซับซ้อนกว่าเมื่ออ่านข้อมูลจากสตรีมการบล็อกในกรณีของ java IO ดังนั้นในกรณีที่ต้องการการเชื่อมต่อน้อยลงด้วยแบนด์วิดท์ที่สูงมาก ด้วยการส่งข้อมูลครั้งละมาก ๆ มากกว่าในกรณีนี้ java IO API อาจเหมาะสมที่สุด
คำอธิบาย
ตามชื่อแนะนำช่องถูกใช้เป็นค่าเฉลี่ยของการไหลของข้อมูลจากปลายด้านหนึ่งไปยังอีกด้านหนึ่งที่นี่ในช่อง java NIO จะทำหน้าที่เหมือนกันระหว่างบัฟเฟอร์และเอนทิตีที่ปลายอีกด้านหนึ่งในคำอื่น ๆ ช่องใช้เพื่ออ่านข้อมูลไปยังบัฟเฟอร์และเขียนข้อมูลจากบัฟเฟอร์
แตกต่างจากสตรีมที่ใช้ในแชนเนล Java IO ทั่วไปคือสองทางคือสามารถอ่านและเขียนได้ Java NIO channel รองรับการไหลของข้อมูลแบบอะซิงโครนัสทั้งในโหมดบล็อกและไม่บล็อก
การใช้งานช่อง
ช่อง Java NIO ถูกนำไปใช้ในคลาสต่อไปนี้เป็นหลัก -
FileChannel- ในการอ่านข้อมูลจากไฟล์เราใช้ช่องไฟล์ ออบเจ็กต์ของช่องไฟล์สามารถสร้างได้โดยการเรียกเมธอด getChannel () บนอ็อบเจ็กต์ไฟล์เท่านั้นเนื่องจากเราไม่สามารถสร้างอ็อบเจ็กต์ไฟล์ได้โดยตรง
DatagramChannel - ช่องดาต้าแกรมสามารถอ่านและเขียนข้อมูลผ่านเครือข่ายผ่าน UDP (User Datagram Protocol) วัตถุของ DataGramchannel สามารถสร้างได้โดยใช้วิธีการของโรงงาน
SocketChannel- ช่อง SocketChannel สามารถอ่านและเขียนข้อมูลผ่านเครือข่ายผ่าน TCP (Transmission Control Protocol) นอกจากนี้ยังใช้วิธีการของโรงงานในการสร้างวัตถุใหม่
ServerSocketChannel- ServerSocketChannel อ่านและเขียนข้อมูลผ่านการเชื่อมต่อ 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!
คำอธิบาย
ดังที่ได้กล่าวไปแล้วการใช้งาน FileChannel ของ Java NIO channel ถูกนำมาใช้เพื่อเข้าถึงคุณสมบัติข้อมูลเมตาของไฟล์รวมถึงการสร้างการปรับเปลี่ยนขนาดและอื่น ๆ นอกจากนี้ File Channels ยังมีมัลติเธรดซึ่งทำให้ Java NIO มีประสิทธิภาพมากกว่า Java IO อีกครั้ง
โดยทั่วไปเราสามารถพูดได้ว่า FileChannel เป็นช่องทางที่เชื่อมต่อกับไฟล์ที่คุณสามารถอ่านข้อมูลจากไฟล์และเขียนข้อมูลลงในไฟล์ได้ลักษณะสำคัญอื่น ๆ ของ FileChannel คือไม่สามารถตั้งค่าเป็นโหมดไม่ปิดกั้นได้ และทำงานในโหมดบล็อกเสมอ
เราไม่สามารถรับออบเจ็กต์ช่องไฟล์โดยตรงได้วัตถุของช่องไฟล์จะได้รับโดย -
getChannel() - วิธีการใด ๆ ใน FileInputStream, FileOutputStream หรือ RandomAccessFile
open() - วิธีการของ File channel ซึ่งโดยค่าเริ่มต้นจะเปิดช่อง
ประเภทอ็อบเจ็กต์ของ File channel ขึ้นอยู่กับประเภทของคลาสที่เรียกจากการสร้างอ็อบเจ็กต์เช่นถ้าอ็อบเจ็กต์ถูกสร้างโดยเรียกเมธอด getchannel ของ FileInputStream จากนั้น File channel จะเปิดขึ้นสำหรับการอ่านและจะโยน 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 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 Datagram ใช้เป็นแชนเนลที่สามารถส่งและรับแพ็กเก็ต UDP ผ่านโปรโตคอลที่เชื่อมต่อน้อยลงโดยค่าเริ่มต้นช่องดาตาแกรมจะบล็อกในขณะที่สามารถใช้ในโหมดที่ไม่ปิดกั้นเพื่อที่จะทำให้มันไม่ปิดกั้นเราสามารถใช้การกำหนดค่าบล็อก ( false) ช่องทาง DataGram สามารถเปิดได้โดยเรียกหนึ่งในวิธีการแบบคงที่ที่มีชื่อว่า open() ซึ่งสามารถใช้ที่อยู่ IP เป็นพารามิเตอร์เพื่อให้สามารถใช้สำหรับการหล่อหลายตัว
ช่องดาต้าแกรมเหมือนกันของ FileChannel ไม่ได้เชื่อมต่อตามค่าเริ่มต้นเพื่อให้เชื่อมต่อได้เราต้องเรียกวิธีการเชื่อมต่อ () อย่างชัดเจนอย่างไรก็ตามไม่จำเป็นต้องเชื่อมต่อช่องดาตาแกรมเพื่อให้ใช้วิธีการส่งและรับในขณะที่ต้องเชื่อมต่อ ในการใช้วิธีการอ่านและเขียนเนื่องจากวิธีการเหล่านั้นไม่ยอมรับหรือส่งคืนที่อยู่ของซ็อกเก็ต
เราสามารถตรวจสอบสถานะการเชื่อมต่อของช่องดาตาแกรมได้โดยเรียกมัน 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 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 ซ็อกเก็ตแชนเนลเป็นแชนเนลประเภทที่เลือกได้ซึ่งหมายความว่าสามารถมัลติเพล็กซ์โดยใช้ตัวเลือกซึ่งใช้สำหรับซ็อกเก็ตการเชื่อมต่อกระแสข้อมูลที่มุ่งเน้นกระแสข้อมูลซ็อกเก็ตแชนเนลสามารถสร้างได้โดยการเรียกใช้สแตติก open() วิธีการจัดเตรียมซ็อกเก็ตที่มีอยู่แล้วใด ๆ ไม่ปรากฏอยู่แล้วช่องซ็อกเก็ตถูกสร้างขึ้นโดยการเรียกใช้วิธีการเปิด แต่ยังไม่ได้เชื่อมต่อเพื่อเชื่อมต่อช่องซ็อกเก็ต connect() จะเรียกวิธีการจุดหนึ่งที่จะกล่าวถึงในที่นี้คือหากไม่ได้เชื่อมต่อช่องสัญญาณและพยายามดำเนินการ I / O ใด ๆ แล้ว NotYetConnectedException จะถูกโยนทิ้งโดยช่องนี้ดังนั้นต้องตรวจสอบให้แน่ใจว่ามีการเชื่อมต่อช่องสัญญาณก่อนดำเนินการ IO ใด ๆ เมื่อเชื่อมต่อช่องแล้วจะยังคงเชื่อมต่ออยู่จนกว่าจะปิดสถานะของช่องซ็อกเก็ตอาจถูกกำหนดโดยการเรียกใช้ isConnected วิธี.
การเชื่อมต่อของช่องซ็อกเก็ตสามารถทำได้โดยการเรียกใช้ finishConnect() วิธีการไม่ว่าการดำเนินการเชื่อมต่อจะอยู่ระหว่างดำเนินการหรือไม่อาจถูกกำหนดโดยการเรียกใช้เมธอด isConnectionPending โดยค่าเริ่มต้นของช่องซ็อกเก็ตรองรับการเชื่อมต่อแบบไม่ปิดกั้นนอกจากนี้ยังรองรับการปิดระบบแบบอะซิงโครนัสซึ่งคล้ายกับการปิดแบบอะซิงโครนัสที่ระบุในคลาส Channel
ช่องซ็อกเก็ตปลอดภัยสำหรับการใช้งานโดยเธรดหลายเธรดพร้อมกัน สนับสนุนการอ่านและการเขียนพร้อมกันแม้ว่าเธรดส่วนใหญ่อาจกำลังอ่านอยู่และเธรดส่วนใหญ่อาจกำลังเขียนในช่วงเวลาใดเวลาหนึ่ง เมธอด connect และ finishConnect จะซิงโครไนซ์ซึ่งกันและกันและความพยายามที่จะเริ่มต้นการดำเนินการอ่านหรือเขียนในขณะที่กำลังดำเนินการเรียกใช้วิธีใดวิธีหนึ่งเหล่านี้จะบล็อกจนกว่าการเรียกใช้จะเสร็จสมบูรณ์
วิธีการสำคัญของ Socket channel
bind(SocketAddress local) - วิธีนี้ใช้เพื่อผูกช่องซ็อกเก็ตกับโลคัลแอดเดรสซึ่งจัดเตรียมไว้เป็นพารามิเตอร์ของเมธอดนี้
connect(SocketAddress remote) - วิธีนี้ใช้เพื่อเชื่อมต่อซ็อกเก็ตกับที่อยู่ระยะไกล
finishConnect() - วิธีนี้ใช้เพื่อเสร็จสิ้นขั้นตอนการเชื่อมต่อช่องซ็อกเก็ต
getRemoteAddress() - วิธีนี้จะส่งกลับที่อยู่ของตำแหน่งระยะไกลที่เชื่อมต่อซ็อกเก็ตของช่อง
isConnected() - ดังที่ได้กล่าวไปแล้ววิธีนี้จะคืนสถานะการเชื่อมต่อของช่องซ็อกเก็ตเช่นเชื่อมต่อหรือไม่
open() and open((SocketAddress remote) - ใช้วิธีการเปิดเพื่อเปิดช่องซ็อกเก็ตโดยไม่มีที่อยู่ที่ระบุในขณะที่วิธีการเปิดที่กำหนดพารามิเตอร์จะเปิดช่องทางสำหรับที่อยู่ระยะไกลที่ระบุและเชื่อมต่อด้วยวิธีการอำนวยความสะดวกนี้ทำงานเหมือนกับการเรียกใช้เมธอด open () โดยเรียกใช้วิธีการเชื่อมต่อเมื่อผลลัพธ์ ซ็อกเก็ตช่องส่งผ่านระยะไกลแล้วส่งคืนช่องนั้น
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 เป็นแชนเนลประเภทที่เลือกได้อีกครั้งซึ่งใช้สำหรับซ็อกเก็ตการเชื่อมต่อกระแสข้อมูลที่มุ่งเน้นการสตรีมแชนเนลซ็อกเก็ตเซิร์ฟเวอร์สามารถสร้างได้โดยการเรียกใช้สแตติก open() วิธีการจัดเตรียมซ็อกเก็ตที่มีอยู่แล้วใด ๆ ไม่มีอยู่แล้วช่องเสียบเซิร์ฟเวอร์ถูกสร้างขึ้นโดยการเรียกใช้วิธีการเปิด แต่ยังไม่ถูกผูกไว้เพื่อผูกช่องซ็อกเก็ต bind() จะเรียกวิธีการ
จุดหนึ่งที่จะกล่าวถึงในที่นี้คือหากช่องสัญญาณไม่ถูกผูกไว้และพยายามดำเนินการ I / O ใด ๆ แล้ว NotYetBoundException จะถูกโยนทิ้งโดยแชนเนลนี้ดังนั้นเราต้องแน่ใจว่าช่องถูกล้อมรอบก่อนที่จะดำเนินการ IO ใด ๆ
การเชื่อมต่อขาเข้าสำหรับช่องซ็อกเก็ตเซิร์ฟเวอร์จะรับฟังโดยการเรียกใช้เมธอด ServerSocketChannel.accept () เมื่อวิธีการยอมรับ () ส่งคืนจะส่งคืน SocketChannel พร้อมการเชื่อมต่อขาเข้า ดังนั้นวิธีการยอมรับ () จะบล็อกจนกว่าจะมีการเชื่อมต่อขาเข้าหากช่องสัญญาณอยู่ในโหมดไม่ปิดกั้นวิธีการยอมรับจะส่งคืนค่าว่างทันทีหากไม่มีการเชื่อมต่อที่รอดำเนินการ มิฉะนั้นจะบล็อกโดยไม่มีกำหนดจนกว่าจะมีการเชื่อมต่อใหม่หรือเกิดข้อผิดพลาด I / O
ซ็อกเก็ตของช่องใหม่ในตอนแรกไม่ถูกผูกไว้ ต้องถูกผูกไว้กับแอดเดรสที่ระบุผ่านวิธีการผูกของซ็อกเก็ตก่อนจึงจะยอมรับการเชื่อมต่อได้นอกจากนี้ยังสร้างช่องสัญญาณใหม่โดยเรียกใช้เมธอด openServerSocketChannel ของอ็อบเจ็กต์ SelectorProvider ดีฟอลต์ทั้งระบบ
เช่นเดียวกับช่องซ็อกเก็ตเซิร์ฟเวอร์ซ็อกเก็ตช่องสัญญาณสามารถอ่านข้อมูลโดยใช้ read()วิธีการประการแรกบัฟเฟอร์ถูกจัดสรร ข้อมูลที่อ่านจาก ServerSocketChannel จะถูกเก็บไว้ในบัฟเฟอร์ประการที่สองเราเรียกว่าเมธอด ServerSocketChannel.read () และอ่านข้อมูลจาก ServerSocketChannel ลงในบัฟเฟอร์ ค่าจำนวนเต็มของเมธอด read () จะส่งกลับจำนวนไบต์ที่เขียนลงในบัฟเฟอร์
ข้อมูลในทำนองเดียวกันสามารถเขียนไปยังช่องซ็อกเก็ตเซิร์ฟเวอร์โดยใช้ write() วิธีการใช้บัฟเฟอร์เป็นพารามิเตอร์โดยทั่วไปจะใช้วิธีการเขียนใน while loop เนื่องจากจำเป็นต้องทำซ้ำเมธอด write () จนกว่าบัฟเฟอร์จะไม่มีไบต์เพิ่มเติมให้เขียน
วิธีการสำคัญของ Socket channel
bind(SocketAddress local) - วิธีนี้ใช้เพื่อผูกช่องซ็อกเก็ตกับโลคัลแอดเดรสซึ่งจัดเตรียมไว้เป็นพารามิเตอร์ของเมธอดนี้
accept() - วิธีนี้ใช้เพื่อยอมรับการเชื่อมต่อกับซ็อกเก็ตของช่องนี้
connect(SocketAddress remote) - วิธีนี้ใช้เพื่อเชื่อมต่อซ็อกเก็ตกับที่อยู่ระยะไกล
finishConnect() - วิธีนี้ใช้เพื่อเสร็จสิ้นขั้นตอนการเชื่อมต่อช่องซ็อกเก็ต
getRemoteAddress() - วิธีนี้จะส่งกลับที่อยู่ของตำแหน่งระยะไกลที่เชื่อมต่อซ็อกเก็ตของช่อง
isConnected() - ดังที่ได้กล่าวไปแล้ววิธีนี้จะคืนสถานะการเชื่อมต่อของช่องซ็อกเก็ตเช่นเชื่อมต่อหรือไม่
open() - ใช้วิธีการเปิดเพื่อเปิดช่องซ็อกเก็ตโดยไม่มีที่อยู่ที่ระบุวิธีการอำนวยความสะดวกนี้ทำงานเหมือนกับการเรียกใช้เมธอด open () เรียกใช้วิธีการเชื่อมต่อกับช่องสัญญาณซ็อกเก็ตเซิร์ฟเวอร์ที่เป็นผลลัพธ์ส่งผ่านระยะไกลแล้วส่งคืนช่องนั้น
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 เป็น API ที่ได้รับการปรับให้เหมาะสมกว่าสำหรับการดำเนินการ IO ข้อมูลเมื่อเทียบกับ IO API แบบเดิมของ Java การสนับสนุนเพิ่มเติมอีกอย่างหนึ่งที่ Java NIO มีให้คือการอ่าน / เขียนข้อมูลจาก / ไปยังบัฟเฟอร์หลายตัวไปยังแชนเนล และการสนับสนุนการเขียนเรียกว่า Scatter and Gather ซึ่งข้อมูลจะกระจัดกระจายไปยังบัฟเฟอร์หลายรายการจากช่องทางเดียวในกรณีที่อ่านข้อมูลในขณะที่รวบรวมข้อมูลจากหลายบัฟเฟอร์ไปยังช่องเดียวในกรณีที่เขียนข้อมูล
เพื่อให้บรรลุการอ่านและเขียนหลายรายการจากแชนเนลมี ScatteringByteChannel และ GatheringByteChannel API ซึ่ง Java NIO จัดเตรียมไว้สำหรับอ่านและเขียนข้อมูลดังที่แสดงในตัวอย่างด้านล่าง
ScatteringByteChannel
Read from multiple channels - ในสิ่งนี้เราทำขึ้นเพื่ออ่านข้อมูลจากช่องทางเดียวเป็นหลายบัฟเฟอร์สำหรับบัฟเฟอร์หลายตัวนี้จะถูกจัดสรรและเพิ่มลงในอาร์เรย์ประเภทบัฟเฟอร์จากนั้นอาร์เรย์นี้จะถูกส่งเป็นพารามิเตอร์ไปยังเมธอด ScatteringByteChannel read () ซึ่งจะเขียนข้อมูลจาก ช่องในลำดับที่บัฟเฟอร์เกิดขึ้นในอาร์เรย์เมื่อบัฟเฟอร์เต็มแล้วช่องจะย้ายไปเติมบัฟเฟอร์ถัดไป
ตัวอย่างต่อไปนี้แสดงวิธีการกระจายข้อมูลใน 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 เป็น API ที่ได้รับการปรับให้เหมาะสมกว่าสำหรับการดำเนินการ IO ข้อมูลเมื่อเทียบกับ IO API แบบเดิมของ Java การสนับสนุนเพิ่มเติมอีกอย่างหนึ่งที่ Java NIO มีให้คือการอ่าน / เขียนข้อมูลจาก / ไปยังบัฟเฟอร์หลายตัวไปยังแชนเนล และการสนับสนุนการเขียนเรียกว่า Scatter and Gather ซึ่งข้อมูลจะกระจัดกระจายไปยังบัฟเฟอร์หลายรายการจากช่องทางเดียวในกรณีที่อ่านข้อมูลในขณะที่รวบรวมข้อมูลจากหลายบัฟเฟอร์ไปยังช่องเดียวในกรณีที่เขียนข้อมูล
เพื่อให้บรรลุการอ่านและเขียนหลายรายการจากแชนเนลมี ScatteringByteChannel และ GatheringByteChannel API ซึ่ง Java NIO จัดเตรียมไว้สำหรับอ่านและเขียนข้อมูลดังที่แสดงในตัวอย่างด้านล่าง
GatheringByteChannel
write to multiple channels - ในสิ่งนี้เราทำขึ้นเพื่อเขียนข้อมูลจากบัฟเฟอร์หลายตัวลงในช่องทางเดียวสำหรับสิ่งนี้อีกครั้งบัฟเฟอร์หลายรายการจะถูกจัดสรรและเพิ่มลงในอาร์เรย์ประเภทบัฟเฟอร์จากนั้นอาร์เรย์นี้จะถูกส่งเป็นพารามิเตอร์ไปยังเมธอด GatheringByteChannel write () ซึ่งจะเขียนข้อมูล จากบัฟเฟอร์หลายตัวในลำดับบัฟเฟอร์จะเกิดขึ้นในอาร์เรย์จุดหนึ่งที่ต้องจำไว้คือข้อมูลระหว่างตำแหน่งและขีด จำกัด ของบัฟเฟอร์เท่านั้นที่เขียน
ตัวอย่างต่อไปนี้แสดงวิธีดำเนินการรวบรวมข้อมูลใน 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 สามารถถือว่าเป็นอ็อบเจ็กต์ธรรมดาซึ่งทำหน้าที่เป็นคอนเทนเนอร์ขนาดคงที่ของชิ้นข้อมูลที่สามารถใช้ในการเขียนข้อมูลไปยังแชนเนลหรืออ่านข้อมูลจากแชนเนลเพื่อให้บัฟเฟอร์ทำหน้าที่เป็นจุดสิ้นสุดของแชนเนล
มีชุดวิธีการที่ทำให้สะดวกในการจัดการกับบล็อกหน่วยความจำเพื่ออ่านและเขียนข้อมูลเข้าและออกจากช่องสัญญาณ
บัฟเฟอร์ทำให้แพ็กเกจ NIO มีประสิทธิภาพมากขึ้นและเร็วขึ้นเมื่อเทียบกับ IO แบบคลาสสิกเนื่องจากในกรณีของข้อมูล IO ถูกจัดการในรูปแบบของสตรีมที่ไม่รองรับการไหลของข้อมูลแบบอะซิงโครนัสและพร้อมกันนอกจากนี้ IO ยังไม่อนุญาตให้เรียกใช้ข้อมูลเป็นกลุ่มหรือกลุ่มไบต์ .
พารามิเตอร์หลักที่กำหนดบัฟเฟอร์ Java NIO สามารถกำหนดเป็น -
Capacity - จำนวนข้อมูล / ไบต์สูงสุดที่สามารถจัดเก็บในบัฟเฟอร์ได้ไม่สามารถเปลี่ยนแปลงความจุของบัฟเฟอร์ได้เมื่อบัฟเฟอร์เต็มแล้วควรล้างข้อมูลก่อนที่จะเขียนลงไป
Limit - Limit มีความหมายตามโหมดของ Buffer เช่นในโหมดการเขียนของ Buffer Limit เท่ากับความจุซึ่งหมายความว่าข้อมูลสูงสุดที่สามารถเขียนในบัฟเฟอร์ได้ในขณะที่อยู่ในโหมดอ่านของขีด จำกัด บัฟเฟอร์หมายถึงขีด จำกัด ของข้อมูลที่สามารถมีได้ อ่านจากบัฟเฟอร์
Position - ชี้ไปยังตำแหน่งปัจจุบันของเคอร์เซอร์ในบัฟเฟอร์ตั้งค่าเริ่มต้นเป็น 0 ในขณะที่สร้างบัฟเฟอร์หรือกล่าวอีกนัยหนึ่งคือดัชนีขององค์ประกอบถัดไปที่จะอ่านหรือเขียนซึ่งได้รับการอัปเดตโดยอัตโนมัติโดย get () และใส่ ( ) วิธีการ
Mark - ทำเครื่องหมายบุ๊กมาร์กของตำแหน่งในบัฟเฟอร์เมื่อเมธอด mark () เรียกว่าตำแหน่งปัจจุบันจะถูกบันทึกและเมื่อรีเซ็ต () เรียกว่าตำแหน่งที่ทำเครื่องหมายไว้จะถูกเรียกคืน
ประเภทบัฟเฟอร์
Java NIO บัฟเฟอร์สามารถจำแนกได้ตามรูปแบบต่อไปนี้บนพื้นฐานของประเภทข้อมูลที่บัฟเฟอร์เกี่ยวข้องกับ -
- ByteBuffer
- MappedByteBuffer
- CharBuffer
- DoubleBuffer
- FloatBuffer
- IntBuffer
- LongBuffer
- ShortBuffer
วิธีการสำคัญของ Buffer
ดังที่ได้กล่าวไปแล้วว่า Buffer ทำหน้าที่เป็นหน่วยความจำซึ่งจัดเตรียมชุดวิธีการที่ช่วยให้จัดการกับบล็อกหน่วยความจำได้สะดวกยิ่งขึ้นต่อไปนี้เป็นวิธีการสำคัญของ Buffer -
allocate(int capacity) - วิธีนี้ใช้เพื่อจัดสรรบัฟเฟอร์ใหม่ที่มีความจุเป็นพารามิเตอร์เมธอด Allocate พ่น IllegalArgumentException ในกรณีที่ความจุที่ส่งผ่านเป็นจำนวนเต็มลบ
read() and put() - วิธีการอ่านของช่องใช้ในการเขียนข้อมูลจากช่องสัญญาณไปยังบัฟเฟอร์ในขณะที่ put เป็นวิธีการของบัฟเฟอร์ที่ใช้ในการเขียนข้อมูลในบัฟเฟอร์
flip() - วิธีการพลิกจะเปลี่ยนโหมดของ Buffer จากการเขียนเป็นโหมดการอ่านนอกจากนี้ยังตั้งค่าตำแหน่งกลับเป็น 0 และกำหนดขีด จำกัด ว่าตำแหน่งอยู่ที่ใดในขณะที่เขียน
write() and get() - วิธีการเขียนของช่องใช้ในการเขียนข้อมูลจากบัฟเฟอร์ไปยังช่องสัญญาณในขณะที่ get เป็นวิธีการของบัฟเฟอร์ที่ใช้ในการอ่านข้อมูลจากบัฟเฟอร์
rewind() - ใช้วิธีการกรอกลับเมื่อต้องอ่านซ้ำเนื่องจากตั้งค่าตำแหน่งกลับเป็นศูนย์และไม่เปลี่ยนค่าขีด จำกัด
clear() and compact() - ใช้ทั้งสองวิธีที่ชัดเจนและกะทัดรัดเพื่อสร้างบัฟเฟอร์จากโหมดอ่านเป็นเขียนclear() วิธีการทำให้ตำแหน่งเป็นศูนย์และขีด จำกัด เท่ากับความจุในวิธีนี้ข้อมูลในบัฟเฟอร์จะไม่ถูกล้างเฉพาะเครื่องหมายที่ได้รับการเริ่มต้นใหม่
ในทางกลับกัน compact() วิธีนี้ใช้เมื่อยังคงมีข้อมูลที่ยังไม่ได้อ่านและเรายังคงใช้โหมดการเขียนของบัฟเฟอร์ในกรณีนี้วิธีการที่กะทัดรัดจะคัดลอกข้อมูลที่ยังไม่ได้อ่านทั้งหมดไปยังจุดเริ่มต้นของบัฟเฟอร์และตั้งค่าตำแหน่งไปทางขวาหลังจากองค์ประกอบสุดท้ายที่ยังไม่ได้อ่านคุณสมบัติขีด จำกัด ยังคงอยู่ ตั้งค่าเป็นความจุ
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 รองรับการทำธุรกรรมหลายรายการจากและไปยังช่องและบัฟเฟอร์ดังนั้นเพื่อตรวจสอบ NIO Channel หนึ่งช่องหรือมากกว่าและพิจารณาว่าช่องทางใดที่พร้อมสำหรับการทำธุรกรรมข้อมูลเช่นการอ่านหรือการเขียน Java NIO ให้ Selector
ด้วย 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(long timeout) - วิธีนี้ทำเช่นเดียวกับ select () ยกเว้นว่าจะบล็อกเธรดเป็นเวลาสูงสุดมิลลิวินาทีการหมดเวลา (พารามิเตอร์)
selectNow() - วิธีนี้ไม่ได้ปิดกั้นเลย แต่จะส่งคืนทันทีเมื่อมีช่องใดก็ตามที่พร้อม
นอกจากนี้เพื่อที่จะออกจากเธรดที่ถูกบล็อกซึ่งเรียกใช้วิธีการเลือกwakeup() สามารถเรียกใช้วิธีการจากอินสแตนซ์ตัวเลือกหลังจากนั้นเธรดที่รออยู่ภายใน select () จะกลับมาทันที
ในที่สุดเราสามารถปิดตัวเลือกโดยการโทร close() ซึ่งยังทำให้อินสแตนซ์ SelectionKey ทั้งหมดที่ลงทะเบียนกับ Selector นี้ไม่ถูกต้องพร้อมกับการปิดตัวเลือก
ตัวอย่าง
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 ไปป์เป็นส่วนประกอบที่ใช้ในการเขียนและอ่านข้อมูลระหว่างสองเธรดท่อส่วนใหญ่ประกอบด้วยสองช่องทางซึ่งรับผิดชอบในการเผยแพร่ข้อมูล
หนึ่งในสองช่องที่เป็นส่วนประกอบหนึ่งเรียกว่าช่อง Sink ซึ่งส่วนใหญ่ใช้สำหรับการเขียนข้อมูลและช่องอื่น ๆ คือช่องแหล่งที่มาซึ่งมีจุดประสงค์หลักเพื่ออ่านข้อมูลจากช่อง Sink
การซิงโครไนซ์ข้อมูลจะถูกเก็บไว้ตามลำดับในระหว่างการเขียนและการอ่านข้อมูลเนื่องจากต้องมั่นใจว่าข้อมูลจะต้องอ่านในลำดับเดียวกันกับที่เขียนไปยัง Pipe
ต้องแจ้งให้ทราบว่าเป็นการไหลแบบทิศทางเดียวของข้อมูลใน Pipe กล่าวคือข้อมูลที่เขียนในช่อง Sink เท่านั้นและสามารถอ่านได้จากช่องต้นทางเท่านั้น
ในท่อ Java NIO ถูกกำหนดให้เป็นคลาสนามธรรมโดยมีสามวิธีเป็นหลักซึ่งสองวิธีเป็นนามธรรม
วิธีการของคลาส Pipe
open() - วิธีนี้ใช้เพื่อรับอินสแตนซ์ของ Pipe หรือเราสามารถพูดได้ว่าไพพ์ถูกสร้างขึ้นโดยเรียกใช้เมธอดนี้
sink() - วิธีนี้จะคืนค่าช่องอ่างของท่อซึ่งใช้ในการเขียนข้อมูลโดยเรียกวิธีการเขียน
source() - วิธีนี้จะส่งคืนช่องต้นทางของ 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ซึ่งมีเนื้อหาดังต่อไปนี้ ไฟล์นี้จะใช้เป็นอินพุตสำหรับโปรแกรมตัวอย่างของเรา
ตามชื่อที่แนะนำ Path คือตำแหน่งเฉพาะของเอนทิตีเช่นไฟล์หรือไดเร็กทอรีในระบบไฟล์เพื่อให้สามารถค้นหาและเข้าถึงได้จากตำแหน่งนั้น ๆ
ในทางเทคนิคของ Java Path เป็นอินเทอร์เฟซที่นำมาใช้ในแพ็กเกจไฟล์ Java NIO ระหว่าง Java เวอร์ชัน 7 และเป็นการแสดงตำแหน่งในระบบไฟล์เฉพาะเนื่องจากพา ธ อินเตอร์เฟสอยู่ในแพ็คเกจ Java NIO ดังนั้นจึงได้รับชื่อที่ถูกต้องเป็น java .nio.file.Path.
โดยทั่วไปเส้นทางของเอนทิตีอาจมีสองประเภทประเภทหนึ่งคือพา ธ สัมบูรณ์และอีกประเภทหนึ่งเป็นพา ธ สัมพัทธ์เนื่องจากชื่อของทั้งสองพา ธ แสดงให้เห็นว่าพา ธ สัมบูรณ์คือที่อยู่ที่ตั้งจากรูทไปยังเอนทิตีที่ระบุตำแหน่งในขณะที่พา ธ สัมพัทธ์เป็นที่อยู่ที่ตั้ง ซึ่งสัมพันธ์กับเส้นทางอื่น ๆ Path ใช้ตัวคั่นในคำจำกัดความเป็น "\" สำหรับ 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 ให้เรา
วิธีการสำคัญของ Path Interface
getFileName() - ส่งคืนระบบไฟล์ที่สร้างอ็อบเจ็กต์นี้
getName() - ส่งคืนองค์ประกอบชื่อของเส้นทางนี้เป็นวัตถุ Path
getNameCount() - ส่งคืนจำนวนองค์ประกอบชื่อในเส้นทาง
subpath() - ส่งคืนเส้นทางสัมพัทธ์ที่เป็นลำดับต่อมาขององค์ประกอบชื่อของเส้นทางนี้
getParent() - ส่งคืนพา ธ พาเรนต์หรือค่าว่างหากพา ธ นี้ไม่มีพาเรนต์
getRoot() - ส่งคืนองค์ประกอบรากของเส้นทางนี้เป็นวัตถุเส้นทางหรือค่าว่างหากเส้นทางนี้ไม่มีองค์ประกอบราก
toAbsolutePath() - ส่งคืนอ็อบเจ็กต์ Path ที่แสดงถึงพา ธ สัมบูรณ์ของพา ธ นี้
toRealPath() - ส่งคืนเส้นทางจริงของไฟล์ที่มีอยู่
toFile() - ส่งคืนอ็อบเจ็กต์ไฟล์ที่แสดงเส้นทางนี้
normalize() - ส่งคืนเส้นทางที่เป็นเส้นทางนี้โดยตัดองค์ประกอบชื่อที่ซ้ำซ้อนออกไป
compareTo(Path other) - เปรียบเทียบเส้นทางนามธรรมสองทางตามศัพท์วิธีนี้จะคืนค่าเป็นศูนย์หากอาร์กิวเมนต์เท่ากับเส้นทางนี้ค่าน้อยกว่าศูนย์หากเส้นทางนี้มีศัพท์น้อยกว่าอาร์กิวเมนต์หรือค่าที่มากกว่าศูนย์หากเส้นทางนี้มีค่ามากกว่าอาร์กิวเมนต์ในเชิงศัพท์ .
endsWith(Path other) - ทดสอบว่าเส้นทางนี้ลงท้ายด้วยเส้นทางที่กำหนดหรือไม่หากเส้นทางที่กำหนดมีองค์ประกอบ N และไม่มีองค์ประกอบรูทและเส้นทางนี้มีองค์ประกอบ N หรือมากกว่าเส้นทางนี้จะสิ้นสุดด้วยเส้นทางที่กำหนดหากองค์ประกอบ N สุดท้ายของแต่ละเส้นทาง เริ่มต้นที่องค์ประกอบที่ไกลที่สุดจากรากมีค่าเท่ากัน
endsWith(String other) - ทดสอบว่าเส้นทางนี้ลงท้ายด้วย Path หรือไม่ซึ่งสร้างขึ้นโดยการแปลงสตริงพา ธ ที่กำหนดในลักษณะที่ระบุโดยเมธอด endWith (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 มี API ยูทิลิตี้อีกหนึ่งตัวที่มีชื่อว่าไฟล์ซึ่งโดยทั่วไปจะใช้สำหรับการจัดการไฟล์และไดเร็กทอรีโดยใช้วิธีการแบบคงที่ซึ่งส่วนใหญ่ทำงานบนออบเจ็กต์ Path
ดังที่กล่าวไว้ในบทช่วยสอน Path ว่าอินเทอร์เฟซ Path ถูกนำมาใช้ในแพ็คเกจ Java NIO ระหว่างเวอร์ชัน Java 7 ในแพ็คเกจไฟล์ดังนั้นบทช่วยสอนนี้จึงใช้สำหรับแพ็คเกจไฟล์เดียวกัน
คลาสนี้ประกอบด้วยเมธอดแบบคงที่ที่ดำเนินการกับไฟล์ไดเร็กทอรีหรือไฟล์ประเภทอื่น ๆ เท่านั้นในกรณีส่วนใหญ่เมธอดที่กำหนดไว้ที่นี่จะมอบสิทธิ์ให้กับผู้ให้บริการระบบไฟล์ที่เกี่ยวข้องเพื่อดำเนินการกับไฟล์
มีวิธีการมากมายที่กำหนดไว้ในคลาสไฟล์ซึ่งสามารถอ่านได้จากเอกสาร Java ในบทช่วยสอนนี้เราพยายามที่จะครอบคลุมวิธีการที่สำคัญบางอย่างจากวิธีการทั้งหมดของคลาส Java NIO Files
วิธีการที่สำคัญของคลาสไฟล์
ต่อไปนี้เป็นวิธีการสำคัญที่กำหนดไว้ในคลาส Java NIO Files
createFile(Path filePath, FileAttribute attrs) - คลาสไฟล์จัดเตรียมวิธีการนี้เพื่อสร้างไฟล์โดยใช้ 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) - วิธีนี้ใช้เพื่อคัดลอกไบต์ทั้งหมดจากอินพุตสตรีมที่ระบุไปยังไฟล์เป้าหมายที่ระบุและส่งคืนจำนวนไบต์ที่อ่านหรือเขียนเป็นค่ายาว LinkOption สำหรับพารามิเตอร์นี้ด้วยค่าต่อไปนี้ -
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 รองรับการทำงานพร้อมกันและมัลติเธรดซึ่งช่วยให้เราจัดการกับแชนเนลต่างๆพร้อมกันได้ในเวลาเดียวกันดังนั้น API ที่รับผิดชอบในสิ่งนี้ในแพ็คเกจ Java NIO คือ AsynchronousFileChannel ซึ่งกำหนดไว้ภายใต้แพ็คเกจช่อง NIO ดังนั้นชื่อที่ถูกต้อง สำหรับ AsynchronousFileChannel คือ java.nio.channels.AsynchronousFileChannel.
AsynchronousFileChannel คล้ายกับ FileChannel ของ NIO ยกเว้นว่าแชนเนลนี้เปิดใช้งานไฟล์เพื่อดำเนินการแบบอะซิงโครนัสซึ่งแตกต่างจากการดำเนินการ I / O แบบซิงโครนัสที่เธรดเข้าสู่การดำเนินการและรอจนกว่าการร้องขอจะเสร็จสมบูรณ์ดังนั้นแชนเนลแบบอะซิงโครนัสจึงปลอดภัยสำหรับการใช้งาน โดยหลายเธรดพร้อมกัน
ในแบบอะซิงโครนัสคำร้องขอจะถูกส่งผ่านเธรดไปยังเคอร์เนลของระบบปฏิบัติการเพื่อให้มันเสร็จสิ้นในขณะที่เธรดยังคงประมวลผลงานอื่นเมื่องานของเคอร์เนลเสร็จสิ้นมันจะส่งสัญญาณไปยังเธรดจากนั้นเธรดจะรับสัญญาณและขัดจังหวะงานปัจจุบันและประมวลผล งาน I / O ตามต้องการ
เพื่อให้บรรลุการทำงานพร้อมกันช่องทางนี้มีสองแนวทางซึ่งรวมถึงวิธีหนึ่งที่ส่งกลับ a java.util.concurrent.Future object และอื่น ๆ คือการส่งผ่านไปยังการดำเนินการวัตถุประเภท java.nio.channels.CompletionHandler.
เราจะเข้าใจทั้งสองแนวทางด้วยความช่วยเหลือของตัวอย่างทีละตัวอย่าง
Future Object - ในอินสแตนซ์ของอินเทอร์เฟซในอนาคตจะถูกส่งคืนจากช่องสัญญาณในอินเทอร์เฟซในอนาคตมี get() วิธีการที่ส่งคืนสถานะของการดำเนินการที่ได้รับการจัดการแบบอะซิงโครนัสบนพื้นฐานของการตัดสินใจดำเนินการงานอื่น ๆ ต่อไปนอกจากนี้เรายังสามารถตรวจสอบว่างานเสร็จสมบูรณ์หรือไม่โดยเรียก isDone วิธี.
ตัวอย่าง
ตัวอย่างต่อไปนี้แสดงวิธีการใช้วัตถุในอนาคตและงานแบบอะซิงโครนัส
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 และแทนที่สองวิธีหนึ่งคือ 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 สำหรับทุกอักขระจะมีหน่วยรหัส Unicode ที่กำหนดไว้อย่างดีซึ่ง JVM จัดการภายในดังนั้นแพ็คเกจ Java NIO จึงกำหนดคลาสนามธรรมที่มีชื่อว่า Charset ซึ่งส่วนใหญ่จะใช้สำหรับการเข้ารหัสและถอดรหัสชุดอักขระและ UNICODE
ชุดอักขระมาตรฐาน
Charset ที่รองรับใน java มีให้ด้านล่าง
US-ASCII - อักขระ ASCII เจ็ดบิต
ISO-8859-1 - อักษรละติน ISO
UTF-8 - นี่คือรูปแบบการแปลง UCS 8 บิต
UTF-16BE - นี่คือรูปแบบการแปลง UCS 16 บิตพร้อมคำสั่ง endian byte ขนาดใหญ่
UTF-16LE - นี่คือการแปลง UCS 16 บิตพร้อมคำสั่ง endian byte เล็กน้อย
UTF-16 - รูปแบบการแปลง UCS 16 บิต
วิธีการที่สำคัญของคลาส Charset
forName() - วิธีนี้สร้างออบเจ็กต์ชุดอักขระสำหรับชื่อชุดอักขระที่กำหนดชื่อสามารถเป็นนามแฝงหรือนามแฝง
displayName() - วิธีนี้ส่งคืนชื่อมาตรฐานของชุดอักขระที่กำหนด
canEncode() - วิธีนี้จะตรวจสอบว่าชุดอักขระที่ระบุรองรับการเข้ารหัสหรือไม่
decode() - วิธีนี้จะถอดรหัสสตริงของชุดอักขระที่กำหนดให้เป็น charbuffer ของ Unicode charset
encode() - วิธีนี้เข้ารหัส charbuffer ของ unicode charset ลงในไบต์บัฟเฟอร์ของชุดอักขระที่กำหนด
ตัวอย่าง
ตัวอย่างต่อไปนี้แสดงให้เห็นถึงวิธีการที่สำคัญของคลาส 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 จัดเตรียม API ที่เรียกว่า FileLock อีกครั้งซึ่งใช้เพื่อล็อกไฟล์ทั้งหมดหรือบางส่วนของไฟล์ดังนั้นไฟล์หรือส่วนนั้นจะไม่ถูกแชร์หรือเข้าถึงได้
ในการจัดหาหรือใช้การล็อกดังกล่าวเราต้องใช้ FileChannel หรือ AsynchronousFileChannel ซึ่งมีสองวิธี lock() และ tryLock()เพื่อจุดประสงค์นี้ล็อคที่มีให้อาจมีสองประเภท -
Exclusive Lock - การล็อกแบบพิเศษจะป้องกันไม่ให้โปรแกรมอื่นได้รับการล็อกที่ทับซ้อนกันของประเภทใด
Shared Lock - การล็อกที่ใช้ร่วมกันจะป้องกันไม่ให้โปรแกรมอื่น ๆ ที่ทำงานพร้อมกันได้รับการล็อกแบบเอกสิทธิ์เฉพาะบุคคลที่ทับซ้อนกัน แต่จะช่วยให้สามารถรับการล็อกที่ใช้ร่วมกันที่ทับซ้อนกันได้
วิธีการที่ใช้ในการล็อคไฟล์ -
lock() - วิธีนี้ของ FileChannel หรือ AsynchronousFileChannel ได้รับการล็อกเฉพาะสำหรับไฟล์ที่เกี่ยวข้องกับช่องสัญญาณที่กำหนดประเภทการส่งคืนของวิธีนี้คือ FileLock ซึ่งใช้เพิ่มเติมสำหรับการตรวจสอบการล็อกที่ได้รับ
lock(long position, long size, boolean shared) - วิธีนี้อีกครั้งเป็นวิธีการล็อคที่โอเวอร์โหลดและใช้เพื่อล็อคส่วนใดส่วนหนึ่งของไฟล์
tryLock() - วิธีนี้จะส่งคืน FileLock หรือ null หากไม่สามารถรับการล็อกได้และพยายามที่จะได้รับการล็อกเฉพาะอย่างชัดเจนสำหรับไฟล์ของช่องนี้
tryLock(long position, long size, boolean shared) - วิธีนี้พยายามที่จะได้รับการล็อคในพื้นที่ที่กำหนดของไฟล์ของช่องนี้ซึ่งอาจเป็นประเภทพิเศษหรือประเภทที่ใช้ร่วมกัน
วิธีการของ FileLock Class
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.