day01、I/O流
I:input 输入(读取)
O:output 输出(写入)
流:数据(字符,字节)1个字符=2个字节=8个二进制位
- 输入:把硬盘中的数据读取到内存中使用
- 输出:把内存中的数据写入到硬盘中保存
java.io.OutputStream:字节输出流
* 此抽象类是输出字节流的所有类的父类超类
* 定义了一些成员方法
* public void close():关闭此输出流并释放与此流相关联的任何系统资源。
* public void flush():刷新此输出流并强制任何缓冲的输出字节被写出。
* public void write(byte[] b) :将 b.length字节从指定的字节数组写入此输出流。
* 重点 public void write(byte[] b, int off, int len) :从指定的字节数组写入 len个字节,从偏移 off开始输出到此输出流。
具体使用I\O
客户端
1.连接服务器Socket
2.发送消息
//客户端
public class TcpClientDemo01 {
public static void main(String[] args) {
Socket socket=null;
OutputStream os=null;
try {//1.要知道服务器的地址2.端口号
InetAddress serverIP = InetAddress.getByName("127.0.0.1");
int port = 9999;
//2.创建一个socket连接
socket = new Socket(serverIP,port);
//3.发送消息IO流
os = socket.getOutputStream();
os.write("nihao".getBytes());//通知是一个Byts的类型
} catch (Exception e) {
e.printStackTrace();
}finally {
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
服务器
1.建立服务的端口 ServletSocket
2.等待用户的连接 accept
3.接受用户的消息
//服务端
public class TcpServerDemo01 {
public static void main(String[] args) {
ServerSocket serverSocket=null;
Socket socket = null;
InputStream is=null;
ByteArrayOutputStream Baos=null;
try {//1.我得有一个地址
serverSocket = new ServerSocket(9999);
//2.等待客户端连接过来
socket = serverSocket.accept();//这个socket和Client中的Socket是一个对象可以获取到客户端的响应
//3.读取客户端的消息 也就是读取socket中的消息
is = socket.getInputStream();
//管道流
Baos = new ByteArrayOutputStream();//将客户端的数据流和服务器端的客户流用一个管道包裹起来实现IO流的数据交换
//创建缓冲区new byte[1024]创建一个长度为1024字节长的缓冲区来存放
byte[] buffer = new byte[1024];
int len;
while((len=is.read(buffer))!=-1){
Baos.write(buffer,0,len);//利用管道流将存储的数据输出出来 返回的类型是byte[]数组
}
System.out.println(Baos.toString());//将Baos中的byte[]数组转换为String类型
} catch (IOException e) {
e.printStackTrace();
}finally {
//关闭资源流先进后关,后进先关
if(Baos!=null){
try {
Baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(serverSocket!=null){
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
深入理解难点重点
//创建缓冲区new byte[1024]创建一个长度为1024字节长的缓冲区来存放
byte[] buffer = new byte[1024];
int len;
while((len=is.read(buffer))!=-1){
Baos.write(buffer,0,len);//利用管道流将存储的数据输出出来 返回的类型是byte[]数组
}
System.out.println(Baos.toString());//将Baos中的byte[]数组转换为String类
(len=is.read(buffer))!=-1 如何理解
is.read()是一个字节一个字节的读取is中的数据
而用buffer就可以将这些字节分为块来传输 如果数据有10000字节 那么就会分为10000/1000 + 1 =11个
为什么要+1呢:
流程
若我们下载一个文件,要在读取中不断的获取read()的返回值,判断何时-1,来表示读取完成。
read(buffer)如何读入?
如10000byte的文件下载,我们buffer长度1000,read(buffer)其实可以看做,是将文件分成【(10000除以1000 向上取整)+1 份】11份,其中最后一块其实就是个空的,用来判断文件读取完成。
传输文件
客户端
package com.you.lesson2;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
//接受文件
public class TcpServerDemo02 {
public static void main(String[] args) throws IOException {
//1.创建服务(端口)
ServerSocket serverSocket = new ServerSocket(9000);
//2.监听客户端的连接
Socket socket = serverSocket.accept();//阻塞式监听,一直会监听,客户端连接后停止
//3.获取数据流
InputStream is = socket.getInputStream();
//但是获取的数据是数据流最终要获取到一个文件 所以要把这个数据流输出成文件
FileOutputStream fos = new FileOutputStream(new File("receive.jpg"));
//设置缓冲区输出文件 重点反复理解
byte[] buffer = new byte[1024];
int len;
while ((len=is.read(buffer))!=-1){//重点 反复理解
fos.write(buffer,0,len);
}
//数据接受完毕之后给客户端一个响应 我好了
OutputStream os = socket.getOutputStream();
os.write("我好了你可以断开了".getBytes());
//断开连接
fos.close();
is.close();
socket.close();
serverSocket.close();
}
}
重难点理解:
//3.获取数据流
InputStream is = socket.getInputStream();
//但是获取的数据是数据流最终要获取到一个文件 所以要把这个数据流输出成文件
FileOutputStream fos = new FileOutputStream(new File("receive.jpg"));
这里用socket获取到了客户端传来的数据流
但是最终要获得的是一个文件而不是数据流
所以使用了new FileOutputStream()这样的一个管道流把数据流转换成文件也就是后面括号中的内容
//设置缓冲区输出文件 重点反复理解
byte[] buffer = new byte[1024];
int len;
while ((len=is.read(buffer))!=-1){//重点 反复理解
fos.write(buffer,0,len);
}
这里while循环体中为什么用fos而不是is
因为最终输出出来的只能是文件
在有管道层fos在 is就不能掉用write方法
只有fos可以调用
客户端
package com.you.lesson2;
import java.io.*;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
//文件传输客户端
public class TcpClientDemo02 {
public static void main(String[] args) throws IOException {
//1.获取ip地址
// InetAddress Inet = new InetAddress.getByName("127.0.0.1"); 会爆红错 待解决
//1.升级版直接建立socket连接
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9000);
//2.创建一个输出流
OutputStream os = socket.getOutputStream();
//3.获得文件流
// 先读取文件再把文件变成一个流再写出去
FileInputStream fls = new FileInputStream(new File("QQ截图20200405185041.png"));
//4.写出文件(设置一个缓冲区先把文件流保存起来再通过os写出去) 重点反复理解
byte[] buffer = new byte[1024];//设置缓冲区大小
int len;
while((len=fls.read(buffer))!=-1){
os.write(buffer,0,len);
}
//通知服务器 我已经发送完了
socket.shutdownOutput();//socket.shutdownOutput方法是关闭发送的信号 告诉服务器端已经传输完了
//确定服务器接受完事儿,关闭资源
InputStream is = socket.getInputStream();
//传过来的是一个Byte[]数组 所以我们用new 一个Byte数组来输出
ByteArrayOutputStream Baos = new ByteArrayOutputStream();
byte[] bufffer = new byte[1024];
int len2;
while ((len2=is.read(buffer))!=-1){
Baos.write(buffer,0,len2);
}
System.out.println(Baos.toString());
//5.关闭资源
Baos.close();
is.close();
fls.close();
os.close();
socket.close();
}
}
//1.获取ip地址
// InetAddress Inet = new InetAddress.getByName("127.0.0.1"); 会爆红错 待解决
//1.升级版直接建立socket连接
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9000);
升级版的建立socket连接。
今天IO学习心得
三次握手,4次挥手
-
三次握手:
- A:我要传送数据了
- B:好了我知道你要传送了
- A:传送
-
四次挥手:
-
A:我要结束了
-
B:我知道你要结束了
-
B:你真的要断开了吗
-
A:我真的要断开了
-
TCP传输数据的流程
客户端和服务端
客户端:
1.获取服务器的ip地址和端口 new InenAddress 升级版:new Socket(InetAddress.getByName(“127.0.0.1”), 9000)
2.获取数据流
2.1 直接发送信息
socket.GetOutputStream();//直接发送一个数据流
// 直接用os.write("xxx".GetByte[])发送信息
2.2 发送其他类型(文件等。。。)的信息
socket.InputStream();//先要获取文件的信息
//文件:
//3.获得文件流
// 先读取文件再把文件变成一个流再写出去
FileInputStream fls = new FileInputStream(new File("QQ截图20200405185041.png"));
//4.写出文件(设置一个缓冲区先把文件流保存起来再通过os写出去) 重点反复理解
//看最终需要的是什么 是字符就用os.write
byte[] buffer = new byte[1024];//设置缓冲区大小
int len;
while((len=fls.read(buffer))!=-1){
os.write(buffer,0,len);
}
3.将数据流转换成相应的类型(Byte[]数组,文件。。。。)
字节流:直接用os.write("xxx".GetByte[])//这一步也是将String类型的xxx转换为Byte[]类型的字节数组
文件:
FileInputStream fls = new FileInputStream(new File("QQ截图20200405185041.png"));
//new File将文件转化为FileInputString文件
4.关闭资源
原则 先开后关,后开先关
服务器端:
1.设定服务器的端口
ServerSocket serverSocket = new ServerSocket(9000); //new ServerSocket
2.获取客户端中的响应
Socket socket = serverSocket.accept();//serverSocker.accept()
3.与客户端类似但是相反的获取数据流
3.1 直接接受信息
socket.InputStream();//获取的数据要通过转码
ByteArrayOutputStream Baos = new ByteArrayOutputStream();//总之接受的一方需要设置一个管道层来转换
3.2 接受其他类型(文件等。。。)的信息
FileOutputStream fos = new FileOutputStream(new File("receive.jpg"));
//设置缓冲区输出文件 重点反复理解
byte[] buffer = new byte[1024];
int len;
while ((len=is.read(buffer))!=-1){//重点 反复理解
fos.write(buffer,0,len);//最终需要的是文件所以用fos.write
}