目录
一、新建项目

二、IO流
1. 什么是IO流?
I 是 Input,O 是Output,也就是输入输出流。
当我们操作数据时,以内存为基准,把数据读取到内存中是输入,把数据从内存写入到硬盘是输出
2. IO的流向说明图解

图片来自哔哩哔哩黑马程序员
3. IO 流的分类
根据数据的流向可以分为:输入流和输出流
根据数据的类型可以分为:字节流和字符流
操作文件类型
字节流:以字节为单位,可以操作所有文件类型
字符流:以字符为单位,只能输入输出纯文本文件

4. 字节流
输出流
//1. 创建 FileOutputStream 对象,指定写入的文件路径。
FileOutputStream fos = new FileOutputStream("文件路径");
//2. 将字符串转换为字节数组并写入文件。
fos.write("hello".getBytes());
//3. 关闭输出流
fos.close();
字节输出流的细节
1.创建字节输出流的对象
- 参数是字符串表示的路径或者File文件对象都是可以的
- 如果文件不存在,就会创建一个新的文件,不过需要父级路径是正确的
- 如果文件已经存在,会覆盖原文件
2.写数据
是根据字节对应的ASCII码表
3.关闭数据流
追加
在创建字节输出流的对象的时候,第二个参数是打开追加
输入流
//1. 创建 FileInputStream 对象,指定读取的文件路径。
FileInputStream fis = new FileInputStream("文件路径");
//每次只会读取一个字节,读取出来的是int型,需要转成Char类型
System.out.println((char)fis.read());
//释放资源
fis.close();
字节输入流的细节
1. 创建对象
如果指定的路径文件不存在,会字节报错
2. 读取内容
一次只会读取一个字节,读取的是ASCII码表对应的数值
当读取指针指到末尾没有内容了,会返回-1
3. 释放资源
5. 练习
拷贝文件
当使用一个字节一个字节来读取数据,再写入数据的方式,速度比较慢
所以,可以定义一个数组,一次读取尽量把数组装满,一次写入整个数组的数量
FileInputStream fis = new FileInputStream(要读取的文件路径);
FileOutputStream fos = new FileOutputStream(要写入的文件路径);
//创建一个数组,用来一次读取多少字节
byte [] buf = new byte[1024*1024*10];
int b;
while ((b = fis.read(buf)) != -1) {
fos.write(buf, 0, b); //第一个参数表示将buf数组里的数据写入到文件里
} //第二个参数是从 0 索引开始,写入的字节数是 b
fis.close();
fos.close();
解读代码
fis.read(buf)用于从输入流中读取数据到缓冲区buf,返回值b表示实际读取到的数据字节数。当读取到的数据为-1时,表示输入流已经到达末尾,循环结束。
fos.write(buf, 0, b)则用于将缓冲区中的数据写入到输出流中,写入的字节数为b。
6. 字符流
输入流
//创建字符流对象
FileReader fr = new FileReader("要读取的文件路径");
int ch;
//字符流的底层也是字节流,默认也是一次读取一个字节
while ( (ch = fr.read() ) != -1){
System.out.print( (char) ch); //读取出来后会自动解码然后转成十进制
} //所以再转成字符就可以了
fr.close();
字符流读取的细节
- 字符流的底层也是字节流,默认也是按照一个字节一个字节读取的
- 遇到中文就会一次读取多个字节,这样可以避免乱码,编码不同,一次读取的字节也不同
- 在读取之后,底层会自动解码然后转成十进制数,然后把十进制数返回
- 返回的十进制数也是表示字符集上的数值, 如果需要看到汉字,那么就需要再转成字符就行了
字符输入流原理解析
1. 创建字符输入流对象
底层会关联文件,并且在内存里创建一个byte数组作为缓冲区,长度为8192字节的数组
2. 读取数据
底层: 1.判断缓冲区有没有数据可以读取
2.缓冲区没有数据:从文件里读取数据到缓冲区,尽量把缓冲区装满
如果文件里没有数据了,返回-1
3.缓冲区有数据:从缓冲区获取数据。
空参的read方法:一次读取一个字节,遇到中文一次读取多个字节(根据字符集),把字节解码后并且转成十进制数字返回
有参的read方法:把读取字节,解码,转成文字合并了,然后把文字放在数组里
字符输出流原理解析
创建字符输出流的对象的时候,在内存会创建一个缓冲区
有三种情况会把缓冲区的数据写入到文件里
- 当缓冲区存放满了的时候
- 手动刷新,flush刷新之后还可以继续写数据
- 释放资源
要学习 Tomcat ,就需要先了解什么是网络编程
创建两个类 一个作为客户端,一个作为服务器端

三、网络编程
1. UDP通信程序
- Java中的UDP通信
- UDP协议是一种不可靠的无连接的网络协议,它在通信的两端各建立一个Socket对象,但是这两个Socket只是发送,接收数据的对象,因此对于基于UDP协议的通信双方而言,没有所谓的客户端和服务器的概念
- Java提供了DatagramSocket类作为基于UDP协议的Socket
- 构造方法
| 方法名 | 说明 |
| DatagramSocket() | 创建数据报套接字并将其绑定到本机地址上的任何可用端口 |
| DatagramPacket(byte[] buf,int len,InetAddress add,int port) | 创建数据包,发送长度为len的数据包到指定主机的指定端口 |
- 相关方法
| 方法名 | 说明 |
| void send(DatagramPacket p) | 发送数据报包 |
| void close() | 关闭数据报套接字 |
| void receive(DatagramPacket p) | 从此套接字接受数据报包 |
UDP 发送数据
//创建发送端的Socket对象(DatagramSocket)
DatagramSocket ds = new DatagramSocket();
//创建数据,并把数据打包
//构造一个数据包,发送长度为 length 的数据包到指定IP上的指定端口号。
byte[] bys = "你好".getBytes();
DatagramPacket dp = new DatagramPacket(bys,bys.length,InetAddress.getByName("127.0.0.1"),8888);
//调用DatagramSocket对象的 send 方法发送数据
ds.send(dp);
//关闭通信通道
ds.close();
UDP 接收数据
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Server {
public static void main(String[] args) throws IOException {
// 创建一个DatagramSocket实例,绑定到8888端口,用于接收UDP数据包。
DatagramSocket ds = new DatagramSocket(8888);
// 创建一个大小为1024字节的字节数组,用于存储接收到的数据。
byte[] bytes = new byte[1024];
// 该实例用于接收UDP数据包。
DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
// receive方法接收来自任何发送者的数据包,并将其存储在dp中。
// 这个方法是阻塞的,直到接收到一个数据包。
ds.receive(dp);
// 获取接收到的数据包中的数据部分和长度。
byte[] data = dp.getData();
int length = dp.getLength();
// 将接收到的字节数据转换为字符串并打印。
// 字符串的起始位置是0,长度是数据包的实际长度。
// 这样可以确保只打印接收到的有效数据部分。
System.out.println(new String(data,0, length));
// 释放资源
ds.close();
}
}
测试

2. TCP 通信程序
- Java中的TCP通信
- Java对基于TCP协议的的网络提供了良好的封装,使用Socket对象来代表两端的通信端口,并通过Socket产生IO流来进行网络通信。
- Java为客户端提供了Socket类,为服务器端提供了ServerSocket类
TCP发送端
import java.io.IOException;
import java.io.OutputStream;
import java.net.*;
public class Client {
public static void main(String[] args) throws IOException {
//1.创建Socket对象
//细节:在创建对象的同时会连接服务端
// 如果连接不上,代码会报错
Socket socket = new Socket("127.0.0.1",8080);
//2.可以从连接通道中获取输出流
OutputStream os = socket.getOutputStream();
//写出数据
os.write("hello".getBytes());
//3.释放资源
os.close();
socket.close();
}
}
TCP 服务器端
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
// 创建一个ServerSocket对象,监听8888端口,等待客户端连接
ServerSocket ss = new ServerSocket(8080);
// 调用accept()方法阻塞等待,直到有客户端连接到服务器,返回一个Socket对象用于与该客户端通信
Socket socket = ss.accept();
System.out.println("客户端连接成功");
// 获取Socket对象的输入流,用于读取客户端发送的数据
InputStream is = socket.getInputStream();
// 定义一个整型变量b,用于存储读取到的字节
int b;
// 循环读取输入流中的数据,read()方法返回-1表示流已结束
while ((b = is.read()) != -1){
// 将读取到的字节转换为字符并输出
System.out.print((char)b);
}
// 关闭与客户端的连接
socket.close();
// 关闭连接通道
ss.close();
}
}
3. 解读代码
TCP 服务器端
accept方法是阻塞的,作用就是等待客户端连接- 客户端创建对象并连接服务器,此时是通过三次握手协议,保证跟服务器之间的连接
- 针对客户端来讲,是往外写的,所以是输出流,针对服务器来讲,是往里读的,所以是输入流
read方法也是阻塞的- 客户端在关流的时候,还多了一个往服务器写结束标记的动作,结束标记 -1
- 最后一步断开连接,通过四次挥手协议保证连接终止
Socket 套接字
Socket 套接字,作用就是用来实现网络上不同主机的应用程序进行双向通信。
套接字包括 IP 地址和端口号两个部分。
Socket 被用于应用层和传输层之间的通信。
Java 提供的 Socket 的类的核心功能就是 建立连接,发送数据,接收数据
Socket(InetAddress address,int port) 建立连接
getoutputStram() 发送数据
getInputStream() 接收数据
传输数据的类型
在网络中,数据传输的都是字节 byte,然后把字节放到字节数组里发送,这就是为什么在发送数据前要把数据转成字节
accept 方法
accept 方法用于接收来自客户端的连接请求。这个方法是阻塞的,也就是它会一直等待,直到有一个新的客户端连接才会继续往下执行
read 方法
read 方法是从当前建立的连接通道中读取字节,一次读取一个字节,所以使用循环读取数据。
read 方法也是阻塞的,这意味着它会一直等待直到有足够的数据可读,或者直到连接关闭。
那数据读取完了怎么结束等待呢?判断数据是否读取完,如果读取完,就停止循环
返回的 -1
当客户端主动关闭连接后会发送一个结束标志,服务端的 read 方法就会返回 -1 ,表示客户端关闭了连接
当读完数据时,read 方法会返回 -1 ,表示数据读取完毕
作业
1. 实现在线聊天室
可以使用TCP建立连接
张三发送:你好
李四发送:你好呀
2. 预习
网络通信三要素:IP、端口、协议
TCP、UDP,它们之间的区别是什么?
三次握手、四次挥手
HTTP 传输协议:请求协议,响应协议
进程和线程的关系
1288

被折叠的 条评论
为什么被折叠?



