文章目录
- 字符缓冲流
- 字符缓冲输出流 _Buffered和Writer
- 字符缓冲输入流
- 字符缓冲流练习
- 转换流
- 字符编码
- 字符集
- 转换流
- 转换流_OutputStreamWriter
- 序列流和反序列流的介绍
- 序列化流_ObjectOutputStream
- 反序列化_ObjectInputStream
- 不想被序列化操作
- 反序列化时出现的问题以及分析和解决
- 扩展(经验值)
- 打印流_PrintStream
- PrintStream打印流基本使用
- PrintStream打印流完成续写
- Properties集合
- Properties结合IO流使用方法
- Commons-io 工具包
- 添加第三方jar包
- 工具包的使用
- 网络结构
- 服务器概念
- 通信三要素
字符缓冲流
字符缓冲输出流 _Buffered和Writer
1.构造
BufferedWriter(Writer w)
Writer:抽象类,传递子类
2.方法:
和FileWriter一样
3.特有方法:
newLine() 换行
public class test01 {
public static void main(String[] args) throws IOException {
final BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("D:\\Ajava\\buffwri.txt"));
bufferedWriter.write("李云龙");
bufferedWriter.newLine(); //换行
bufferedWriter.write("丁伟");
bufferedWriter.newLine();
bufferedWriter.write("孔捷");
bufferedWriter.newLine();
bufferedWriter.write("消灭小日本");
bufferedWriter.newLine();
bufferedWriter.close();
}
}
字符缓冲输入流
1.构造:
BufferedReader(Reader r)
Reader:抽象类,需要传递子类对象
2.方法:
和FileReader一样
3.特有方法:
String readLine() 一把读一整行内容
public class test02 {
public static void main(String[] args) throws IOException {
final BufferedReader bufferedReader = new BufferedReader(new FileReader("D:\\Ajava\\buffwri.txt"));
/* System.out.println(bufferedReader.readLine());
System.out.println(bufferedReader.readLine());
System.out.println(bufferedReader.readLine());
System.out.println(bufferedReader.readLine());
System.out.println(bufferedReader.readLine());*/
//bufferedReader.close();
//定义一个字符串接收读出来的数据
String line;
while((line = bufferedReader.readLine())!=null){
System.out.println(line);
}
}
}
字符缓冲流练习
将文件中的内容排好序,写到另一个写文件中
步骤
1.创建BufferedReader用于读取文件中的内容
2.创建BufferedWriter用于将排好序的内容写到新文件中
3.创建ArrayList集合,用于存储读过来的内容
4.边读,边存
5.利用Collections中的sort方法,对ArrayList和集合进行排序
6.遍历集合,变遍历,边写
7.关流
public class test03 {
public static void main(String[] args) throws IOException {
final BufferedReader bufferedReader = new BufferedReader(new FileReader("D:\\Ajava\\buffwri.txt"));
final BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("D:\\Ajava\\buffwriso.txt"));
final ArrayList<String> list = new ArrayList<>();
String line;
while ((line = bufferedReader.readLine())!=null){
list.add(line);
}
//利用Collections中的sort方法,对集合进行排序
Collections.sort(list);
//遍历集合,边遍历,边写
for (String s : list) {
bufferedWriter.write(s);
bufferedWriter.newLine();
}
//关流
bufferedReader.close();
bufferedWriter.close();
}
}
转换流
字符编码
计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字,英文,标点符号,汉字等字符都是二进制数转换之后的结果。【按照某种规则,将字符存储到计算机中,称为”编码“】,反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为 解码
比如说,按照A规则存储,同样按照A规则解析,那么就能显示正确的文本f符号,反之按照A规则存储再按照B规则解析,就会出现乱码现象。
字符编码(Character Encoding):就是一套自然语言的字符和二进制数之间的对应规则
字符集
也叫编码表,是一个系统支持的所有字符的集合,包括各国家文字,符号标点,图形符号,数字等
计算机要准确的存储和识别各种字符集符号,需要进行字符编码
一套字符集必然至少有一套字符编码,常见的字符集有ASCII字符集,GBK字符集,Unicode字符集等
ASCII字符集 :
- ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)。
- 基本的ASCII字符集,使用7位(bits)表示一个字符,共128字符。ASCII的扩展字符集使用8位(bits)表示一个字符,共256字符,方便支持欧洲常用字符。
-ISO-8859-1字符集: - 拉丁码表,别名Latin-1,用于显示欧洲使用的语言,包括荷兰、丹麦、德语、意大利语、西班牙语等。
- ISO-8859-1使用单字节编码,兼容ASCII编码。
GBxxx字符集: - GB就是国标的意思,是为了显示中文而设计的一套字符集。
GB2312:简体中文码表。一个小于127的字符的意义与原来相同。但两个大于127的字符连在一起时,就表示一个汉字,这样大约可以组合了包含7000多个简体汉字,此外数学符号、罗马希腊的字母、日文的假名们都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。 - GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等。
- GB18030:最新的中文码表。收录汉字70244个,采用多字节编码,每个字可以由1个、2个或4个字节组成。支持中国国内少数民族的文字,同时支持繁体汉字以及日韩汉字等。
Unicode字符集 : - Unicode编码系统为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码。
- 它最多使用4个字节的数字来表达每个字母、符号,或者文字。有三种编码方案,UTF-8、UTF-16和UTF-32。最为常用的UTF-8编码。
- UTF-8编码,可以用来表示Unicode标准中任何字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。所以,我们开发Web应用,也要使用UTF-8编码。它使用一至四个字节为每个字符编码,编码规则:
- 128个US-ASCII字符,只需一个字节编码。
- 拉丁文等字符,需要二个字节编码。
- 大部分常用字(含中文),使用三个字节编码。
- 其他极少使用的Unicode辅助字符,使用四字节编码。
注意:
如何做到不乱码:编码和解码遵守一样的规则
GBK中一个中文占2个字节
UTF-8一个中文占3个字节
转换流
1.概述 字节流想字符流的桥梁
2.构造:InputStreamReader(InputStream in, String charsetName)
in:抽象类,传递子类对象
charsetName: 指定编码,不区分大小写
3.方法:和FileReader一样
public class test04 {
public static void main(String[] args) throws IOException {
final InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("D:\\Ajava\\buffwri.txt"),"gbk");
//一次读取一个字符
int read = inputStreamReader.read();
int read1 = inputStreamReader.read();
System.out.println((char) read);
System.out.println((char) read1);
inputStreamReader.close();
}
}
转换流_OutputStreamWriter
1.概述:字符流向字节流的桥梁
2.构造:
OutputStreamWriter(OutputStream out,String charsetName)
3.使用:和FileWriter一样
4.作用:可以按照指定编码存储数据
public class test05 {
public static void main(String[] args) throws IOException {
final OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("D:\\Ajava\\bian.txt"),"gbk");
outputStreamWriter.write("猪");
outputStreamWriter.close();
}
}
序列流和反序列流的介绍
作用:读写对象
将来我们new出来的对象中也携带了数据(属性值),我们可以将携带数据的对象存储到硬盘上,用的时候直接读出来
序列化流_ObjectOutputStream
1.作用:写对象
2.构造:
ObjectOutputStream(OutputStream out)
3.方法:
void writeObject(Object obj) ----- 写对象
4.注意:想要完成序列化操作
相要被序列化的对象实现Serializable接口
public class Person implements Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class test06 {
public static void main(String[] args) throws IOException {
final ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\Ajava\\person.txt"));
Person p1 = new Person("李云龙",25);
objectOutputStream.writeObject(p1);
objectOutputStream.close();
}
}
反序列化_ObjectInputStream
1.构造:
ObjectInputStream(InputStream in)
2.方法
Object readObject()
不想被序列化操作
如果有成员不想被序列化到文件中,将成员修饰成transient(瞬态关键字)的成员
反序列化时出现的问题以及分析和解决
1.问题描述:
当我们修改源代码以后,没有重新序列化,直接反序列化,会出现:序列号冲突问题(InvalidClassException)
2.解决:
将序列号定死
public class Person implements Serializable {
public static final long serialVersionUTD = 42l;
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
扩展(经验值)
1.如果我们序列化多个对象以后,我们如何反序列化那?
注意:如果反序列化次数不合理,会出现EOFException(文件意外到达结尾异常)
2.解决
将多个对象放到一个集合中,我们序列化这个集合
public class test02 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//method01();
method02();
}
public static void method01() throws IOException {
final ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\Ajava\\per.txt"));
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("李云龙",18));
list.add(new Person("丁伟",30));
list.add(new Person("孔捷",32));
oos.writeObject(list);
oos.close();
}
private static void method02() throws IOException, ClassNotFoundException {
final ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\Ajava\\per.txt"));
ArrayList<Person> list = (ArrayList<Person>) ois.readObject();
for (Object o : list) {
System.out.println(o);
}
}
}
打印流_PrintStream
PrintStream打印流基本使用
1.构造
PrintStream(String fileName)
2.方法:
println() 原样输出,自带换行功能
print() 原样输出。不带换行
public class test03 {
public static void main(String[] args) throws FileNotFoundException {
final PrintStream printStream = new PrintStream("D:\\Ajava\\print.txt");
printStream.println("李云龙");
printStream.println("孔捷");
printStream.println("丁伟");
printStream.println("魏大勇");
printStream.close();
}
}
拓展:
System类中的方法:
Static void setOut(PrintStram out) ---- 改变流向 ---- 将println从控制台上转移到指定的文件中
作用
配合日志文件使用
public static void method() throws FileNotFoundException {
final PrintStream ps = new PrintStream("D:\\Ajava\\print.txt");
System.setOut(ps);
System.out.println("楚云飞");
System.out.println("赵刚");
System.out.println("段鹏");
ps.close();
}
PrintStream打印流完成续写
相关代码,只需要在路径上稍加改变,加入参数true即可
public static void method() throws FileNotFoundException {
final PrintStream ps = new PrintStream(new FileOutputStream("D:\\Ajava\\print.txt",true));
System.setOut(ps);
System.out.println("楚云飞");
System.out.println("赵刚");
System.out.println("段鹏");
ps.close();
}
Properties集合
Properties结合IO流使用方法
方法:
void load(InputStream inStream) ----- 将流中的数据加载到Properties属性集中
使用场景:集合配置文件使用
注意:将来很多的”死数据“应该放到配置文件中,不应该放到源码中,我们可以通过解析配置文件,读取配置文件中的数据,去操作
1.在当前模块下创建一个xxx.properties的文件
2.在配置文件中写配置
a.每个配置都是key=value形式
b.没写完一个键值对需要换行写下一个键值对
c.不能有空格
d.key和value都是String类型,但是不要手动加上”“
public class test05 {
public static void main(String[] args) throws IOException {
final Properties properties = new Properties();
final FileInputStream fileInputStream = new FileInputStream("D:\\Ajava\\properties.txt");
properties.load(fileInputStream);
System.out.println(properties.getProperty("username"));
System.out.println(properties.getProperty("password"));
}
}
Commons-io 工具包
IO技术开发中,代码量很大,而且代码的重复率较高。如果我们要遍历目录,拷贝目录就需要使用方法的递归调用,也增大了程序的复杂度。
Apache软件基金会,开发了IO技术的工具类 commonsIO 大大简化了IO开发
添加第三方jar包
1.Apache软件基金会属于第三方 (Oracle公司第一方,我们自己第二方,其他的都是第三方)我们要使用第三方开发好的工具,需要添加jar包。
2.什么是jar包:本身是一个压缩包,后缀名为.jar 里面存的都是class文件
3.导jar包
a.在当前模块下,创建文件夹,取名为lib或者libs
b.将要使用的jar包粘贴到jlib文件夹下
c,将jar包解压到当前模块下
对着lib或者具体的jar包右键---- add as library ---- level 选项选择 mdoule — name 栏会变空,不用管 — ok
工具包的使用
IOUtils类
静态方法:IOUtils.copy(InputStream in, OutputStream out) 传递字节流,实现文件复制
静态方法:IOUtils.closeQuietly(任意流对象)悄悄的释放资源,自动处理close() 方法抛出的异常
public class test06 {
public static void main(String[] args) throws IOException {
//传递字节流,实现文件复制
IOUtils.copy(new FileInputStream("C:\\Users\\94863\\Pictures\\Saved Pictures\\huahua.jpg"),new FileOutputStream("C:\\Users\\94863\\Pictures\\Saved Pictures\\hua.jpg"));
}
}
public class test07 {
public static void main(String[] args) {
FileWriter fw = null;
try {
fw = new FileWriter("D:\\Ajava\\writer.txt");
} catch (IOException e) {
e.printStackTrace();
}finally {
/*
如果fw不等于null,证明new出来了
所以我们需要close
否则就不用关了
* */
if (fw!=null){
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}finally {
IOUtils.closeQuietly(fw);
}
}
}
}
}
FileUtils类
静态方法:FileUtils.copyDirectoryToDirectory(File src.File dest)
传递File类型的目录,进行整个目录的复制,自动进行递归遍历
参数:
src:要复制的文件夹路径
dest:要将文件夹粘贴到哪里去
静态方法 writeStringToFile(File file,String str)写字符串到文本文件中
静态方法 String readFileToString(File file)读取文本文件,返回字符串
public class test08 {
public static void main(String[] args) throws IOException {
//进行整个目录的复制,目的进行递归遍历
//FileUtils.copyDirectoryToDirectory(new File("D:\\Ajava"),new File("D:\\Bjava"));
//写字符串到文本文件中
//FileUtils.writeStringToFile(new File("D:\\Ajava\\uti.txt"),"李云龙");
//读取文本文件,返回字符串
System.out.println(FileUtils.readFileToString(new File("D:\\Ajava\\uti.txt")));
}
}
网络结构
C/S结构 全称为Client/Server结构,是指客户端和服务器结构,常有程序有QQ、红蜘蛛、飞秋等软件
B/S结构 全称为Browser/Server结构,是指浏览器和服务器结构,常见浏览器有IE、谷歌、火狐等
两种结构各有优势,但是无论哪种架构,都离不开网络的支持,网络编程
就是在一定的协议下,实现两台计算机的通信的程序
服务器概念
服务器是安装了服务器软件的计算机
网络通信协议:两台计算机在做数据交互时要遵守的规则,协议会对数据的格式,速率等进行规定,只有遵守了整个协议,才能完成数据交互。
两台计算机想完成数据交互,需要遵守网络通信协议
通信三要素
[IP地址]
计算机的唯一标识,用于两台计算机之间的连接
a.概述:指互联网协议地址(Internet Protocol Address),俗称IP计算机的唯一标识
b.作用:可用于计算机和计算机之间的连接
c.IPV4 32位的二进制数,通常被分为4个字节,表示成a.b.c.d 的形式,例如192.168.65.100 。其中a、b、c、d都是0~255之间的十进制整数,那么最多可以表示42亿个。
IPV6:为了扩大地址空间,拟通过IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制数,表示成ABCD:EF01:2345:6789:ABCD:EF01:2345:6789->号称能给地球上的每一粒沙子分配一个IP地址
d.查看ip的命令:测试是否能连接其他计算机的命令:ping ip地址
e:特殊的网址:代表的是本机地址,到了哪里都不会变,代表自己
127.0.0.1 localhost localhost:端口号/项目名/资源
[协议]
TCP:面向连接协议
需要先确认连接,才能进行数据交互
三次握手:
- 第一次握手,客户端向服务器端发出连接请求,等待服务器确认。
- 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。
- 第三次握手,客户端再次向服务器端发送确认信息,确认连接
好处:数据安全,能给数据的传输提供一个安全的传输环境
坏处:效率低
UDP:面向无连接协议
好处:效率高
坏处:传输的数据不安全,容易丢失数据包
[端口号]
每一个应用程序的唯一标识
用两个字节表示的整数,它的取值范围是0~65535。
其中,0~1023之间的端口号用于一些知名的网络服务和应用,
普通的应用程序需要使用1024以上的端口号。如果端口号被另外一个服务或应用所占用,
会导致当前程序启动失败
TCP的三次握手 和四次握手
三次握手:
第一次握手,客户端向服务器端发出连接请求,等待服务器确认。
第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。
第三次握手,客户端再次向服务器端发送确认信息,确认连接。
四次挥手:
第一次挥手:客户端向服务器端提出结束连接,让服务器做最后的准备工作。此时,客户端处于半关闭状态,即表示不再向服务器发送数据了,但是还可以接受数据。
第二次挥手:服务器接收到客户端释放连接的请求后,会将最后的数据发给客户端。并告知上层的应用进程不再接收数据。
第三次挥手:服务器发送完数据后,会给客户端发送一个释放连接的报文。那么客户端接收后就知道可以正式释放连接了。
第四次挥手:客户端接收到服务器最后的释放连接报文后,要回复一个彻底断开的报文。这样服务器收到后才会彻底释放连接。这里客户端,发送完最后的报文后,会等待2MSL,因为有可能服务器没有收到最后的报文,那么服务器迟迟没收到,就会再次给客户端发送释放连接的报文,此时客户端在等待时间范围内接收到,会重新发送最后的报文,并重新计时。如果等待2MSL后,没有收到,那么彻底断开。