IO流NIO

Posted yimengxianzhi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IO流NIO相关的知识,希望对你有一定的参考价值。

IO流:

a、I是指Input(输入),O是指Output(输出)

b、在Java中,文件的输入输出是通过流来实现的,用来实现程序或进程间的通信,或读写外围设备,文件等

c、一个流,必有源端和目的端,它们可以是计算机内存的某区域,也可以是磁盘文件,甚至可以是Internet上的某个URL,对于流而言,我们不用关心数据是如何传输的,只需要向源端输入数据,向目的端获取数据即可。

d、流按照处理数据的单位,可以分为字节流和字符流,按照流向分为输入流和输出流

 

字节流:用于操作字节为单位的二进制文件文件(音频 视频 图片 docx等,用记事本打开是乱码的文件一般就是字节流)

常用方法:

FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
        //输入流
    fileInputStream = new FileInputStream("C:/Java_Tools/image/hello.jpg");
    //输出流
        fileOutputStream = new FileOutputStream("C:/Java_Tools/hello.jpg");
    
    byte[] car = new byte[1024];
    int length = 0;
    
    //当读取数据为-1了,读取结束
    while((length=fileInputStream.read(car))!=-1){
        fileOutputStream.write(car,0,length);
    }
    
    //冲刷缓存
    fileOutputStream.flush();
} catch (Exception e) {
    e.printStackTrace();
}finally{
    
    if(fileInputStream!=null){
        try {
            fileInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    if(fileOutputStream!=null){
        try {
            fileOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
}    

 

字符流:将字节转换为2个字节的Unicode字符就有了字符流,用于操作字符文件(记事本等)

常用方法:

FileReader fileReader null;
FileWriter fileWriter = null;
try {
    //输入流
    fileReader = new FileReader("C:/Java_Tools/log.log");
    //输出流
        fileWriter = new FileWriter("C:/Java_Tools/image/log.log");
    
    char[] car = new char[1024];
    int length = 0;
    
    while((length=fileReader.read(car))!=-1){
        fileWriter.write(car,0,length);
    }
    fileWriter.flush();
    
} catch (Exception e) {
    e.printStackTrace();
}finally{
    
    if(fileReader!=null){
        try {
            fileReader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    if(fileWriter!=null){
        try {
            fileWriter.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
}

 

缓冲流——数据在复制过程中会从磁盘中获取,有一个缓冲区

缓冲字节流:实现字节为单位的二进制文件

输入流:BufferedInputStream

输出流:BufferedOutputStream

缓冲字符流:实现2个字节的字符文件

输入流:BufferedReader

输出流:BufferedWriter

 

转换流:由于文件自身编码方式和程序运行时使用的默认编码方式不一致,致使程序读取或输出字符文件时可能会出现乱码,这时可以使用字节流操作文件,然后再讲字节流转换成字符流

字节输入流——>字符输入流:InputStreamReader

字节输出流——>字符输出流:OutputStreamWriter

 

NIO(NEW IO):

NIO提供多路非阻塞式的高伸缩性网络I/O,从而提高了效率,NIO主要有三大核心组件:Channel、Buffer、Selector,重点介绍前两者

 

Buffer:Buffer是一个抽象类,Buffer类型变量对应的对象代表一块缓冲区,ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer和ShortBuffer类都是Buffer抽象类的子类,其中ByteBuffer最常用

常用方法:

a、static ByteBuffer allocate(int capacity):分配一个新的字节缓冲区

public class Test {
    public static void main(String[] args) {
            ByteBuffer bytebuffer=ByteBuffer.allocate(1024);
    }
}

b、int capacity() :返回此缓冲区的容量,实际上直接将capacity成员属性值返回。

public class Test {
    public static void main(String[] args) {
            ByteBuffer bytebuffer=ByteBuffer.allocate(1024);
            System.out.println(bytebuffer.capacity());
    }
}
//输出结果:1024

c、ByteBuffer put(byte b):将字节类型数据写入当前位置的缓冲区,然后position+1,位置从0开始

public class Test {
    public static void main(String[] args) {
            ByteBuffer bytebuffer=ByteBuffer.allocate(1024);
            byte a=3;
            bytebuffer.put(a);
    }
}

d、byte[] array() :将ByteBuffer类型的数据转为byte数组

public class Test {
    public static void main(String[] args) {
            ByteBuffer bytebuffer=ByteBuffer.allocate(1024);
            byte a=3;
            bytebuffer.put(a);
            byte[] bbuf=bytebuffer.array();
    }
}

e、int position():返回缓冲区当前位置,实际上直接将position成员属性值返回。

public class Test {
    public static void main(String[] args) {
            ByteBuffer bytebuffer=ByteBuffer.allocate(1024);
            System.out.println(bytebuffer.position());
            byte a=3;
            bytebuffer.put(a);
            System.out.println(bytebuffer.position());
    }
}
//输出结果:0   1

f、Buffer flip() :翻转缓冲区,将当前position值赋值给limit,并将position置零;这个方法主要防止在最后一次输出时,如果缓存区并未装满,则将position值赋值给limit即为当前缓冲区内数据量,一般搭配hasRemaining方法使用。如果没有limit属性而直接使用capacity,则会输出冗余数据。

源码分析:

技术图片

举例:

public class Test {
    public static void main(String[] args) {
            ByteBuffer bytebuffer=ByteBuffer.allocate(1024);
            bytebuffer.position();
            byte a=3;
            bytebuffer.put(a);
            bytebuffer.position();
            bytebuffer. flip();
            bytebuffer.position();
    }
}
//输出结果:0   1   0

g、byte get()读取缓冲区当前位置的字节,然后当前位置+1

public class Test {
    public static void main(String[] args) {
            ByteBuffer bytebuffer=ByteBuffer.allocate(1024);
            bytebuffer.position();
            byte a=3;
            bytebuffer.put(a);
            bytebuffer.position();
            bytebuffer. flip();
            bytebuffer.position();
            bytebuffer.get();
    }
}

h、boolean hasRemaining():在释放缓冲区时告诉您是否已经达到缓冲区的上界

源码分析:

技术图片

 

 

 举例:

public class Test {
    public static void main(String[] args) {
        ByteBuffer bytebuffer=ByteBuffer.allocate(1024);
        System.out.println(bytebuffer.position());
        byte a=3;
        bytebuffer.put(a);
        System.out.println(bytebuffer.position());
        System.out.println(bytebuffer.hasRemaining());
        bytebuffer. flip();
        bytebuffer.get();
        System.out.println(bytebuffer.position());
        System.out.println(bytebuffer.hasRemaining());
    }
}
//输出结果:0   1   true   1   false

i、Buffer clear():将缓冲区重置为空状态。它并不改变缓冲区中的任何数据元素,而是仅仅将上界值初始化为容量的值,并把位置设回0。

源码分析:

技术图片

 

 

 举例:

public class Test {
    public static void main(String[] args) {
        ByteBuffer bytebuffer=ByteBuffer.allocate(1024);
        bytebuffer.position();
        byte a=3;
        bytebuffer.put(a);
        bytebuffer.clear();
        System.out.println(bytebuffer.get());
        System.out.println(bytebuffer.position());
        System.out.println(bytebuffer.hasRemaining());
    }
}
//输出结果:3   1   true

 

 

Channel:一个接口,该接口类型变量指向的对象代表一个数据传输通道,Channel对象是面向缓冲区的:数据总是从通道读取到缓冲区(Buffer类型对象),或从缓冲区(Buffer类型对象)写入到通道中

常用方法:

a、FileChannel:从文件中读写数据。

b、DatagramChannel:通过UDP读写网络中的数据。

c、SocketChannel:通过TCP读写网络中的数据。

d、ServerSocketChannel:可以监听新进来的TCP连接,像Web服务器那样,对每一个新进来的连接都会创建一个SocketChannel。

public class Test {
    public static void main(String[] args) {
        try {
            FileInputStream fileInputStream=new FileInputStream("C:/Java_Tools/log.log");
            FileChannel inChannel=fileInputStream.getChannel();
            
            FileOutputStream fileOutputStream=new FileOutputStream("C:/Java_Tools/image/log.log");
            FileChannel ouChannel=fileOutputStream.getChannel();
            
            ByteBuffer byteBuffer= ByteBuffer.allocate(1024);
            while(inChannel.read(byteBuffer)!=-1) {
                byteBuffer.flip();
                ouChannel.write(byteBuffer);
                byteBuffer.clear();
            }    
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

以上是关于IO流NIO的主要内容,如果未能解决你的问题,请参考以下文章

java内存流:java.io.ByteArrayInputStreamjava.io.ByteArrayOutputStreamjava.io.CharArrayReaderjava.io(代码片段

IO流与NIO流

Java NIO和IO的主要差别

Java NIO和IO的区别

java缓冲字符字节输入输出流:java.io.BufferedReaderjava.io.BufferedWriterjava.io.BufferedInputStreamjava.io.(代码片段

用NIO实现http协议