IO总结

IO
NIO(non-blockinig)
特性:
Channels and Buffers(通道和缓冲区):标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。
Asynchronous IO(异步IO):Java NIO可以让你异步的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情。当数据被写入到缓冲区时,线程可以继续处理它。从缓冲区写入通道也类似。传统的IO是阻塞的。NIO是非阻塞的
Selectors(选择器):Java NIO引入了选择器的概念,选择器用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个的线程可以监听多个数据通道。
核心:
1. 通道(channel):Channel是一个对象,是双向的(所以更好的反映了底层操作系统的实现),可以通过它读取和写入数据。拿 NIO 与原来的 I/O 做个比较,通道就像是流。
通常我们调用write()方法来将缓冲区写入通道和read()方法来将通道的数组读取到缓冲区。
2. 缓冲区(buffer):在NIO库中。任何时候访问 NIO 中的数据,您都是将它放到缓冲区中。相当于一个中间层。缓冲区实质上是一个数组。也提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。
最常用的是ByteBuffer。但其实对于每一种基本的java类型都有一个对应的缓冲器类型。
ByteBuffer,CharBuffer,ShortBuffer,IntBuffer,LongBuffer,FloatBuffer,DoubleBuffer,
都是Buffer接口的实现。基本方法都一致,详情查看api文档。
一般的操作流程为:
FileInputStream inputStream = new FileInputStream(“F:\javaFile\789.txt”);// 得到一个文件数据源
FileChannel channel = inputStream.getChannel();// 得到一个通道。
ByteBuffer buffer = ByteBuffer.allocate(1024);// 创建一个1024长度的缓冲区
channel.read(buffer);//写入缓冲区
buffer.flip();翻转 ,写->读。主要是改变postion.limit等参数。
while (buffer.remaining()>0) {//还有元素
System.out.println((char)buffer.get());//get方法读取
}
缓冲区的状态变量和状态方法:
状态变量:跟踪他的状态和包含的数据
Position:跟踪写了多少数据,你读了三个数据。Position=3.指向数组中第四个元素。
Limit:limit 变量表明还有多少数据需要取出(在从缓冲区写入通道时),或者还有多少空间可以放入数据(在从通道读入缓冲区时)。position 总是小于或者等于 limit。
Capacity:最大数据容量。limit 决不能大于 capacity。
Clear()方法:重设缓冲区以便接收更多的字节。基本用作使buffer由读到写的状态。
1.它将 limit 设置为与 capacity 相同
2.它设置 position 为 0。
Flip()方法:Limilt设置与position(随着数据的写入不断增加)相同。Position设置为0.
使用get()和put()方法来读和写。还有很多的类型化的方法get() 和 put() 方法, ByteBuffer 还有用于读写不同类型的值的其他方法,如下所示:
getByte(),getChar(),putShort(),putInt()等
事实上,这其中的每个方法都有两种类型 ― 一种是相对的,另一种是绝对的。它们对于读取格式化的二进制数据(如图像文件的头部)很有用。
下面的内部循环概括了使用缓冲区将数据从输入通道拷贝到输出通道的过程。
while (true) {
buffer.clear();
int r = fcin.read( buffer );
if (r==-1) {
break;
}
buffer.flip();
fcout.write( buffer );
}
一般使用ByteBuffer buffer = ByteBuffer.allocate( 1024 );来创建缓冲区,指定大小的底层数组。
我们使用ByteBuffer buffer = ByteBuffer.allocateDirect( 1024 )创建直接缓冲区,Java 虚拟机将尽最大努力直接对它执行本机 I/O 操作。也就是说,它会在每一次调用底层操作系统的本机 I/O 操作之前(或之后),尝试避免将缓冲区的内容拷贝到一个中间缓冲区中(或者从一个中间缓冲区中拷贝数据)。
byte array[] = new byte[1024];
ByteBuffer buffer = ByteBuffer.wrap( array );//wrap方法把一个现有的数组包装成缓冲区。什么样的数组包装成什么样的缓冲区。
Slice()分片。将一个缓冲区分出一个子缓冲区。但是他们的数据是共享的。指向同一个底层数组。
调用缓冲区的 asReadOnlyBuffer() 方法,将任何常规缓冲区转换为只读缓冲区。

文件映射到内存:内存映射文件 I/O 是一种读和写文件数据的方法,它可以比常规的基于流或者基于通道的 I/O 快得多。现代操作系统一般根据需要将文件的部分映射为内存的部分,从而实现文件系统。Java 内存映射机制不过是在底层操作系统中可以采用这种机制时,提供了对该机制的访问。他的写入是危险的,可能会直接修改磁盘的文件。
将一个 FileChannel (它的全部或者部分)映射到内存中。为此我们将使用 FileChannel.map() 方法。下面代码行将文件的前 1024 个字节映射到内存中:
MappedByteBuffer mbb = fc.map( FileChannel.MapMode.READ_WRITE,
0, 1024 );
map() 方法返回一个 MappedByteBuffer,它是 ByteBuffer 的子类。因此,您可以像使用其他任何 ByteBuffer 一样使用新映射的缓冲区,操作系统会在需要时负责执行映射。

分散和聚集:使用多个而不是单个缓冲区来保存数据的读写方法。创建和操作缓冲区数组。

文件锁定:同步访问某个资源作为共享资源的文件。
通过调用filechannel上的trylock()非阻塞的或者lock()阻塞的,就可以获得整个文件的FileLock()。release()可以释放锁。代码:
RandomAccessFile raf = new RandomAccessFile( “usefilelocks.txt”, “rw” );
FileChannel fc = raf.getChannel();
FileLock lock = fc.lock( start, end, false );
释放锁:lock.release();
NIO的强大功能部分来自于Channel的非阻塞特性。
SocketChannel的用法。
1,打开SocketChannel:
socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress(“10.10.195.115”,8080));
2.关闭:socketChannel.close();
读取数据: buffer.clear();
buffer.put(info.getBytes());
buffer.flip();
while(buffer.hasRemaining()){
System.out.println(buffer);
socketChannel.write(buffer);
}
注意SocketChannel.write()方法的调用是在一个while循环中的。write()方法无法保证能写多少字节到SocketChannel。所以,我们重复调用write()直到Buffer没有要写的字节为止。
非阻塞模式下,read()方法在尚未读取到任何数据时可能就返回了。所以需要关注它的int返回值,它会告诉你读取了多少字节。

  1. Selectors(选择器):异步 I/O 中的核心对象名为 Selector。
    使用NIO中非阻塞IO编写服务器处理程序,有三个步骤
    1.向Selector对象注册感兴趣的事件
    2.从Selector中获取感兴趣的事件
    3.根据不同事件进行相应的处理
    流程:
    Selector sel = Selector.open();// 创建Selector对象

// 创建可选择通道,并配置为非阻塞模式
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);

// 绑定通道到指定端口
ServerSocket socket = server.socket();
InetSocketAddress address = new InetSocketAddress(port);
socket.bind(address);

// 向Selector中注册感兴趣的事件
server.register(sel, SelectionKey.OP_ACCEPT);
return sel;

BIO(传统IO)
其实在底层早就是用的NIO来实现的。
Java.io包中
结构图:
在这里插入图片描述
文件的属性和基本操作;
1.文件操作(file)表示文件和文件夹
1.路径分隔符
在window和linux平台文件路径分隔符有区别
在JAVA中\表示转义
win:\和/ 目录分割 ;分号属性分割 不区分大小写
unix: /目录分割 :冒号属性分割 区分大小写
我们以后在写文件路径的时候:
1.直接写“/”因为两个平台都适用 “c://java.a.txt”
2.用java给出的常量来拼“c:”+java.io.File.separator+“java”
2.文件file类中的方法
创建:
File file1=new File(“F:/javaFile/123.txt”);//第一种 路径
File file2=new File(“F:/javaFile”,“123.txt”);//第二种 上次路径加文件名
File file3=new File(“F:/javaFile”);
File file4=new File(file3,“123.txt”);//第三种
在很多的方法,可以查阅api文档
File file1=new File(“F:/javaFile/123.txt”);//创建
System.out.println(file1.getAbsolutePath());//文件绝对路径
System.out.println(file1.getName());//文件名
System.out.println(file1.getParent());//上级文件
System.out.println(file1.canExecute());//是否可执行 可以打开就是可执行
System.out.println(file1.canRead());//是否可读
System.out.println(file1.canWrite());//是否可写
System.out.println(file1.length());//文件大小
列出目录下的所有文件:
在这里插入图片描述
文件过滤器:
在这里插入图片描述
4. IO流 的分类和操作模板。
字符流:但实际中很多的数据是文本,又提出了字符流的概念,它是按虚拟机的encode来处理,也就是要进行字符集的转化。转化之后再来处理。
字节流:字节流是最基本的,要用在处理二进制数据,它是按字节来处理的。
在这里插入图片描述

四大基类:

在这里插入图片描述
四大基本流(字节输入流,字节输出流,字符输入流。字符输出流)都是抽象类
其他的都是继承于他们的,我们只能创建其子类对象。
在这里插入图片描述

  1. 文件流
    FileOutputStream:文件字节输出流
    我们输出空行用write(‘\n’) 换行
    在这里插入图片描述
    FileInputStream:文件字节输入流
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述

我们在使用字节流操作汉字或者特殊的字符的符号语言的时候容易乱码,建议使用字符流。
先有字节流,再有字符流,字符流是对字节流的补充。
一般操作二进制文件(图片,音频,视频)等用字节流
操作文本文件用字符流。
FileWriter:文件的字符输出流
FileReader:文件的字符输入流
编码和解码:
编码:字符串传化成byte数组
解码:byte数组转化为字符串。
编码和解码的方式要相同。
在这里插入图片描述

存储字母和汉字都占一个字节
存储汉字:gbk家族 两个字节;utf-8 三个字节。
我们都是用utf-8
2. 包装流:装饰设计模式
前面我们所说的文件流(FileInputStream)就是液体个节点流。操作比较复杂,功能少。
包装流:包装了节点流。对节点流的增强。关闭的时候只需要关闭外面的流就ok
3. 缓冲流:
比节点流性能更加强大
是一个包装流。起缓冲作用
BufferedInputStream:
BufferedOutputStream:
BufferedReader:
BufferedWriter:
我们在操作流的时候,我们习惯定义了一个byte数组。我么每次直接从磁盘读取。性能很低。所以缓冲流就是定义了一个byte[] buffer=new byte[1024] 数组缓冲区。一次性从磁盘读取8kb的数据。
4. 转换流:
只有字节流转换成字符流,没有字符转字节:
InputStreamReader:字节输入流传化成字符输入流
OutputStreamWriter:字节输出流转化成字符输出流
字节流可以操作一切文件。字符流操作纯文本文件,是对字节流的增强。
5. 数组(内存)流:适配器设计模式

  1. 字节数组流
    ByteArrayOutputStream:输出到内存数组中 程序到内存数组
    ByteArrayInputStream:输入到程序 内存数组到程序

  2. 字符数组流:
    CharArrayOutputStream:
    CharArrayInputStream:

  3. 字符串流:
    把数据临时存储在字符串中
    StringReader:字符串输入流
    StringWriter: 字符串输出流

  4. 合并(顺序)流
    SequenceInputStream:将两个或多个流合并依此读出。

  5. 对象流
    在这里插入图片描述
    ObjectInputStream:反序列化操作
    ObjectOutputStream:序列化操作
    在这里插入图片描述
    细节和版本问题:

  6. 如果其中某些数据(密码)等不做序列化。
    在对应字段上加上transient修饰。该字段不做序列化。

  7. 反序列化是,java必须提供该对象的class文件,随着项目的升级。系统的class文件会发生变化(字段修改),如何保证两个class文件的兼容性?
    如果不显示serialVersionID类变量。该变量的值由jvm提供。而修改之后往往不同。从而造成不兼容反序列化失败。
    private static final long serialVersionUID = 1L;

  8. 打印流
    PrintStream:字节打印流
    PrintWriter:字符打印流
    刷新问题请注意:
    对于字节流 底层是没有缓存的,不需要刷新。
    对于字符流。注意刷新机制。
    使用打印流作为输出操作。此时输出操作特别简单。因为提供了很多的方法。可以打印各种数据类型。
    其实我们的system.out.println()中的system.out 这个其实就等价于一个PrintStream打印流对象。
    注意怎么使用格式化输出。System.out.printf(format,data);

  9. 标准的输输入输出:
    在这里插入图片描述

  10. 扫描器(scanner类)
    在这里插入图片描述
    加载properties文件:
    在这里插入图片描述
    9.数据流:
    提供了可以读写任意数据类型的方法;我们写入数据的文件会乱码。我们依照对应的方法读出就ok。
    DataOutputStream;提供了各种writexx方法
    DataInputStream:提供了各种readxxx方法。
    两种方法的类型必须对应起来。
    在这里插入图片描述
    RamdomAccessFile:随机文件访问。和前面的数据流差不多,但是可以是任意位置(调整文件指针的位置)进行读写。
    10.管道流:
    实现两个线程之间的通信。
    PipedInputStream:
    PipedOutputStream:
    PipedWrite:
    PipedReader:
    线程A将数据写入。B线程将数据读出。
    线程A:
    PipedOutputStream out=new PipedOutputStream();//创建
    Out.write();//写入数据
    线程B:
    PipedInputStream in=new PipedInputStream(out);//把上面的out对象传入创建in对象
    In.read();//读取数据
    11.NIO(new IO)
    Java.nio包中。
    JDK1.4开始的新的IO.可以把一块磁盘文件映射到内存中。我们再去读取内存中的数据。
    主要用于服务器中,对于我们代码依然使用传统的IO.
    在这里插入图片描述
    在jdk1.7的时候提供了NIO2.0.提供了异步的IO
    提供了Files(文件工具类)封装多种方法(递归,拷贝等)
    在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值