Apa Java IO dadi ala?

IO (Input & Output) API minangka API Java sing nggampangake pangembang kanggo nggarap stream. Contone, kita nampa sawetara data (contone, jeneng ngarep, jeneng tengah, jeneng mburi) lan kita kudu nulis menyang file — wektu wis teka kanggo nggunakake java.io .

Struktur perpustakaan java.io

Nanging Java IO duwe kekurangan, mula ayo ngomong babagan saben siji:

  1. Watesan akses kanggo input / output. Masalahe yaiku nalika pangembang nyoba maca utawa nulis soko menyang file nggunakake Java IO , file kasebut bakal ngunci lan mblokir akses menyang file kasebut nganti rampung.
  2. Ora ana dhukungan kanggo sistem file virtual.
  3. Ora ana dhukungan kanggo tautan.
  4. Akeh lan akeh pengecualian sing dicenthang.

Nggarap file mesthi mbutuhake pangecualian: contone, nyoba nggawe file anyar sing wis ana bakal mbuwang IOException . Ing kasus iki, aplikasi kudu terus mlaku lan pangguna kudu diwenehi kabar kenapa file kasebut ora bisa digawe.


try {
	File.createTempFile("prefix", "");
} catch (IOException e) {
	// Handle the IOException
}

/**
 * Creates an empty file in the default temporary-file directory 
 * any exceptions will be ignored. This is typically used in finally blocks. 
 * @param prefix 
 * @param suffix 
 * @throws IOException - If a file could not be created
 */
public static File createTempFile(String prefix, String suffix) 
throws IOException {
...
}

Ing kene kita bisa ndeleng manawa metode createTempFile mbuwang IOException nalika file kasebut ora bisa digawe. Pengecualian iki kudu ditangani kanthi tepat. Yen kita nyoba nelpon cara iki ing njaba blok nyoba-nyekel , kompiler bakal ngasilake kesalahan lan menehi saran rong pilihan kanggo ndandani: mbungkus metode kasebut ing blok nyoba-nyekel utawa nggawe metode sing nelpon File.createTempFile mbuwang IOException ( supaya bisa ditangani ing tingkat sing luwih dhuwur).

Tekan Java NIO lan kepiye dibandhingake karo Java IO

Java NIO , utawa Java Non-Blocking I/O (utawa kadhangkala Java New I/O) dirancang kanggo operasi I/O kanthi kinerja dhuwur.

Ayo mbandhingake metode Java IO lan sing ngganti.

Pisanan, ayo ngomong babagan nggarap Java IO :

Kelas InputStream


try(FileInputStream fin = new FileInputStream("C:/codegym/file.txt")){
    System.out.printf("File size: %d bytes \n", fin.available());
    int i=-1;
    while((i=fin.read())!=-1) {
        System.out.print((char)i);
    }   
} catch(IOException ex) {
    System.out.println(ex.getMessage());
}

Kelas FileInputStream kanggo maca data saka file. Iku marisi kelas InputStream lan mulane nindakake kabeh cara. Yen file ora bisa dibukak, FileNotFoundException dibuwang.

Kelas OutputStream


String text = "Hello world!"; // String to write
try(FileOutputStream fos = new FileOutputStream("C:/codegym/file.txt")){
    // Convert our string into bytes
    byte[] buffer = text.getBytes();
    fos.write(buffer, 0, buffer.length);
    System.out.println("The file has been written");
} catch(IOException ex) {
    System.out.println(ex.getMessage());
}

Kelas FileOutputStream kanggo nulis bita menyang file. Asale saka kelas OutputStream .

Kelas Reader lan Writer

Kelas FileReader ngidini kita maca data karakter saka stream, lan kelas FileWriter digunakake kanggo nulis stream karakter . Kode ing ngisor iki nuduhake carane nulis lan maca saka file:


        String fileName = "c:/codegym/Example.txt";

        // Create a FileWriter object
        try (FileWriter writer = new FileWriter(fileName)) {

            // Write content to file
            writer.write("This is a simple example\nin which we\nwrite to a file\nand read from a file\n");
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Create a FileReader object
        try (FileReader fr = new FileReader(fileName)) {
            char[] a = new char[200]; // Number of characters to read
            fr.read(a); // Read content into an array
            for (char c : a) {
                System.out.print(c); // Display characters one by one
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

Saiki ayo ngomong babagan Java NIO :

Saluran

Ora kaya stream sing digunakake ing Java IO , Saluran minangka antarmuka rong arah, yaiku, bisa maca lan nulis. Saluran Java NIO ndhukung aliran data asinkron ing mode pamblokiran lan non-pamblokiran.


RandomAccessFile aFile = new RandomAccessFile("C:/codegym/file.txt", "rw");
FileChannel inChannel = aFile.getChannel();

ByteBuffer buf = ByteBuffer.allocate(100);
int bytesRead = inChannel.read(buf);

while (bytesRead != -1) {
  System.out.println("Read: " + bytesRead);
  buf.flip();
	  while(buf.hasRemaining()) {
	      System.out.print((char) buf.get());
	  }
  buf.clear();
  bytesRead = inChannel.read(buf);
}
aFile.close();

Ing kene kita nggunakake FileChannel . Kita nggunakake saluran file kanggo maca data saka file. Objek saluran file mung bisa digawe kanthi nelpon metode getChannel () ing obyek file - ora ana cara kanggo nggawe obyek saluran file langsung.

Saliyane FileChannel , kita duwe implementasi saluran liyane:

  • FileChannel - kanggo nggarap file

  • DatagramChannel - saluran kanggo nggarap sambungan UDP

  • SocketChannel - saluran kanggo nggarap sambungan TCP

  • ServerSocketChannel ngemot SocketChannel lan padha karo cara kerja server web

Wigati dimangerteni: FileChannel ora bisa dialihake menyang mode non-blocking. Mode non-blocking Java NIO ngidini sampeyan njaluk data diwaca saka saluran lan mung nampa apa sing kasedhiya (utawa ora ana apa-apa yen durung ana data). Yen ngandika, SelectableChannel lan implementasine bisa dilebokake ing mode non-blocking nggunakake cara connect () .

Pamilih

Java NIO ngenalake kemampuan kanggo nggawe thread sing ngerti saluran sing siap nulis lan maca data lan bisa ngolah saluran kasebut. Kemampuan iki dileksanakake nggunakake kelas Selector .

Nyambungake saluran menyang pamilih


Selector selector = Selector.open();
channel.configureBlocking(false); // Non-blocking mode
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);

Dadi kita nggawe Selector lan nyambung menyang SelectableChannel .

Kanggo digunakake karo pamilih, saluran kudu ing mode non-blocking. Iki tegese sampeyan ora bisa nggunakake FileChannel kanthi pamilih, amarga FileChannel ora bisa dilebokake ing mode non-blocking. Nanging saluran soket bakal apik.

Ing kene, kita sebutake yen ing conto SelectionKey yaiku sakumpulan operasi sing bisa ditindakake ing saluran. Tombol pilihan ngidini kita ngerti status saluran.

Jinis SelectionKey

  • SelectionKey.OP_CONNECT nuduhake saluran sing siap kanggo nyambung menyang server.

  • SelectionKey.OP_ACCEPT minangka saluran sing siap nampa sambungan sing mlebu.

  • SelectionKey.OP_READ nuduhake saluran sing siap maca data.

  • SelectionKey.OP_WRITE nuduhake saluran sing siap nulis data.

panyangga

Data kasebut diwaca dadi buffer kanggo diproses luwih lanjut. A pangembang bisa mindhah bali lan kasebut ing buffer, kang menehi kita sethitik liyane keluwesan nalika Processing data. Ing wektu sing padha, kita kudu mriksa apa buffer ngemot jumlah data sing dibutuhake kanggo pangolahan sing bener. Uga, nalika maca data menyang buffer, priksa manawa sampeyan ora ngrusak data sing wis ana sing durung diproses.


ByteBuffer buf = ByteBuffer.allocate (2048); 
int bytesRead = channel.read(buf);
buf.flip(); // Change to read mode
while (buf.hasRemaining()) { 
	byte data = buf.get(); // There are methods for primitives 
}

buf.clear(); // Clear the buffer - now it can be reused

Sifat dhasar saka buffer:

Atribut dhasar
kapasitas Ukuran buffer, yaiku dawa array.
posisi Posisi wiwitan kanggo nggarap data.
watesan watesan operasi. Kanggo operasi maca, watesan yaiku jumlah data sing bisa diwaca, nanging kanggo operasi nulis, iku kapasitas utawa kuota sing kasedhiya kanggo nulis.
tandha Indeks nilai sing parameter posisi bakal direset nalika reset () cara disebut.

Saiki ayo ngomong sethithik bab sing anyar ing Java NIO.2 .

Path

Path nggambarake path ing sistem file. Isine jeneng file lan dhaptar direktori sing nemtokake path menyang.


Path relative = Paths.get("Main.java");
System.out.println("File: " + relative);
// Get the file system
System.out.println(relative.getFileSystem());

Paths minangka kelas sing prasaja banget kanthi metode statis tunggal: get() . Iki digawe mung kanggo entuk obyek Path saka string utawa URI sing dilewati.


Path path = Paths.get("c:\\data\\file.txt");

File

File minangka kelas sarana sing ngidini kita langsung entuk ukuran file, nyalin file, lan liya-liyane.


Path path = Paths.get("files/file.txt");
boolean pathExists = Files.exists(path);

FileSystem

FileSystem nyedhiyakake antarmuka menyang sistem file. FileSystem dianggo kaya pabrik kanggo nggawe macem-macem obyek (Path,PathMatcher,File). Iku mbantu kita ngakses file lan obyek liyane ing sistem file.


try {
      FileSystem filesystem = FileSystems.getDefault();
      for (Path rootdir : filesystem.getRootDirectories()) {
          System.out.println(rootdir.toString());
      }
  } catch (Exception e) {
      e.printStackTrace();
  }

Tes kinerja

Kanggo tes iki, ayo njupuk rong file. Sing pertama yaiku file teks cilik, lan sing nomer loro yaiku video gedhe.

Kita bakal nggawe file lan nambah sawetara tembung lan karakter:

% tutul text.txt

Berkas kita ngemot total 42 bita ing memori:

Saiki ayo nulis kode sing bakal nyalin file saka siji folder menyang folder liyane. Ayo dites ing file cilik lan gedhe kanggo mbandhingake kacepetan IO lan NIO lan NIO.2 .

Kode kanggo nyalin, ditulis nganggo Java IO :


public static void main(String[] args) {
        long currentMills = System.currentTimeMillis();
        long startMills = currentMills;
        File src = new File("/Users/IdeaProjects/testFolder/text.txt");
        File dst = new File("/Users/IdeaProjects/testFolder/text1.txt");
        copyFileByIO(src, dst);
        currentMills = System.currentTimeMillis();
        System.out.println("Execution time in milliseconds: " + (currentMills - startMills));
    }

    public static void copyFileByIO(File src, File dst) {
        try(InputStream inputStream = new FileInputStream(src);
            OutputStream outputStream = new FileOutputStream(dst)){

            byte[] buffer = new byte[1024];
            int length;
            // Read data into a byte array and then output to an OutputStream
            while((length = inputStream.read(buffer)) > 0) {
                outputStream.write(buffer, 0, length);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Lan iki kode kanggo Java NIO :


public static void main(String[] args) {
        long currentMills = System.currentTimeMillis();
        long startMills = currentMills;

        File src = new File("/Users/IdeaProjects/testFolder/text.txt");
        File dst = new File("/Users/IdeaProjects/testFolder/text2.txt");
        // Code for copying using NIO
        copyFileByChannel(src, dst);
        currentMills = System.currentTimeMillis();
        System.out.println("Execution time in milliseconds: " + (currentMills - startMills));
    }

    public static void copyFileByChannel(File src, File dst) {
        // 1. Get a FileChannel for the source file and the target file
        try(FileChannel srcFileChannel  = new FileInputStream(src).getChannel();
            FileChannel dstFileChannel = new FileOutputStream(dst).getChannel()){
            // 2. Size of the current FileChannel
            long count = srcFileChannel.size();
            while(count > 0) {
                /**=============================================================
                 * 3. Write bytes from the source file's FileChannel to the target FileChannel
                 * 1. srcFileChannel.position(): the starting position in the source file, cannot be negative
                 * 2. count: the maximum number of bytes transferred, cannot be negative
                 * 3. dstFileChannel: the target file
                 *==============================================================*/
                long transferred = srcFileChannel.transferTo(srcFileChannel.position(),
                        count, dstFileChannel);
                // 4. After the transfer is complete, change the position of the original file to the new one
                srcFileChannel.position(srcFileChannel.position() + transferred);
                // 5. Calculate how many bytes are left to transfer
                count -= transferred;
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Kode kanggo Java NIO.2 :


public static void main(String[] args) {
  long currentMills = System.currentTimeMillis();
  long startMills = currentMills;

  Path sourceDirectory = Paths.get("/Users/IdeaProjects/testFolder/test.txt");
  Path targetDirectory = Paths.get("/Users/IdeaProjects/testFolder/test3.txt");
  Files.copy(sourceDirectory, targetDirectory);

  currentMills = System.currentTimeMillis();
  System.out.println("Execution time in milliseconds: " + (currentMills - startMills));
}

Ayo dadi miwiti karo file cilik.

Wektu eksekusi kanggo Java IO rata-rata 1 milidetik. Kanthi nindakake tes kaping pirang-pirang, kita entuk asil saka 0 nganti 2 milidetik.

Wektu eksekusi ing milidetik: 1

Wektu eksekusi Java NIO luwih suwe. Wektu rata-rata yaiku 11 milidetik. Asil saka 9 kanggo 16. Iki amarga Java IO dianggo beda saka sistem operasi kita. IO mindhah lan ngolah file siji-siji, nanging sistem operasi ngirim data ing siji potongan gedhe. NIO nindakake kanthi ora apik amarga berorientasi buffer, ora berorientasi stream kaya IO .

Wektu eksekusi ing milidetik: 12

Lan ayo uga nyoba kanggo Java NIO.2 . NIO.2 wis nambah manajemen file dibandhingake karo Java NIO . Pramila perpustakaan sing dianyari ngasilake asil sing beda-beda:

Wektu eksekusi ing milidetik: 3

Saiki ayo nyoba kanggo nyoba file gedhe kita, video 521 MB. Tugas bakal persis padha: nyalin file menyang folder liyane. Delengen!

Asil kanggo Java IO :

Wektu eksekusi ing milidetik: 1866

Lan iki minangka asil kanggo Java NIO :

Wektu eksekusi ing milidetik: 205

Java NIO nangani file 9 kaping luwih cepet ing test pisanan. Tes sing bola-bali nuduhake asil sing padha.

Lan kita uga bakal nyoba tes ing Java NIO.2 :

Wektu eksekusi ing milidetik: 360

Apa asil iki? Mung amarga ora ana gunane kanggo mbandhingake kinerja ing antarane, amarga tujuane beda. NIO luwih abstrak I / O tingkat kurang, nalika NIO.2 oriented menyang manajemen file.

Ringkesan

Kita bisa kanthi aman ujar manawa Java NIO luwih efisien nalika nggarap file amarga bisa digunakake ing blok. Plus liyane yaiku perpustakaan NIO dipérang dadi rong bagéan: siji kanggo nggarap file, liyane kanggo nggarap jaringan.

API anyar Java NIO.2 kanggo nggarap file nawakake akeh fitur migunani:

  • sistem file sing luwih migunani nggunakake Path ,

  • nangani file ZIP kanthi nyata nggunakake panyedhiya sistem file khusus,

  • akses menyang atribut file khusus,

  • akeh cara sing trep, kayata maca kabeh file kanthi statement siji, nyalin file kanthi statement siji, lsp.

Iku kabeh babagan file lan sistem file, lan kabeh iku cukup dhuwur.

Kasunyatane saiki yaiku Java NIO nduwe kira-kira 80-90% karya karo file, sanajan pangsa Java IO isih signifikan.

💡 PS Tes iki ditindakake ing MacBook Pro 14" 16/512. Asil tes bisa beda-beda adhedhasar sistem operasi lan spesifikasi stasiun kerja.