NIO基础操作有哪些

发布时间:2021-10-20 14:38:02 作者:iii
来源:亿速云 阅读:158

这篇文章主要介绍“NIO基础操作有哪些”,在日常操作中,相信很多人在NIO基础操作有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”NIO基础操作有哪些”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

NIO

同步非阻塞

阻塞与非阻塞的区别:

Channel(通道)和Buffer(缓冲区)

与普通IO的不同和关系

通道的概念

通道是对原I/O包中的流的模拟。到任何目的地的所有数据都必须通过一个Channel对象(通道)。一个Buffer实质上就是一个容器对象。发送给一个通道的所有对象都必须首先放到缓冲区中;从通道中读取的任何数据都要读到缓冲区中

缓冲区的概念

ByteBuffer
CharBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer

选择器

Selector是多路复用器,用于同时检测多个通道的事件以实现异步I/O。

通过一个选择器来同时对多个套接字通道进行监听,当套接字通道有可用的事件的时候,通道改为可用状态,选择器就可以实现可用的状态。

工作原理

客户端-----》Channel-----》Selector------》keys--状态改变---》server

Buffer 缓冲区 Channel 通道 Selector 选择器

Server端创建ServerSocketChannel 有一个Selector多路复用器 轮询所有注册的通道,根据通道状态,执行相关操作

Client端创建SocketChannel 注册到Server端的Selector

buffer

ByteBuffer

有且仅有ByteBuffer(字节缓冲区)可以直接与通道交互。

public static void main(String[] args) {
        //生成FileChannel文件通道  FileChannel的操作--> 操作ByteBuffer用于读写,并独占式访问和锁定文件区域


        // 写入文件
        try(FileChannel fileChannel = new FileOutputStream(FILE).getChannel()){
            fileChannel.write(ByteBuffer.wrap("test".getBytes()));
        } catch (IOException e){
            throw new RuntimeException("写入文件失败",e);
        }
        // 在文件结尾写入
        try(FileChannel fileChannel = new RandomAccessFile(FILE,"rw").getChannel()){
            fileChannel.position(fileChannel.size());//移至文件结尾
            fileChannel.write(ByteBuffer.wrap("some".getBytes()));
        } catch (IOException e){
            throw new RuntimeException("写入文件结尾失败",e);
        }

        try(FileChannel fileChannel = new FileInputStream(FILE).getChannel();
            FileChannel out = new FileOutputStream("C:\\Users\\sinosoft\\Desktop\\copy.txt").getChannel()
        ){
            // 读取操作,需要调用allocate显示分配ByteBuffer
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            // read之后将数据放入缓冲区
            while (fileChannel.read(byteBuffer) != -1){
                byteBuffer.flip(); // 准备写入
                out.write(byteBuffer);
                byteBuffer.clear(); // 清空缓存区
            }
        } catch (IOException e){
            throw new RuntimeException("读取文件失败",e);
        }
    }
方法说明

rewind()方法是将position设置为缓冲区的开始位置

get()和put()都会修改position

get(int)和put(int)都不会修改position

mark()设置mark为当前position

flip()将写模式切换为读模式

public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }

内存映射文件

内存映射文件可以创建和修改那些因为太大而无法放入内存的文件。

RandomAccessFile tdat = new RandomAccessFile("test.dat", "rw");
MappedByteBuffer out = tdat.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, length);

或者
FileChannel fc = new FileInputStream(new File("temp.tmp")).getChannel();
IntBuffer ib = fc.map(FileChannel.MapMode.READ_ONLY,0, fc.size()).asIntBuffer();

映射文件访问比标准IO性能高很多

文件锁定

文件锁定可同步访问,文件锁对其他操作系统进程可见,因为java文件锁直接映射到本机操作系统锁定工具。

public class FileLockTest {
    private static final String FILE = "C:\\Users\\sinosoft\\Desktop\\剩余工作副本.txt";
    public static void main(String[] args) throws IOException, InterruptedException {
        FileChannel fileChannel = new FileOutputStream(FILE).getChannel();

        // 文件锁
        FileLock fileLock = fileChannel.tryLock();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                FileChannel fileChannel = null;
                try {
                    fileChannel = new FileOutputStream(FILE).getChannel();
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
                ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                byteBuffer.put("aqws".getBytes());
                try {
                    System.out.println("线程准备写");
                    fileChannel.write(byteBuffer);
                    System.out.println("线程写完");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        if(fileLock != null){
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            byteBuffer.put("aqwqdqdhwfwihfejfhi".getBytes());
            System.out.println("主线程睡眠");
            Thread.sleep(10000);
            // 会报错 java.nio.channels.NonWritableChannelException
//            fileChannel.read(byteBuffer);
            System.out.println("主线程准备写");
            fileChannel.write(byteBuffer);
            fileLock.release();
        }
    }
}



主线程睡眠
线程准备写
java.io.IOException: 另一个程序已锁定文件的一部分,进程无法访问。
	at sun.nio.ch.FileDispatcherImpl.write0(Native Method)
	at sun.nio.ch.FileDispatcherImpl.write(FileDispatcherImpl.java:75)
	at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
	at sun.nio.ch.IOUtil.write(IOUtil.java:65)
	at sun.nio.ch.FileChannelImpl.write(FileChannelImpl.java:211)
	at com.zhanghe.study.io.nio.FileLockTest$1.run(FileLockTest.java:35)
	at java.lang.Thread.run(Thread.java:745)
主线程准备写

通过调用FileChannel上的tryLock或lock,可以获得整个文件的FileLock(SocketChannel、DatagramChannel和ServerSocketChannel不需要锁定,因为本质上就是单线程实体)

tryLock()是非阻塞的,试图获取锁,若不能获取,只是从方法调用返回

lock()会阻塞,直到获得锁,或者调用lock()的线程中断,或者调用lock()方法的通道关闭。

使用FileLock.release()释放锁

// 锁定文件的一部分,锁住size-position区域。第三个参数指定是否共享此锁
tryLock(long position, long size, boolean shared)

到此,关于“NIO基础操作有哪些”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

推荐阅读:
  1. Oracle基础操作有哪些
  2. jQuery基础操作有哪些

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:怎么用Lua编写猜数字游戏

下一篇:如何使用单机信息收集

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》