一、NIO流
NIO:主要是通过selector选择器管理所有的IO事件,服务端为例:首先需要serverSoketChannel.open();获得一个channel然后通过channel.configureBlocking(false);设置非阻塞再通过channel.socket();获取一个Serversocket,然后通过bing()绑定端口,后打开选择器 selector.open();通过channel.register(selector,key);注册通道。后通过selector.select();监听key.
NIO(同步非阻塞):面向缓冲区;
Java NIO 由以下几个核心部分组成:
- Buffers -- 缓冲区 :针对系统的缓冲区
- Channels -- 通道 : 类似于BIO里面的流
- Selectors -- 选择器
FileOutputStream fos = new FileOutputStream("test.txt");
FileChannel channel = fos.getChannel();
下面是JAVA NIO中的一些主要Channel的实现:
- FileChannel : 文件通道
- DatagramChannel : UDP通道
- SocketChannel : TCP客户端通道
- ServerSocketChannel : TCP 服务端通道
以下是Java NIO里关键的Buffer实现:
- ByteBuffer
- ShortBuffer
- IntBuffer
- LongBuffer
- FloatBuffer
- DoubleBuffer
- CharBuffer
创建缓冲区:ByteBuffer allocate = ByteBuffer.allocate(int a);
获得指针:allocate.position()
获得限制:allocate.limit()
获得容量:allocate.capacity()
写入数据:put(byte) or put(byte[])
反转:flip() ;反转此缓冲区:将指针初始化,限制为数据的长度
remaining()获取到指针与限制之间的元素数量
BIO是一个连接一个线程。
NIO是一个请求一个线程。
AIO是一个有效请求一个线程。
ByteBuffer buffer = ByteBuffer.allocateDirect(10);
System.out.println("获取指针位置:"+buffer.position());//0
System.out.println("获取限制位置:"+buffer.limit());//10
System.out.println("获取容量位置:"+buffer.capacity());//10
System.out.println("---------------------");
buffer.put("123456".getBytes());
System.out.println("获取指针位置:"+buffer.position());//6
System.out.println("获取限制位置:"+buffer.limit());//10
System.out.println("获取容量位置:"+buffer.capacity());//10
System.out.println("---------------------");
buffer.flip();//置反,指针归零,限制到原指针位置
System.out.println("获取指针位置:"+buffer.position());//0
System.out.println("获取限制位置:"+buffer.limit());//6
System.out.println("获取容量位置:"+buffer.capacity());//10
System.out.println("---------------------");
//读取 remaining()读取指针到限制的有效字节
for (int i = 0; i <buffer.remaining(); i++) {
System.out.print((char)buffer.get(i));
}
NIO拷贝文件的两种方式:创建BIO ==》 获取NIO通道 ==》 开辟缓冲区 ==》拷贝 ==》关流
1、BIO---FileInputStream
//一次性拷贝buffer
File file = new File("调音师.mkv");
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream("调音师-副本.mkv");
//通过BIO流的对象获取NIO流的通道
FileChannel rChannel = fis.getChannel();
FileChannel wChannel = fos.getChannel();
//开辟缓存区
ByteBuffer buffer = ByteBuffer.allocate(1024);
//拷贝
while(rChannel.read(buffer)!=-1) {
buffer.flip();
wChannel.write(buffer);
buffer.clear();
}
//关流
fis.close();
fos.close();
2、BIO--RandomAccessFile
//源文件
File file = new File("调音师.mkv");
long len = file.length();
//创建BIO
RandomAccessFile rRaf = new RandomAccessFile(file, "r");
RandomAccessFile wRaf = new RandomAccessFile("调音师-副本.mkv","rw");
//获取NIO的管道
FileChannel rChannel = rRaf.getChannel();
FileChannel wChannel = wRaf.getChannel();
//开辟缓冲区
MappedByteBuffer rMap = rChannel.map(MapMode.READ_ONLY, 0, len);
MappedByteBuffer wMap = wChannel.map(MapMode.READ_WRITE, 0, len);
//拷贝
for (int i = 0; i < len; i++) {
byte b = rMap.get(i);
wMap.put(b);
}
//关流
rRaf.close();
wRaf.close();
二、异常
异常可分为两大类:java.lang.Exception类与java.lang.Error类。这两个类均继承自java.lang.Throwable类。
IOException extends Exception
RuntimeException extends Exception
习惯上将Error与Exception类统称为异常类,但两者本质还是不同的。Error类专门用来处理严重影响程序运行的错误,可是通常程序设计者不会设计程序代码去捕捉这个错误,其原因在于即使捕捉到它,也无法给予适当的处理。
异常也称为例外,是在程序运行过程中发生的、会打断程序正常执行的事件。下面是几种常见的异常:
内存溢出的错误(OutOfMemoryError):创建对象,并存入集合中,此对象不会被释放资源
栈内存溢出(StackOverflowError):调用方法,就会在栈内开辟空间,死循环的调用方法,栈就会被装满
算术异常(ArithmeticException);
空指针异常(NullPointerException);没有给对象开辟内存空间时
找不到文件异常(FileNotFoundException);
运行时异常(RunntimeException)非受检性异常:那些程序员在编写程序的时,应该避免的异常(逻辑异常),编译器不要求强制处置的异常
类型转换异常(ClassCastException):(注意:下转型一定用instanceof判断)
下标越界异常(ArrayIndexOutOfBoundsException);
受检(checked)异常 --- 一般性异常:编译器要求必须处置的异常。指的是程序在运行时由于外界因素造成的一般性异常。
文件未找到的异常(FileNotFoundException)
IOException IO流的异常
ClassNotFoundException:类未找到异常
Java的异常处理机制也秉持着面向对象的基本思想。在Java中,所有的异常都是以类的类型存在。除了内置的异常类之外,Java也可以自定义异常类。此外,Java的异常处理机制也允许自定义抛出异常。
2.1为何需要异常处理
异常是在程序运行过程中发生的事件,比如算术异常,数组越界,文件找不到等,这些事件的发生将阻止程序的正常运行。为了加强程序的健壮性,在程序设计时,必须考虑到可能发生的异常事件,并作出相应的处理。
2.2异常的处理
异常发生后,Java便把这个异常抛出来,如果抛出来之后没有程序代码去捕捉它,程序便终止。如果加上捕捉异常的程序代码,则可针对不同的异常做妥善的处理,这种处理的方式称为异常处理。
try{
···要检查的代码块···
}catch(异常类 对象名称){
异常发生时的处理语句;
}finally{
一定会运行到的程序代码;
}
处理步骤:
- try程序块若是有异常发生,程序的运行便中断,并抛出“异常类所产生的对象”;
- 抛出的对象如果属于catch()括号内欲捕获的异常类,catch则会捕捉此异常,然后进到catch的块里继续运行。
- 无论try程序块是否捕捉到异常,或者捕捉到的异常是否catch()括号里的异常相同,最后一定会运行finally块里的程序代码。
在异常捕捉的过程中做了两个判断:第1个是try程序块是否有异常产生,第2个是产生的异常是否和catch()括号内捕捉的异常相同。
finally块是可以省略的。如果省略finally块不写,那么在catch()块运行结束后,程序将跳到try-catch块之后继续执行。
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("调音师.mkv");
fos = new FileOutputStream("调音师-副本.mkv");
byte[] b = new byte[1024];
int len;
while((len = fis.read(b))!=-1) {
fos.write(b, 0, len);
}
}catch(FileNotFoundException e){
System.out.println("文件未找到异常");
}catch(IOException e) {
System.out.println("IO流异常");
}finally {
if(fis!=null) {
try{
fis.close();
}catch(IOException e) {}
}
if(fos!=null) {
try{
fos.close();
}catch(IOException e) {}
}
}
以下方式不用主动关闭流
//执行完了try..catch..就自动关流
try (FileInputStream fis = new FileInputStream("调音师.mkv");
FileOutputStream fos = new FileOutputStream("调音师-副本.mkv")){
byte[] b = new byte[1024];
int len;
while((len = fis.read(b)) != -1){
fos.write(b, 0, len);
}
} catch (FileNotFoundException e) {
System.out.println("文件未找到异常");
} catch (IOException e) {
System.out.println("IO流异常");
}
出现多个异常的处理方式:
try {
System.out.println(10/0);
String str =null;
System.out.println(str.equals("xxx"));
}catch(ArithmeticException | NullPointerException e){
System.out.println("异常出现了");
}
2.3抛出异常
1.在程序中抛出异常
在程序抛出异常时,一定要用到throw这个关键词。
throw 异常类实例对象。throw语句必须使用new关键字来产生对象。
2.指定方法抛出异常
方法名称(参数...) throws 异常类1,异常类2,...
抛出的异常交给调用的方法去处理
2.4自定义异常类
所有可处理的异常类均继承自Exception类,所以自定义异常类也必须继承这个类。
class 异常名称 extends Exception
{
.....
}
//自定义异常类
public class MyException extends Exception{
private static final long serialVersionUID = 8123594069232603221L;
@Override
public String toString() {
return "除数不能为0的异常";
}
}
//手动抛异常,自定义异常类
Scanner scan = new Scanner(System.in);
int num1 = scan.nextInt();
int num2 = scan.nextInt();
try {
if(num2==0) {
throw new MyException();
}
}catch(MyException e) {
System.out.println(e);
num2=1;
}
System.out.println(num1/num2);