Sebelumnya, kita mengenal IO API (Input/Output Application Programming Interface) dan paket java.io , yang kelasnya terutama untuk bekerja dengan aliran di Java. Kuncinya di sini adalah konsep aliran .

Hari ini kita akan mulai mempertimbangkan NIO API (New Input/Output).

Perbedaan utama antara dua pendekatan untuk I/O adalah bahwa API IO berorientasi aliran sedangkan API NIO berorientasi buffer. Jadi konsep utama yang harus dipahami adalah buffer dan saluran .

Apa itu buffer dan apa itu saluran?

Saluran adalah portal logis tempat data bergerak masuk dan keluar, sedangkan buffer adalah sumber atau tujuan dari data yang dikirimkan ini . Selama keluaran, data yang ingin Anda kirim dimasukkan ke dalam buffer, dan buffer meneruskan data ke saluran. Selama input, data dari saluran dimasukkan ke dalam buffer.

Dengan kata lain:

  • buffer hanyalah sebuah blok memori tempat kita dapat menulis informasi dan dari mana kita dapat membaca informasi ,
  • saluran adalah gateway yang menyediakan akses ke perangkat I/O seperti file atau soket .

Saluran sangat mirip dengan aliran dalam paket java.io. Semua data yang pergi ke mana saja (atau datang dari mana saja) harus melewati objek saluran. Secara umum, untuk menggunakan sistem NIO, Anda mendapatkan saluran ke entitas I/O dan buffer untuk menyimpan data. Kemudian Anda bekerja dengan buffer, memasukkan atau mengeluarkan data sesuai kebutuhan.

Anda dapat bergerak maju dan mundur dalam buffer, yaitu "menjalankan" buffer, yang merupakan sesuatu yang tidak dapat Anda lakukan di aliran. Ini memberi lebih banyak fleksibilitas saat memproses data. Di perpustakaan standar, buffer diwakili oleh kelas Buffer abstrak dan beberapa turunannya:

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

Perbedaan utama antara subclass adalah tipe data yang mereka simpan — bytes , ints , longs , dan tipe data primitif lainnya.

Properti penyangga

Buffer memiliki empat sifat utama. Ini adalah kapasitas, batas, posisi, dan tanda.

Kapasitas adalah jumlah maksimum data/byte yang dapat disimpan dalam buffer. Kapasitas buffer tidak dapat diubah . Setelah buffer penuh, itu harus dibersihkan sebelum menulis lebih banyak.

Dalam mode tulis, batas buffer sama dengan kapasitasnya, menunjukkan jumlah maksimum data yang dapat ditulis ke buffer. Dalam mode baca, batas buffer mengacu pada jumlah maksimum data yang dapat dibaca dari buffer.

Posisi menunjukkan posisi kursor saat ini di buffer . Awalnya, ini diatur ke 0 saat buffer dibuat. Dengan kata lain, itu adalah indeks dari elemen berikutnya yang akan dibaca atau ditulis.

Tanda digunakan untuk menyimpan posisi kursor . Saat kami memanipulasi buffer, posisi kursor berubah secara konstan, tetapi kami selalu dapat mengembalikannya ke posisi yang ditandai sebelumnya.

Metode untuk bekerja dengan buffer

Sekarang mari kita lihat sekumpulan metode utama yang memungkinkan kita bekerja dengan buffer (blok memori) kita untuk membaca dan menulis data ke dan dari saluran.

  1. mengalokasikan(int capacity) — metode ini digunakan untuk mengalokasikan buffer baru dengan kapasitas yang ditentukan. Metode alokasikan() melontarkan IllegalArgumentException jika kapasitas yang diteruskan adalah bilangan bulat negatif.

  2. capacity() mengembalikan capacity buffer saat ini .

  3. position() mengembalikan posisi kursor saat ini. Operasi baca dan tulis memindahkan kursor ke ujung buffer. Nilai pengembalian selalu kurang dari atau sama dengan batas.

  4. limit() mengembalikan batas buffer saat ini.

  5. mark() digunakan untuk menandai (menyimpan) posisi kursor saat ini.

  6. reset() mengembalikan kursor ke posisi yang sebelumnya ditandai (disimpan).

  7. clear() menyetel posisi ke nol dan menyetel batas kapasitas. Metode ini tidak menghapus data dalam buffer. Itu hanya menginisialisasi ulang posisi, batas, dan tanda.

  8. flip() mengalihkan buffer dari mode tulis ke mode baca. Ini juga menetapkan batas posisi saat ini dan kemudian mengembalikan posisi ke nol.

  9. read() — Metode baca saluran digunakan untuk menulis data dari saluran ke buffer, sedangkan metode put() buffer digunakan untuk menulis data ke buffer.

  10. write() — Metode tulis saluran digunakan untuk menulis data dari buffer ke saluran, sedangkan metode get() buffer digunakan untuk membaca data dari buffer.

  11. rewind() memundurkan buffer. Metode ini digunakan saat Anda perlu membaca ulang buffer — metode ini menyetel posisi ke nol dan tidak mengubah batas.

Dan sekarang beberapa kata tentang saluran.

Implementasi saluran terpenting di Java NIO adalah kelas-kelas berikut:

  1. FileChannel — Saluran untuk membaca dan menulis data dari/ke file.

  2. DatagramChannel — Kelas ini membaca dan menulis data melalui jaringan melalui UDP (User Datagram Protocol).

  3. SocketChannel — Saluran untuk membaca dan menulis data melalui jaringan melalui TCP (Transmission Control Protocol).

  4. ServerSocketChannel — Saluran untuk membaca dan menulis data melalui koneksi TCP, seperti halnya server web. SocketChanneldibuat untuk setiap koneksi yang masuk .

Praktik

Saatnya menulis beberapa baris kode. Pertama, mari baca file dan tampilkan kontennya di konsol, lalu tulis beberapa string ke file.

Kode berisi banyak komentar — Saya harap mereka akan membantu Anda memahami cara kerja semuanya:


// Create a RandomAccessFile object, passing in the file path
// and a string that says the file will be opened for reading and writing
try (RandomAccessFile randomAccessFile = new RandomAccessFile("text.txt", "rw");
    // Get an instance of the FileChannel class
    FileChannel channel = randomAccessFile.getChannel();
) {
// Our file is small, so we'll read it in one go   
// Create a buffer of the required size based on the size of our channel
   ByteBuffer byteBuffer = ByteBuffer.allocate((int) channel.size());
   // Read data will be put into a StringBuilder
   StringBuilder builder = new StringBuilder();
   // Write data from the channel to the buffer
   channel.read(byteBuffer);
   // Switch the buffer from write mode to read mode
   byteBuffer.flip();
   // In a loop, write data from the buffer to the StringBuilder
   while (byteBuffer.hasRemaining()) {
       builder.append((char) byteBuffer.get());
   }
   // Display the contents of the StringBuilder on the console
   System.out.println(builder);
 
   // Now let's continue our program and write data from a string to the file
   // Create a string with arbitrary text
   String someText = "Hello, Amigo!!!!!";
   // Create a new buffer for writing,
   // but let the channel remain the same, because we're going to the same file
   // In other words, we can use one channel for both reading and writing to a file
   // Create a buffer specifically for our string — convert the string into an array and get its length
   ByteBuffer byteBuffer2 = ByteBuffer.allocate(someText.getBytes().length);
   // Write our string to the buffer
   byteBuffer2.put(someText.getBytes());
   // Switch the buffer from write mode to read mode
   // so that the channel can read from the buffer and write our string to the file
   byteBuffer2.flip();
   // The channel reads the information from the buffer and writes it to our file
   channel.write(byteBuffer2);
} catch (FileNotFoundException e) {
   e.printStackTrace();
} catch (IOException e) {
   e.printStackTrace();
}

Coba NIO API — Anda akan menyukainya!