I/O 即输入(Input)/ 输出(Output)的缩写, java中用“流(stream)”来抽象表示这么一个写入写出的功能,封装成一个“类”,都放在java.io这个包里面。
Input指从外部读入数据到内存,例如,把文件从磁盘读取到内存,从网络读取数据到内存等等。
Output指把数据从内存输出到外部,例如,把数据从内存写入到文件,把数据从内存输出到网络等等。
IO流主要的分类方式有以下3种:
1)字节流,字符流
2)节点流和处理流
节点流直接操作数据读写
处理流就相当于在这个水管上面装了一些“控制阀门”,最终用户只要关心“阀门”具备的能力就行。
3)JAVA所有流
4)在诸多处理流中,有一个非常重要,那就是缓冲流。
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO读取次数,从而提高读写的效率。
字节输入流InputStream
主要方法:
read()
:从此输入流中读取一个数据字节。read(byte[] b)
:从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。read(byte[] b, int off, int len)
:从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。close()
:关闭此输入流并释放与该流关联的所有系统资源。字节输出流OutputStream
主要方法:
write(byte[] b)
:将 b.length 个字节从指定 byte 数组写入此文件输出流中。write(byte[] b, int off, int len)
:将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。write(int b)
:将指定字节写入此文件输出流。close()
:关闭此输入流并释放与该流关联的所有系统资源。字符输入流Reader
主要方法:
read()
:读取单个字符。read(char[] cbuf)
:将字符读入数组。read(char[] cbuf, int off, int len)
: 将字符读入数组的某一部分。read(CharBuffer target)
:试图将字符读入指定的字符缓冲区。flush()
:刷新该流的缓冲。close()
:关闭此流,但要先刷新它。字符输出流Writer
主要方法:
write(char[] cbuf)
:写入字符数组。write(char[] cbuf, int off, int len)
:写入字符数组的某一部分。write(int c)
:写入单个字符。write(String str)
:写入字符串。write(String str, int off, int len)
:写入字符串的某一部分。flush()
:刷新该流的缓冲。close()
:关闭此流,但要先刷新它。另外,字符缓冲流还有两个独特的方法:
BufferedWriter
类newLine()
:写入一个行分隔符。这个方法会自动适配所在系统的行分隔符。BufferedReader
类readLine()
:读取一个文本行。 String hello= new String( "hello word!");
byte[] byteArray= hello.getBytes();
try{
File file= new File( "d:/test.txt");
OutputStream os= new FileOutputStream( file);
os.write(byteArray);
os.close();
}catch(Exception e){
}
FileInputStream in = null;
try {
in =new FileInputStream("d:/test.txt");
}catch(FileNotFoundException e){
System.out.println("file is not found");
System.exit(-1);
}
try {
while ((b=in.read())!=-1) {
System.out.println((char)b);
}
in.close();
}catch(IOException e) {
System.out.println("IO异常,读取失败");
System.exit(-1);
}
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
try {
FileInputStream fis = new FileInputStream("d:\\test.txt");
FileOutputStream fos = new FileOutputStream("d:\\test2.txt");
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
byte[] b = new byte[1024];
int off=0;
while ((off=bis.read(b))>0) {
bos.write(b,0,off);
}
bis.close();
bos.close();
}catch (IOException e) {
e.printStackTrace();
}finally {
bis.close();
bos.close();
}
字节流可以转换成字符流,java.io包中提供的InputStreamReader类就可以实现
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new FileWriter("d:/test.txt"));
String line =null;
while ((line=br.readLine())!=null) {
if ("q".contentEquals(line)) {
break;
}
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
br.close();
try {
Person P=new Person("test",26);
FileOutputStream fos=new FileOutputStream("d:/test.txt");
ObjectOutputStream oos=new ObjectOutputStream(fos);
oos.writeObject(P);
oos.flush();
oos.close();
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}
FileInputStream fis=new FileInputStream("d:/test.txt");
ObjectInputStream ois=new ObjectInputStream(fis);
Person P2=(Person)ois.readObject();
System.out.println(P2.name+","+P2.age);
}
BIO在Java语言里是一种比较老的网络I/O模型,是同步阻塞IO,实现模型为一个连接就需要一个线程去处理。这种方式简单来说就是当有客户端来请求服务器时,服务器就会开启一个线程去处理这个请求,即使这个请求不干任何事情,这个线程都一直处于阻塞状态。
网络连接中-server:
public class server {
private static Socket socket=null;
public static void main(String[] args) {
try {
//绑定端口
ServerSocket serverSocket=new ServerSocket();
serverSocket.bind(new InetSocketAddress(8080));
while (true){
//等待连接 阻塞
System.out.println("等待连接");
socket = serverSocket.accept();
System.out.println("连接成功");
//连接成功后新开一个线程去处理这个连接
new Thread(new Runnable() {
@Override
public void run() {
byte[] bytes=new byte[1024];
try {
System.out.println("等待读取数据");
//等待读取数据 阻塞
int length=socket.getInputStream().read(bytes);
System.out.println(new String(bytes,0,length));
System.out.println("数据读取成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
网络连接中-client:
public class Client {
public static void main(String[] args) {
Socket socket= null;
try {
socket = new Socket("127.0.0.1",8080);
socket.getOutputStream().write("一条数据".getBytes());
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
BIO是阻塞的,最大的缺点就是资源的浪费。
在JDK1.4的时候,NIO出现。NIO则是非阻塞IO,NIO在获取连接或者请求时,即使没有取得连接和数据,也不会阻塞程序。NIO的服务器实现模式为一个线程可以处理多个请求(连接)。
NIO有几个知识点需要掌握,Channel(通道),Buffer(缓冲区), Selector(多路复用选择器)。
AIO是在JDK1.7中推出的新的IO方式--异步非阻塞IO,也被称为NIO2.0。AIO 采用订阅-通知模式:即应用程序向操作系统注册IO监听,然后继续做自己的事情。当操作系统发生IO事件,并且准备好数据后,在主动通知应用程序,触发相应的函数。
Java提供了四个异步通道:AsynchronousSocketChannel、AsynchronousServerSocketChannel、AsynchronousFileChannel、AsynchronousDatagramChannel。