目录
一.了解IO
Java中的IO体系:在Java中I/0流操作的类很多,但是核心体系实际上就只有File、lnputStream、OutputStream、Reader、Writer.
IO流的分类
IO流的数据来源
1.网络
2.磁盘
//磁盘
FileInputStream fi = null; //创建管道
try {
fi = new FileInputStream("d:/111/123.txt"); //存放在磁盘中的文件
int i = 0;
//如果没有值 read()会返回-1
while ((i = fi.read()) != -1) {
System.out.print((char) i);
}
} catch (IOException e) {
e.printStackTrace();
}
3.内存
//内存
String str = "Hello Word"; //数据在内存中存放
ByteArrayInputStream bai = new ByteArrayInputStream(str.getBytes());
int i = 0;
//如果没有值 read()会返回-1
while ((i = bai.read()) != -1) {
System.out.print((char) i);
}
4.键盘
//键盘
//Scanner
InputStream is = System.in;
int i = 0;
//如果没有值 read()会返回-1
while ((i = is.read()) != -1) {
System.out.print((char) i);
}
}
注意:
流使用完成后一定要关闭!!
我们可以调用close方法手动关闭
也可以把流写在try(创建流){} catch(){}里JVM(java7)可以帮我们自动关闭流,前提是那个流实现了closeable接口
IO流的原理
为了安全,用户的进程不能直接操作底层的硬件,只能委派操作系统去执行。所以IO操作一定要借助内核去完成。
二.字节流
1.read方法加缓存数组
目的:减少磁盘IO
public class ReadBufferDemo {
public static void main(String[] args) {
FileInputStream fi = null; //创建管道
FileOutputStream fo = null;
try {
//存放在磁盘中的文件 "Hello World"
fi = new FileInputStream("d:/111/123.txt");
fo = new FileOutputStream("d:/111/123_cp.txt");
int i = 0;
//创建一个数组 相当于缓存 可以减少 磁盘IO的次数
byte[] buffer = new byte[3];
//buffer [][0][]->[H][e][l] ->[1][o][ ]->[w][o][r] ->[1][d][r]
while ((i = fi.read(buffer)) != -1) {
//在这个类例子中,原本需要和磁盘进行11次I0操作,我增加了buffer之后,只需要进行4次IO
System.out.println(new String(buffer,0,i));
}
} catch (IOException e) {
e.printStackTrace();
}
//关闭流
}
}
2.字节流解决乱码问题
因为中文在UTF-8中占3个字节 所以我们一个一个字节的取一定会乱码,所以我们一次全取出来在输出就可以解决乱码的问题
try(FileInputStream in = new FileInputStream(file);
FileOutputStream out = new FileOutputStream(cp_file)) {
int len = 0;
//因为中文在UTF-8中占3个字节 所以我们一个一个字节的取一定会乱码
byte[] buffer = new byte[1024];
while ((len = in.read(buffer)) != -1) {
System.out.println(new String(buffer,0,len));
}
}catch (Exception e) {
}
3.缓冲字节流
对比普通字节流和缓冲字节流复制文件test.zip大小约500000kb,所需时间的多少
public class BufferDemo1 {
//test.zip 大小500000kb
static File file = new File("d:/111/test.zip");
//普通字节流 加缓冲数组
static void in_cp(File file, File cp_file) {
try(FileInputStream in = new FileInputStream(file);
FileOutputStream out = new FileOutputStream(cp_file)) {
int len = 0;
byte[] buffer = new byte[1024];//设置缓存区大小为1024
while ((len = in.read(buffer)) != -1) {
//输出
out.write(buffer,0,len);
}
}catch (Exception e) {
}
}
//缓冲字节流
//普通字节流 加缓冲数组
static void bin_cp(File file, File cp_file) {
try(FileInputStream in = new FileInputStream(file);
FileOutputStream out = new FileOutputStream(cp_file);
BufferedInputStream bin = new BufferedInputStream(in);
BufferedOutputStream bout = new BufferedOutputStream(out)) {
int len = 0;
byte[] buffer = new byte[1024];
while ((len = bin.read(buffer)) != -1) {
//输出
bout.write(buffer,0,len);
}
}catch (Exception e) {
}
}
public static void main(String[] args) {
long star = System.currentTimeMillis();
//普通字节流
File cp1_file = new File("d:/111/test1.zip");
in_cp(file, cp1_file);
System.out.println("普通字节流花费时间"+(System.currentTimeMillis()-star));
long star2 = System.currentTimeMillis();
//缓冲字节流
File cp2_file = new File("d:/111/test2.zip");
bin_cp(file, cp2_file);
System.out.println("缓冲字节流花费时间"+(System.currentTimeMillis()-star2));
}
}
结果:
普通字节流花费时间8096
缓冲字节流花费时间1378
因为BufferedInputStream 底层 采用的缓存数组大小为8192
所以我想 试着把普通字节流的缓存数组 设为1024*8 发现他们的执行效率几乎相同
结果:
普通字节流花费时间1457
缓冲字节流花费时间1484
缓冲流的flush()方法的作用:
因为缓冲流的缓冲数组为1024*8,当我们write的时候,只有当缓冲区填满了的时候才会写入,所以为了防止数据没填满缓冲区导致数据没写入,我们可以用到这个flush()方法,顺便提一下close方法里也会调用一次flush相当于刷盘操作。
5.序列化和反序列化
ObjectOutputStream实现序列化对象
static void serialize(Object obj) {
//ObjectOutputStream实现对象的序列化
try(FileOutputStream fo = new FileOutputStream("d:/111/user");
ObjectOutputStream obo = new ObjectOutputStream(fo)) {
//把对象写入磁盘 相当于序列化
obo.writeObject(obj);
} catch (Exception e) {
}
System.out.println("序列化成功");
}
ObjectInputStream实现反序列化对象
static void deserialize(File file) {
try(FileInputStream fi = new FileInputStream(file);
ObjectInputStream obi = new ObjectInputStream(fi)) {
//把对象从磁盘读取 相当于反序列化
User user = (User) obi.readObject();
System.out.println("反序列化" + user);
} catch (Exception e) {
}
}
test
public static void main(String[] args) {
User user = new User("ws", 18);
//序列化对象
serialize(user);
//反序列化
deserialize(new File("d:/111/user"));
}
结果:
序列化成功
反序列化User{name='ws', age=18}
三.字符流
字符流体系与字节流相似,字符流中特别的就是字符转换流InputStreamRead,他是字节流转换字符流的桥梁,它还可以指定编码格式。
四.网络IO
1.Socket和ServerSocket
模拟客户端与服务端通信
ServerSoket
public class ServerSoketDemo {
final static int DEFAULT_PORT = 7486;
public static void main(String[] args) {
ServerSocket serverSocket = null;
try {
//创建一个监听
serverSocket = new ServerSocket(DEFAULT_PORT);
//等待客户端连接 accept()会阻塞 直到获取到客户端才会往下执行
Socket socket = serverSocket.accept();
System.out.println("客户端" + socket.getPort() +"已连接");
//获取字节输入流getInputStream();
//转换为缓存字符输入流
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String msg = null;
msg = br.readLine();
//接受客户端消息
System.out.println("客户端发送消息:" + msg);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter( socket.getOutputStream()));
//给客户端发送消息
bw.write("我收到你的消息啦~\n");
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
ClienSocket
public class ClienSocketDemo {
final static int DEFAULT_PORT = 7486;
public static void main(String[] args) {
try {
Socket socket = new Socket("localhost",DEFAULT_PORT);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write("我是客户端:clien-01\n");
bw.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String msg = br.readLine();
System.out.println(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果:
2.BIO阻塞IO
所以 传统的IO在网络的数据传输上有两部分的阻塞,一部分是连接阻塞,一部分是IO阻塞。
可以利用线程池对其进行优化
//创建线程池
private final ExecutorService executorService = Executors.newCachedThreadPool();
//创建监听
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
System.out.println("开启服务");
while(true) {
final Socket socket = serverSocket.accept(); //连接阻塞
System.out.println("客户端" + socket.getPort() +"已连接");
//把IO的逻辑交给多线程完成
executorService.execute(new ProcessorHandler(service, socket));
}
} catch (IOException e) {
e.printStackTrace();
}
//关闭serverSocket
2.基于Socket手写实现RPC框架
五.NIO(New IO)
简述:
NIO 从JDK1.4提出的,本意是New l0,它的出现为了弥补I0的不足,提供了更高效的方式,针对于网络IO,他还可以非阻塞的模式进行网络IO.