I/O流
IO流的分类:
InputStreamReader:转换流:把字节流转换成字符流,字符流使用更加方便。并且可以指定编码格式。
案例:读取文件
// 文件中内容为Hello World
public static void main(String[] args) {
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream("E:/test.txt");
int i = 0;
// 终止符号:i=fileInputStream.read(),读取一个字节数据
// 该方法效率低,读取一个字符就要和磁盘进行交互。
while ( (i=fileInputStream.read()) != -1 ) {
System.out.print((char) i);// ASCII码
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
fileInputStream.close();
}
}
一、IO流数据来源及操作的API
IO流的来源
// 1. 磁盘IO
FileInputStream fileInputStream = new FileInputStream("E:/test.txt");
// 2. 内存,字节数组
String str = "hello word";
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(str.getBytes());
// 3.键盘
// 4.网络(重点),不同的计算机之间进行通讯
Socket socket;
socket.getInputStream();
socket.getOutputStream();
二、本地磁盘文件操作(File)
File类是Java中为文件进行创建、删除、重命名、移动等操作而设计 的一个类。它是属于Java.io包下的类。
例子:
// 把字节流读取到一个缓存中,而没有使用缓冲流。
public static void main(String[] args) throws IOException{
File file = new File("E:/logo.png");
FileInputStream fileInputStream = new FileInputStream("E:/logo.png");
FileOutputStream fileOutputStream = new FileOutputStream("E:/logo_copy.png");
byte[] buffer = new byte[1024];// 占内存,不是越大越好
int len = 0;
while( (len=fileInputStream.read(buffer)) != -1 ) {
// 方法一:写道磁盘,读取一次和磁盘交互一次,效率低
fileOutputStream.write(len);
// 方法二:1024个字节交互一次,效率高
fileOutputStream.write(buffer, 0, len);
}
fileOutputStream.close();
fileInputStream.close();
}
自动关闭流,Java7的用法:将流放在try()中
流必须实现Closeable接口
OutputStream implements Closeable
public static void main(String[] args) throws IOException{
File file = new File("E:/logo.png");
try(
FileInputStream fileInputStream = new FileInputStream("E:/logo.png");
FileOutputStream fileOutputStream = new FileOutputStream("E:/logo_copy.png");
) {
byte[] buffer = new byte[1024];
int len = 0;
while( (len=fileInputStream.read(buffer)) != -1 ) {
// 方法一:写道磁盘,读取一次和磁盘交互一次,效率低
fileOutputStream.write(len);
// 方法二:1024个字节交互一次,效率高
fileOutputStream.write(buffer, 0, len);
}
}catch (Exception e) {
}
}
1 深入浅出read方法
三、基于缓冲流的输入输出流
缓冲流:
如果输出字符大小,没有达到默认缓冲区大小。那么需要手动触发输出到磁盘操作。flush()
public static void main(String[] args){
// 将[文件输出流]包装成 -> 缓冲输出流
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("E:/zhukai.txt"));
bufferedOutputStream.write("Hello World".getBytes());
// bufferedOutputStream.flush(); // 刷盘操作
bufferedOutputStream.close(); // 流关闭的时候,也会触发一个刷盘操作
}
四、基于文件的字符输入输出流实践
// 和字节流的读取没有太大的区别
public static void main(String[] args){
try(FileReader reader = new FileReader("E:/mic.txt")) {
int i = 0;
char[] bf = char[1024];
while( (i=reader.read(bf)) != -1 ) {
System.out.println(new String(bf, 0, i));
}
}catch (Exception e) {
}
}
1. 字符转换流(比较重要)
是字节流 —> 字符流的一个桥梁。
public static void main(String[] args){
try(InputStream is = new FileInputStream("E:/mic.txt")) {
InputStreamReader reader = new InputStreamReader(inputStream, "utf-8");
BufferedReader BufferedReader = new BufferedReader(reader);
// 转换流特有的方法
BufferedReader.readLine();
}catch(Exception e) {
}
}
五、序列化和反序列化,网络传输中使用,socket。
将内存对象,保存在本地磁盘当中:
ObjectOutputStream: 将内存对象写入到磁盘,该对象需要实现序列化接口,serialable.
在socket网络通信中,会用到ObjectOutputStream对象输入输出流。
六、网络IO
例子:
// 启动一个服务端
public static void main(String[] args){
final int DEFAULT_PORT = 8080;
ServerSocket serverSocket = null;
// 绑定一个监听端口
try {
serverSocket = new ServerSocket(DEFAULT_PORT);
// 这里是一个阻塞操作,等待客户端的链接。
Socket socket = serverSocket.accept();
System.out.print("客户端:" + socket.getPort() + "已连接");
// 1. 字符转换流InputStreamReader,字节到字符的转换:new InputStreamReader(socket.getInputStream())
// 2. 将字符流构建成一个字符缓冲流(更加高效)
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));//
String str= bufferedReader.readLine();// 获取客户端输入的一行信息
System.out.println("收到客户端的请求信息:" + str);
// 服务端也可以写出信息到输入端
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamReader(socket.getOutputStream());
bufferedWriter.write("我已经收到了消息!\n");
bufferedWriter.flush();
}catch(IOException e){
e.printStackTrace();
}finally {
bufferedReader.close();
bufferedWriter.close();
socket.close();
}
}
// 客户端
public static void main(String[] args){
final int DEFAULT_PORT = 8080;
Socket socket = new Socket("localhost", DEFAULT_PORT);
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamReader(socket.getOutputStream());
// 加\n是因为服务端要读一行数据,没有这个符号,服务端会认为一直在读一行,readLine方法会阻塞
bufferedWriter.write("我是客户端发送的消息!\n");
bufferedWriter.flush();
// 读取服务端的返回消息
BufferedReader BufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String str= BufferedReader.readLine();
System.out.println("收到服务端的信息:" + str);
}
1. 详解网络通信的底层原理
// 启动一个服务端
public static void main(String[] args){
final int DEFAULT_PORT = 8080;
ServerSocket serverSocket = null;
// 绑定一个监听端口
try {
serverSocket = new ServerSocket(DEFAULT_PORT);
ExecutorService executorService = Executors.newFixedThreadPool(4);
while(true) {
Socket socket = serverSocket.accept(); // 阻塞
executorService.submit(new ServerSocketThread(socket));// 异步的处理方式,线程池处理。
}
}catch(IOException e){
e.printStackTrace();
}finally {
流的关闭
}
}
public class ServerSocketThread implements Runnable{
Socket socket;
@Override
public void run() {
System.out.print("客户端:" + socket.getPort() + "已连接");
// 1. 转换流InputStreamReader,字节到字符的转换:new InputStreamReader(socket.getInputStream())
// 2. 将字符流构建成一个字符缓冲流(更加高效)
BufferedReader BufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));//
String str= BufferedReader.readLine();// 获取客户端输入的一行信息
System.out.println("收到客户端的请求信息:" + str);
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamReader(socket.getOutputStream());
bufferedWriter.write("我已经收到了消息!\n");
bufferedWriter.flush();
}
}
上面这中也是低效的,所以会引出NIO,对于服务器来说线程的数量毕竟是有限的。
七、Socket实现RPC通讯框架
7. 手写RPC框架:
1. 创建两个工程:
- rpc-server
- rpc-client
2. 工程rpc-server中创建两个模块:
右键工程rpc-server工程,new — module 创建模块
- rpc-server-api:是一个被公共依赖的包(接口要公共依赖)。
- rpc-server-provider:接口的实现,服务的实现可以部署在不同的计算机上面。
3. 整理工程目录
maven中分模块的构建方式:删除src目录
4. rpc-server-provider实现API的接口
- rpc-server-provider模块中,先引入rpc-server-api的依赖
- rpc-server-provider模块中,实现rpc-server-api的接口
5. server能够被client远程调用
- rpc-server-provider需要打包:
- rpc-server-provider:install到本地仓库
6. 工程rpc-client也需要依赖rpc-server-api
- rpc-client:引入接口依赖