运维开发网

Java使用BIO和NIO进行文件操作对比代码示例

运维开发网 https://www.qedev.com 2020-12-27 01:20 出处:网络 作者: 玄同太子
什么是Java NIO? 同步非阻塞io模式,拿烧开水来说,NIO的做法是叫一个线程不断的轮询每个水壶的状态,看看是否有水壶的状态发生了改变,从而进行下一步的操作。

什么是Java NIO?

同步非阻塞io模式,拿烧开水来说,NIO的做法是叫一个线程不断的轮询每个水壶的状态,看看是否有水壶的状态发生了改变,从而进行下一步的操作。

Java NIO有三大组成部分:Buffer,Channel,Selector,通过事件驱动模式实现了什么时候有数据可读的问题。

什么是Java BIO?

同步阻塞IO模式,数据的读取写入必须阻塞在一个线程内等待其完成。这里使用那个经典的烧开水例子,这里假设一个烧开水的场景,有一排水壶在烧开水,BIO的工作模式就是, 叫一个线程停留在一个水壶那,直到这个水壶烧开,才去处理下一个水壶。但是实际上线程在等待水壶烧开的时间段什么都没有做。不知道io操作中什么时候有数据可读,所以一直是阻塞的模式。

1、读文件

package com.zhi.test;

import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * 文件读取,缓冲区大小(BF_SIZE)对NIO的性能影响特别大,对BIO无影响<br>
 * 10M的文件,BIO耗时87毫秒,NIO耗时68毫秒,Files.read耗时62毫秒
 * 
 * @author 张远志
 * @since 2020年5月9日19:20:49
 *
 */
public class FileRead {
  /**
   * 缓冲区大小
   */
  private static final int BF_SIZE = 1024;

  /**
   * 使用BIO读取文件
   * 
   * @param fileName 待读文件名
   * @return
   * @throws IOException
   */
  public static String bioRead(String fileName) throws IOException {
    long startTime = System.currentTimeMillis();
    try {
      FileReader reader = new FileReader(fileName);

      StringBuffer buf = new StringBuffer();
      char[] cbuf = new char[BF_SIZE];
      while (reader.read(cbuf) != -1) {
        buf.append(cbuf);
      }
      reader.close();
      return buf.toString();
    } finally {
      System.out.println("使用BIO读取文件耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");
    }
  }

  /**
   * 使用NIO读取文件
   * 
   * @param fileName 待读文件名
   * @return
   * @throws IOException
   */
  public static String nioRead1(String fileName) throws IOException {
    long startTime = System.currentTimeMillis();
    try {
      FileInputStream input = new FileInputStream(fileName);
      FileChannel channel = input.getChannel();

      CharsetDecoder decoder = Charset.defaultCharset().newDecoder();
      StringBuffer buf = new StringBuffer();
      CharBuffer cBuf = CharBuffer.allocate(BF_SIZE);
      ByteBuffer bBuf = ByteBuffer.allocate(BF_SIZE);
      while (channel.read(bBuf) != -1) {
        bBuf.flip();
        decoder.decode(bBuf, cBuf, false); // 解码,byte转char,最后一个参数非常关键
        bBuf.clear();
        buf.append(cBuf.array(), 0, cBuf.position());
        cBuf.compact(); // 压缩
      }
      input.close();
      return buf.toString();
    } finally {
      System.out.println("使用NIO读取文件耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");
    }
  }

  /**
   * 使用Files.read读取文件
   * 
   * @param fileName 待读文件名
   * @return
   * @throws IOException
   */
  public static String nioRead2(String fileName) throws IOException {
    long startTime = System.currentTimeMillis();
    try {
      byte[] byt = Files.readAllBytes(Paths.get(fileName));
      return new String(byt);
    } finally {
      System.out.println("使用Files.read读取文件耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");
    }
  }

  public static void main(String[] args) throws IOException {
    String fileName = "E:/source.txt";
    FileRead.bioRead(fileName);
    FileRead.nioRead1(fileName);
    FileRead.nioRead2(fileName);
  }
}

2、写文件

package com.zhi.test;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;

/**
 * 文件写<br>
 * 10M的数据,BIO耗时45毫秒,NIO耗时42毫秒,Files.write耗时24毫秒
 * 
 * @author 张远志
 * @since 2020年5月9日21:04:40
 *
 */
public class FileWrite {
  /**
   * 使用BIO进行文件写
   * 
   * @param fileName 文件名称
   * @param content 待写内存
   * @throws IOException
   */
  public static void bioWrite(String fileName, String content) throws IOException {
    long startTime = System.currentTimeMillis();
    try {
      FileWriter writer = new FileWriter(fileName);
      writer.write(content);
      writer.close();
    } finally {
      System.out.println("使用BIO写文件耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");
    }
  }

  /**
   * 使用NIO进行文件写
   * 
   * @param fileName 文件名称
   * @param content 待写内存
   * @throws IOException
   */
  public static void nioWrite1(String fileName, String content) throws IOException {
    long startTime = System.currentTimeMillis();
    try {
      FileOutputStream out = new FileOutputStream(fileName);
      FileChannel channel = out.getChannel();
      ByteBuffer buf = ByteBuffer.wrap(content.getBytes());
      channel.write(buf);
      out.close();
    } finally {
      System.out.println("使用NIO写文件耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");
    }
  }

  /**
   * 使用Files.write进行文件写
   * 
   * @param fileName 文件名称
   * @param content 待写内存
   * @throws IOException
   */
  public static void nioWrite2(String fileName, String content) throws IOException {
    long startTime = System.currentTimeMillis();
    try {
      File file = new File(fileName);
      if (!file.exists()) {
        file.createNewFile();
      }
      Files.write(file.toPath(), content.getBytes(), StandardOpenOption.WRITE);
    } finally {
      System.out.println("使用Files.write写文件耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");
    }
  }

  public static void main(String[] args) throws IOException {
    String content = FileRead.nioRead2("E:/source.txt");
    String target1 = "E:/target1.txt", target2 = "E:/target2.txt", target3 = "E:/target3.txt";
    FileWrite.bioWrite(target1, content);
    FileWrite.nioWrite1(target2, content);
    FileWrite.nioWrite2(target3, content);
  }
}

3、复制文件

package com.zhi.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * 文件复制<br>
 * 10M的文件,bio耗时56毫秒,nio耗时12毫秒,Files.copy耗时10毫秒
 * 
 * @author 张远志
 * @since 2020年5月9日17:18:01
 *
 */
public class FileCopy {
  /**
   * 使用BIO复制一个文件
   * 
   * @param target 源文件
   * @param source 目标文件
   * 
   * @throws IOException
   */
  public static void bioCopy(String source, String target) throws IOException {
    long startTime = System.currentTimeMillis();
    try {
      FileInputStream fin = new FileInputStream(source);
      FileOutputStream fout = new FileOutputStream(target);

      byte[] byt = new byte[1024];
      while (fin.read(byt) > -1) {
        fout.write(byt);
      }

      fin.close();
      fout.close();
    } finally {
      System.out.println("使用BIO复制文件耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");
    }
  }

  /**
   * 使用NIO复制一个文件
   * 
   * @param target 源文件
   * @param source 目标文件
   * 
   * @throws IOException
   */
  public static void nioCopy1(String source, String target) throws IOException {
    long startTime = System.currentTimeMillis();
    try {
      FileInputStream fin = new FileInputStream(source);
      FileChannel inChannel = fin.getChannel();
      FileOutputStream fout = new FileOutputStream(target);
      FileChannel outChannel = fout.getChannel();

      inChannel.transferTo(0, inChannel.size(), outChannel);

      fin.close();
      fout.close();
    } finally {
      System.out.println("使用NIO复制文件耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");
    }
  }

  /**
   * 使用Files.copy复制一个文件
   * 
   * @param target 源文件
   * @param source 目标文件
   * 
   * @throws IOException
   */
  public static void nioCopy2(String source, String target) throws IOException {
    long startTime = System.currentTimeMillis();
    try {
      File file = new File(target);
      if (file.exists()) {
        file.delete();
      }
      Files.copy(Paths.get(source), file.toPath());
    } finally {
      System.out.println("使用Files.copy复制文件耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");
    }
  }

  public static void main(String[] args) throws IOException {
    String source = "E:/source.txt";
    String target1 = "E:/target1.txt", target2 = "E:/target2.txt", target3 = "E:/target3.txt";
    FileCopy.bioCopy(source, target1);
    FileCopy.nioCopy1(source, target2);
    FileCopy.nioCopy2(source, target3);
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

0

精彩评论

暂无评论...
验证码 换一张
取 消