1.IO流的分类
按流的方向划分:
输入流
输出流
按流的类型划分:
传统阻塞式IO----
对于读写操作,需要借助于线程来进行处理,读写过程中,线程必须处理完毕才能结束!
wait()等待 /read():读数据(字节:判断结果是否为-1,一直读取!)
非阻塞式IO: IO流的操作(读写某些文件的时候,开启线程)---将这些线程存储在线程池中
举例:
一个线程池1000个线程,使用完毕归还到线程池中
字节流
字节输入流:InputStream
FileInputStream:文件字节输入流
BufferedInputStream:字节缓冲输入流
字节输出流:OutputStream
FileOutputStream:文件字节输出流
BufferedOutputStream:字节缓冲输出流
字符流
字符输入流:Reader
InputStreamReader(InputStream in):字符转换输入流
使用平台默认解码的便捷类:
FileReader
BufferedReader:字符缓冲输入流
字符输出流:Writer
OutputStreamWriter(OutputStream out):字符转换输出流
FileWriter
BufferedWriter:字符缓冲输出流
2.字符流操作文本文件 读写复制操作有几种方式
使用基本的字符流:
InputStreamReader---->FileReader
OutputStreamWriter--->FileWriter
1)一次读取一个字符
2)一次读取一个字符数组
BufferedReader
BufferedWriter
1)一次读取一个字符
2)一次读取一个字符数组
3)一次读取一个文本行
String line = null ;
String readLine()--->阻塞式方法
while((line=字符缓冲输入流对象.readLine())!=null){
使用字符缓冲输出流对象.write(line) ;
字符缓冲输出流对象.newLine() ;
字符缓冲输出流对象.flush();
}
3.throws和throw的区别
throws:
1)跟在方法声明上,在方法的后面可以跟多个一次类名,中间逗号隔开
2)针对throws的异常处理,调用者必须进行显示处理
3)描述的可能性(执行某段代码可能出现有问题)
throw
1)用在方法体中使用
2)对于它的处理,通过方法体中逻辑代码进行处理
3)throw后面跟的是异常对象名:匿名对象 throw new XXXException() ;
执行某段代码,一定会抛出异常---交给jvm,将异常日志信息打印控制台上!
4.处理异常有几种方式
throws:抛出---抛出在方法上
try...catch...finally:捕获异常(开发中)
5.static关键字特点
1)随着类的加载而加载
2)优先于对象存在,不能this共存
3)可以被多个对象共用,共享
4)可以类名直接方法:无论这是变量/还是方法,只要被static修饰---都属于 "类成员"
Properties 继承自Hashtable<K,V>---->实现Map<K,V>接口
* 表示了一个持久的属性集
*
*Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
*
* 构造方法
* public Properties()
//Properties没有泛型,属于Map的一个子实现类
//使用Map接口的功能操作
//创建一个属性列表
Properties properties = new Properties() ;
//put
properties.put("张三",30) ;
properties.put("李四",40) ;
properties.put("王五",50) ;
properties.put("赵六",25) ;
//遍历:Map集合遍历方式: 推荐:keySet()
Set<Object> keySet = properties.keySet();
for(Object obj :keySet){
//通过键获取值
Object value = properties.get(obj);
System.out.println(obj+"---"+value);
}
}
}
关于属性集合类的特有功能:
* 添加方法
* public Object setProperty(String key,String value)
*
* 遍历:
* public Set<String> stringPropertyNames()
* 通过键获取值
* public String getProperty(String key)
public static void main(String[] args) {
//创建一个属性集合类
Properties prop = new Properties() ;
//添加
prop.setProperty("1","文章") ;
prop.setProperty("2","高圆圆") ;
prop.setProperty("3","马伊琍") ;
prop.setProperty("4","赵又廷") ;
prop.setProperty("4","王宝强") ;
//遍历
Set<String> keySet = prop.stringPropertyNames();
for(String key:keySet){
//通过键获取值
String value = prop.getProperty(key);
System.out.println(key+"---"+value);
}
}
}
关于属性集合类的应用;
* 1)因为键和值都是String,所以可能将键和值的保存在文本文件或者配置文件中 :加载过程
* public void load(Reader reader)throws IOException
* public void load(InputStream in)throws IOException
*
* 2)将属性集合类中的内容写出到某个文件中:保存过程
* public void store(OutputStream out,String comments) throws IOException
* 参数1:当前字节输出流
* 参数2:给当前属性列表中写入完毕之后,注释的内容
* public void store(Writer writer,String comments) throws IOException
* 将当前项目下的name.txt内容加载到属性集合类中
public class PropertiesDemo3 {
public static void main(String[] args) throws IOException {
// myLoad() ;
// mySotre() ;
}
//保存:将当前属性集合类中的内容,输出在某个文件中
private static void mySotre() throws IOException {
//创建一个属性列表
Properties prop = new Properties() ;
prop.setProperty("马伊琍","35") ;
prop.setProperty("文章","26") ;
prop.setProperty("姚笛","22") ;
prop.setProperty("王宝强","35") ;
prop.setProperty("马蓉","30") ;
//保存
prop.store(new FileWriter("userList.txt"),"name's list");
}
//加载:将name.txt内容加载到属性集合类中
private static void myLoad() throws IOException {
//创建一个属性集合类
Properties prop = new Properties() ;
System.out.println(prop);
//加载
//字符流
Reader r = new FileReader("name.txt") ;
prop.load(r);
//遍历
Set<String> keySet = prop.stringPropertyNames();
for (String key: keySet) {
String value = prop.getProperty(key) ;
System.out.println(key+"---"+value);
}
//System.out.println(prop);
}
}
如果我们的配置文件后缀名xx.properties
* * 操作步骤:
* * src目录下---->类路径
* * 将properties配置文件放置在src目录下
public static void main(String[] args) throws IOException {
//读取user.properties配置文件: src目录下
//1)需要获取当前类的字节码文件对象( PropertiesDemo4类中要使用配置文件)
/* Class clazz = PropertiesDemo4.class ;
//2)获取当前类的类加载器
//Class类的方法:getClassLoader()--->ClassLoader
ClassLoader classLoader = clazz.getClassLoader();
//public InputStream getResourceAsStream(String name) :传入当前配置文件-->获取当前配置资源
的输入流对象(推荐)
//public URL getResource(String name):传入配置文件名称-->获取当前配置文件的url地址
//通过类加载将配置文件的内容读取到了流中
InputStream inputStream = classLoader.getResourceAsStream("user.properties");
*/
//一步走
InputStream inputStream = PropertiesDemo4.class.getClassLoader().getResourceAsStream("user.properties");
//创建属性集合类中
Properties prop = new Properties() ;
prop.load(inputStream);
//System.out.println(prop);
Set<String> keySet = prop.stringPropertyNames();
for(String key:keySet){
System.out.println(key+"---"+prop.getProperty(key));
}
}
}
想通过程序的方式:获取本地计算机的这个ip字符串形式以及主机名称?
java.net.InetAddress:互联协议的ip地址!
一个具体类中,没有字段,没有构造方法,
那么这个类只有成员方法,成员方法里面存在静态功能,返回值是它本身!
单例模式:
Runtime
private static Runtime currentRuntime = new Runtime() ;
private Runtime(){}
public static Runtime getRuntime(){
return currentRuntime
}
public static InetAddress getByName(String host):给定主机名称,可以获取互联网ip地址对象!
参数:可以传递主机名称/ip地址名称
public String getHostAddress():获取ip地址字符串形式
public String getHostName():获取主机名称
public class InetAddressDemo {
public static void main(String[] args) throws UnknownHostException {
// InetAddress inetAddress = InetAddress.getByName("LAPTOP-BHL76J0S");
InetAddress inetAddress = InetAddress.getByName("10.12.152.131");
//获取ip地址字符串文本
String ip = inetAddress.getHostAddress();
System.out.println(ip);//10.12.152.129
//获取主机名称
String hostName = inetAddress.getHostName();
System.out.println(hostName);//LAPTOP-BHL76J0S
//LAPTOP-4IJ0OFL4
}
}
UDP协议发送端的实现步骤: (不需要建立连接通道,以"数据报包"的方式发送数据)
* DatagramSocket表示用来发送和接收"数据报包"的套接字
* * 1)创建发送端的Socket: DatagramSocket
* * public DatagramSocket() throws SocketException{}
* * 2) 创建 "数据报包"对象
* * public DatagramPacket(byte[] buf,int length,InetAddress address,int port)
* * 3)发送数据报包
* * public void send(DatagramPacket p) throws IOException
* *
* * 4)释放资源
* * close()关闭socket对象
public class SendDemo {
public static void main(String[] args) throws IOException {
//创建发送端的Socket: DatagramSocket
DatagramSocket ds = new DatagramSocket() ;
//创建 "数据报包"对象
// public DatagramPacket(byte[] buf,int length,InetAddress address,int port)
//参数1:包的数据--字节数组
//参数2:包的长度
//参数3:ip地址
//参数4:端口号
String messageStr = "hello,UDP,我来了" ;
byte[] bytes = messageStr.getBytes();
int length = bytes.length ;
InetAddress inetAddress = InetAddress.getByName("10" +
".12.152.129");
int port = 10086 ;
DatagramPacket dp = new DatagramPacket(bytes, length, inetAddress, port);
//3)发送数据
ds.send(dp);
System.out.println("当前数据已经发送...");
//4)释放资源
ds.close();
}
}
UDP协议接收端实现
*
* 1)创建接收端的Socket
* public DatagramSocket(int port) throws SocketException:绑定端口号
*
* 2)数据一个数据报包对象:DatagramPacket
* 接收容器
* public DatagramPacket(byte[] buf, int length) :获取的是缓冲区的数据(不是真实数据)
* 一般情况:byte[] bytes = new byte[1024] ; 自定义字节缓冲区
*
* 3)接收
* public void receive(DatagramPacket p):阻塞式方法:在接收数据之前,一直处于阻塞状态,直到
* 当前接收端监听客户端口号了
* 4) 获取缓冲区的传递的真实数据
* public byte[] getData():获取真实的字节数组
* public int getLength():获取实际长度
* 将获取的字节数据---->String(byte[] bytes,int offset,int length)
* 获取哪个发送端传递的数据:ip 文本形式:
* public InetAddress getAddress()
* IntegerAddss--->public String getHostAddress()
*
* 5)使用完毕,关闭接收端
*
*
* 接收端不能运行多次,否则出现异常了,端口号被占用!
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
System.out.println("接收端等待发送数据...");
//创建接收端的Socket
DatagramSocket ds = new DatagramSocket(10086) ;
// 接收容器:数据报包
//定义一个字节缓冲区
byte[] bytes = new byte[1024] ;
int length = bytes.length ;
DatagramPacket dp = new DatagramPacket(bytes,length) ;
//接收
ds.receive(dp);
System.out.println("已经获取发送数据准备解析...");
//解析真实数据
/*
* public byte[] getData():获取真实的字节数组
* public int getLength():获取实际长度*/
byte[] bytes2 = dp.getData();
int len = dp.getLength();
//获取ip地址
String ip = dp.getAddress().getHostAddress();
String receiveMsgStr = new String(bytes2,0,len) ;
System.out.println("data from " + ip +"and content is: "+receiveMsgStr);
//关闭资源
ds.close();
}
}
Udp接收端不断的接收数据,接收端一般不关闭(模拟真实场景)
udp发送端不断的键盘录入数据,当前录入是 "over/886",结束,接收端不断的接收数据!
* 键盘录入数据采用的是:BufferedReader的readLine()功能来操作
public class ReceiveDemo {
public static void main(String[] args) throws Exception{
try {
System.out.println("等待接收");
DatagramSocket ds =new DatagramSocket(10010) ;
while(true){
//创建接收端的Socket对象
//创建数据报包:接收容器
DatagramPacket dp = new DatagramPacket(new byte[1024],new byte[1024].length) ;
//接收
ds.receive(dp);
//准备解析真实数据
String str = new String(dp.getData(),0,dp.getLength()) ;
String ip = dp.getAddress().getHostAddress() ;
System.out.println("data from: "+ip+" and content is: "+str );
// ds.close(); //接收端不需要关闭
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}udp发送端不断的键盘录入数据,当前录入是 "over/886",结束,接收端不断的接收数据!
* 键盘录入数据采用的是:BufferedReader的readLine()功能来操作
*/
public class SendDemo {
public static void main(String[] args) {
//创建一个字符缓冲输入流
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
//创建一个送端的Socket对象
DatagramSocket ds = null ;
try {
ds = new DatagramSocket() ;
String line = null ;
while((line=br.readLine())!=null){
//自定义结束条件
if("886".equals(line)){
break ;
}
//创建数据报包
DatagramPacket dp = new DatagramPacket(
line.getBytes(),
line.getBytes().length,
InetAddress.getByName("10.12.152.129"),
10010);
ds.send(dp);
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(ds!=null){
ds.close();
}
}
}
}
如何使用udp方式在一个窗口下进行聊天
*
*
* 需要两条线程:发送端发消息的线程
* 接收端接收消息的线程
*
* 创建线程的方式:(除过线程池)
* 1)继承自Thread类
* 2)实现Runnable接口 ---> 能够多个线程占用的 内存空间(共享共用)
* 代理----静态代理模式
发送端的资源类
接收端的资源类对象
public class ChatRoom {
public static void main(String[] args) throws Exception{
//创建两端的Socket对象
//发送端:
DatagramSocket ds = new DatagramSocket() ;
//接收端
DatagramSocket ds2 = new DatagramSocket(12306) ;
//创建资源类对象
//发送端的资源类以及接收端端的子类
SendThread st = new SendThread(ds) ;
ReceiveThread rt = new ReceiveThread(ds2) ;
//创建线程对象
Thread t1 = new Thread(st) ;
Thread t2 = new Thread(rt) ;
t1.start();
t2.start();
}
}
发送端的资源类
*/
public class SendThread implements Runnable {
private DatagramSocket ds ;
public SendThread(DatagramSocket ds){
this.ds = ds ;
}
@Override
public void run() {
try {
//不断键盘录入数据
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
String line = null ;
while((line=br.readLine())!=null){
if("over".equals(line)){
break ;
}
//创建数据报包
DatagramPacket dp = new DatagramPacket(line.getBytes(),
line.getBytes().length,
InetAddress.getByName("10.12.152.129"),
12306);
//发送数据
ds.send(dp) ;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(ds!=null){
ds.close();
}
}
}
}
接收端的资源类对象
*/
public class ReceiveThread implements Runnable {
private DatagramSocket ds ;
public ReceiveThread(DatagramSocket ds){
this.ds = ds ;
}
@Override
public void run() {
try {
while(true){
//创建接收端的Socket对象
//创建数据报包:接收容器
DatagramPacket dp = new DatagramPacket(new byte[1024],new byte[1024].length) ;
//接收
ds.receive(dp);
//准备解析真实数据
String str = new String(dp.getData(),0,dp.getLength()) ;
String ip = dp.getAddress().getHostAddress() ;
System.out.println("data from: "+ip+" and content is: "+str );
}
} catch (Exception e) {
e.printStackTrace();
}
//接收不需要关闭
}
}
TCP/IP协议:客户端发送的过程
*
* 1)创建客户端的Socket
* public Socket(String host,int port) throws UnknownHostException,IOException
* 2)public OutputStream getOutputStream()throws IOException
* 获取当前客户端对象所在的通道内的输出流对象
* 3)使用当前通道内的字节输出流 写数据过去
* 4)释放资源
public class ClientDemo {
public static void main(String[] args) throws IOException {
//1)创建客户端的Socket
Socket socket = new Socket("10.12.152.129",6666) ;
//2)获取当前客户端对象所在的通道内的输出流对象
OutputStream outputStream = socket.getOutputStream();
//3)写数据
outputStream.write("hello,TCP,我来了".getBytes());
//4)释放资源
socket.close();
}
}
服务器端
* 1)创建服务器端的Socket :此类实现服务器套接字
* public ServerSocket(int port)
* throws IOException
* 2)监听客户端连接
* public Socket accept()
* throws IOException
*
* 3) 通过监听到的客户端对象 获取通道的输入流
* public InputStream getInputStream()
*
*
* 4)关闭资源
* 服务器端关闭
public class ServerSocketDemo {
public static void main(String[] args) throws IOException {
//创建服务器端的Socket
ServerSocket ss = new ServerSocket(6666) ; //一旦能成功,就立即建立通道
System.out.println("服务器正在等待连接...");
//2)监听并获取客户端的socket对象
Socket socket = ss.accept(); //阻塞式方法 如果没有监听到,一直等
//3)获取通道内的输入流
InputStream inputStream = socket.getInputStream();
//一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = inputStream.read(bytes);
String str = new String(bytes,0,len) ;
//通过监听到客户端的socket对象获取ip地址
String ip = socket.getInetAddress().getHostAddress();
System.out.println("data from :" +ip +" content is :"+str);
System.out.println("服务器端接收完毕...");
//释放资源
ss.close();
}
}
网络编程的三要素
ip地址:点分十进制法
私人地址:(C类)
回环地址:127.0.0.1
端口号:(360软件插件---可以查本机软件所有端口号)
0-65535:(0-1024暴露端口号)
mysql:3306
tomcat:8080
redis:
no-sql数据库:6375...
协议:tcp/udp协议
2.UDP发送端和接收端如何实现:操作步骤
发送端
1)创建DatagramSocket对象
DatagramSocket ds = new DatagramSocket() ;
2)创建数据报包对象
byte[] bytes = "hello,udp".getBytes() ;
int length = bytes.length;
DatagramPacket dp = new DatagramPacket(
bytes,//包数据
length,//包长度
InetAddress.getByName("10.12.152.129"),//绑定本机的ip地址对象
10086 //端口号
) ;
3)发送数据报包
ds.send(dp) ;
4)释放资源
ds.close() ;
接收端:
1)创建接收端的socket对象
DatagramSocket ds = new DatagramSocket(10086) ;
2)创建接收容器(数据报包)
byte[] bytes = new byte[1024] ;
int length = bytes.length ;
DatagramPacket dp = new DatagramPacket(bytes,length) ;
3)接收
ds.receive(dp) ;
4)解析真实数据
byte[] myBytes = dp.getData() ; //实际字节数组
//获取实际长度
int len = dp.getLength();
//转换成字符串内容
String str = new String(myBytes,0,len) ;
String ip = dp.getInetAddress().getHostAddress() ;
//输出发送端的ip以及发送的内容...
3.TCP发送端和接收端如何实现:操作步骤
TCP客户端
1)创建客户端的socket对象
Socket socket = new Socket("10.12.152.129",10010) ;
2)获取通道内的输出流对象(字节输出流)
OutputStream out = socket.getOutputStream() ;
3)写数据到通道内中
out.write("hello,TCP".getBytes()) ;
4)关闭资源
socket.close() ;
TCP服务器端:
1)创建服务器端的Socket对象
ServerSocket ss = new ServerSocket(10010) ;
2)侦听并获取所在的客户端对象
Socket socket = ss.accpet() ;//侦听前,该方法一直阻塞
3)获取通道内容输入流
InputStream in = socket.getInputStream() ;
4)读数据
byte[] bytes = new byte[1024] ;
int len = in.read(bytes) ;
5)获取客户端发送的确认字符
String str = new String(bytes,0,len) ;
String ip = socket.getInetAddress().getHostAddress() ;
//获取客户端地址ip以及发送内容
反馈---->
4.UDP和TCP的区别
1)是否是需要建立连接通道
UDP:属于无连接方式发送----> 数据报包的方式来发送(包报文...)
TCP:需要建立连接通道(需要三次握手)
2)是否可靠安全
UDP:属于不可靠连接,不安全,执行效率高
TCP:属于可靠连接,安全的,执行效率低
3)发送数据大小是否有限制
UDP:发送的数据大小限制
TCP:
最基本的字节流发送和读取,
可以支持数据无限制(占用内存比较大的数据:视频(大字节类型Blob:支持4G))
5.获取字节码文件的方式
三种
Object的getClass()
任意Java类型的class属性
Class.forName("包名.类名") ;
com.qf.io_01.FileOutputStreamDemo :一个类或者接口的全限定名称
com.qf.io_01.FileOutputStreamDemo