课前回顾:
1.TreeSet
a.特点:元素可以排序,元素唯一,无索引,线程不安全
b.数据结构:红黑树
c.构造:
TreeSet()
TreeSet(Comparator c)
2.TreeMap
a.特点:可以对key排序,key唯一,无索引,线程不安全
b.数据结构:红黑树
c.构造:
TreeMap()
TreeMap(Comparator c)
3.Hashtable:
a.特点:key唯一 无序 无索引 线程安全 不能存null键 null值
b.使用:和HashMap一样
4.Vector:
a.特点:元素可重复 有序 有索引 线程安全
b.使用:和ArrayList一样
5.Properties集合
a.特点:key唯一 无序 无索引 线程安全 不能存null键 null值 key和value都是String
b.特有方法:
setProperty(k,v)
getProperty(k)
stringPropertyNames():获取所有的key
load(InputStream in)->将流中的数据信息加载到Properties集合中
6.File:
a.静态成员
static String pathSeparator -> 与系统有关的路径分隔符 ;
static String separator-> 与系统有关的默认名称分隔符 \
b.构造:
File(String parent,String child)
File(File parent,String child)
File(String path)
c.获取方法:
getAbsolutePath()获取绝对路径
getPath()获取的是封装路径
getName()获取文件或者文件夹名字
length()获取文件的字节数,不是文件夹
getParentFile()获取父路径
d.创建方法:
createNewFile()创建文件
mkdirs()创建文件夹
e.删除方法:
delete()->不走回收站
f.判断方法:
isFile()
isDirectory()
exists()
g.遍历方法:
list()
listFiles()
今日重点:
1.要分清IO流流向->什么是输入 什么是输出
2.会使用所有的流进行写数据(输出) 读数据(输入)
1.概述:
I:In-> 输入-> 读进来
O:Out-> 输出->写出去
2.什么是IO流技术
将数据从一个设备上传输到另外一个设备上的技术
3.为什么要学IO流
之前我们学过数组,集合,这两个都是存储数据的,而且是临时存储,程序运行完毕,程序会从内存中释放出来,此时集合和数组中的数据就没了
我们就想,如何将数据永久保存呢?我们可以将数据放到硬盘的文件中,只要硬盘不废,数据就还在.想用的时候,从硬盘的文件中读出来使用
IO流技术就可以将内存中的数据保存到硬盘上,用的时候还可以从硬盘上将数据读回来使用
1.输出流:从内存出发,将数据写到硬盘的文件中
2.输入流:将数据从硬盘的文件中读到内存中
1.字节流:一切皆字节,万能流
复制的话一定要用字节流
字节输出流:OutputStream
字节输入流:InputStream
2.字符流:操作文本文档->能用记事本打开,人能看懂的
.html .txt .java .css
.doc不是->用记事本打开,会乱码
字符输出流:Writer
字符输入流:Reader
3.单词考验
FileOutputStream:字节输出流
FileInputStream:字节输入流
FileWriter:字符输出流
FileReader:字符输入流
BufferedOutputStream:缓冲字节输出流
BufferedInputStream:缓冲字节输入流
BufferedWriter:缓冲字符输出流
BufferedReader:缓冲字符输入流
ObjectOutputStream:序列化流 -> 写数据
ObjectInputStream:反序列化流-> 读数据
InputStreamReader:转换流->读数据
OutputStreamWriter:转换流->写数据
PrintStream:打印流->输出流->写数据
所有的输出流,都统一用write方法,写数据
所有的输入流,都统一用read方法,读数据
1.字节输出流:OutputStream->抽象类
2.OutputStream是抽象类,不能new对象,所以我们需要学习子类
FileOutputStream
3.构造:
FileOutputStream(File file)
FileOutputStream(String name)
以上两个构造方法,new的时候需要传递文件的路径
4.注意:输出流(所有流)在写数据的时候,如果指定的文件不存在,会自动创建
5.方法:
void write(int b) -> 一次写一个字节
void write(byte[] b) -> 一次写一个字节数组
void write(byte[] b, int off, int len) -> 一次写一个字节数组一部分
b:代表要写的数组
off:代表从数组的哪个索引开始写
len:写多少个
void close() -> 关闭流对象
public class Demo01_FileOutputStream {
/**
* void write(int b) -> 一次写一个字节
*/
public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("day22\\io\\fileout.txt");
fos.write(97);
//关流
fos.close();
}
}
public class Demo02_FileOutputStream {
/**
* void write(byte[] b) -> 一次写一个字节数组
*/
public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("day22\\io\\fileout.txt");
//定义数组
byte[] bytes = {97,98,99,100};
fos.write(bytes);
//关流
fos.close();
}
}
public class Demo03_FileOutputStream {
/**
* void write(byte[] b, int off, int len) -> 一次写一个字节数组一部分
* b:代表要写的数组
* off:代表从数组的哪个索引开始写
* len:写多少个
*/
public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("day22\\io\\fileout.txt");
//定义数组
byte[] bytes = {97,98,99,100};
fos.write(bytes,0,2);
//关流
fos.close();
}
}
public class Demo04_FileOutputStream {
public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("day22\\io\\fileout.txt");
//定义数组
//byte[] bytes = "a".getBytes();
//byte[] bytes = "中国你好".getBytes();
//byte[] bytes = "97".getBytes();
//fos.write(bytes);
fos.write("涛哥和柳岩那个啥的故事".getBytes());
//关流
fos.close();
}
}
1.注意
输出流,默认每次运行都会创建一个新的文件,把之前文件覆盖,无法实现内容追加
2.实现内容追加,不覆盖
FileOutputStream(String name, boolean append) -> 实现内容追加,不覆盖
name:文件路径
append:false->不追加,会覆盖
true-> 追加,不会覆盖
3.实现换行->换行符
windows:\r\n -> 毕竟有一个r有一个n组成,所以一个换行符占2个字节
public class Demo05_FileOutputStream {
public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("day22\\io\\fileout.txt",true);
//fos.write("涛哥和那个啥的故事".getBytes());
//fos.write("\r\n".getBytes());
fos.write("涛哥和那个啥的故事\r\n".getBytes());
//关流
fos.close();
}
}
1.概述:字节输入流-> InputStream-> 抽象类
2.子类:FileInputStream->读数据
3.构造:
FileInputStream(File file)
FileInputStream(String name)
4.注意:读要读已有的文件,不能自动创建文件
5.方法:
int read() -> 一次读取一个字节,返回的是读取的字节内容
int read(byte[] b) -> 一次读取一个字节数组,返回的是读取的字节个数
int read(byte[] b, int off, int len) -> 一次读取一个字节数组一部分,返回的是读取的字节个数
b:要读取的数组
off:从数组的哪个索引开始读
len:读多少个
void close() -> 关流
public class Demo01_FileInputStream {
/**
* int read() -> 一次读取一个字节,返回的是读取的字节内容
*/
public static void main(String[] args)throws Exception {
FileInputStream fis = new FileInputStream("day22\\io\\filein.txt");
/*int read01 = fis.read();
System.out.println(read01);
int read02 = fis.read();
System.out.println(read02);
int read03 = fis.read();
System.out.println(read03);
int read04 = fis.read();
System.out.println(read04);
int read05 = fis.read();
System.out.println(read05);
int read06 = fis.read();
System.out.println(read06);*/
//定义一个变量,接收每次读取的字节
int len;
while((len = fis.read())!=-1){
System.out.println((char) len);
}
fis.close();
}
}
1.循环读取的时候,不要再判断的时候读一次,输出的时候再读一次
2.如果一个流对象被close了,此对象不能再使用了
3.IO流对象,如果将文件中的内容读完了,就不能再次使用此对象读了
1.每个文件最后(末尾),都有一个结束标记,此结束标记看不见,摸不着
public class Demo03_FileInputStream {
/**
* int read(byte[] b) -> 一次读取一个字节数组,返回的是读取的字节个数
*/
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("day22\\io\\filein.txt");
/*
创建byte数组
数组作用:看做是一个临时存储区,我读取的数据会先放到数组中,然后我们从数组中拿数据
数组一般长度定为1024或者1024的倍数
*/
byte[] bytes = new byte[6];
/* int read01 = fis.read(bytes);
//System.out.println(read01);//2代表的是读了2个
//System.out.println(new String(bytes));
System.out.println(new String(bytes,0,read01));
int read02 = fis.read(bytes);
//System.out.println(read02);//2代表的是读了2个
//System.out.println(new String(bytes));
System.out.println(new String(bytes,0,read02));
int read03 = fis.read(bytes);
//System.out.println(read03);//1代表的是读了1个
//System.out.println(new String(bytes));
System.out.println(new String(bytes,0,read03));*/
//定义一个变量,代表读取的个数
int len;
while((len = fis.read(bytes))!=-1){
//System.out.println(new String(bytes,0,len));
System.out.println(new String(bytes,0,len));
}
//关流
fis.close();
}
}
public class Demo04_Copy {
public static void main(String[] args)throws Exception {
//1.创建FileInputStream用于读取文件
FileInputStream fis = new FileInputStream("E:\\Idea\\io\\5.jpg");
//2.创建FileOutputStream用于将读取到的文件写到指定位置
FileOutputStream fos = new FileOutputStream("E:\\Idea\\io\\李成敏.jpg");
//3.定义一个数组
byte[] bytes = new byte[1024];
//4.定义一个变量,接收读取的字节个数
int len;
while((len = fis.read(bytes))!=-1){
//5.将读取到的字节写到指定位置
fos.write(bytes,0,len);
}
//关流-> 先开后关
fos.close();
fis.close();
}
}
public class Demo01_FileReader {
public static void main(String[] args)throws Exception {
FileInputStream fis = new FileInputStream("day22\\io\\reader.txt");
byte[] bytes = new byte[2];
int len;
while((len = fis.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
fis.close();
}
}
1.如果文件中存字母,一个字母占一个字节
2.如果文件中存中文,不用的编码表,一个汉字所在字节数不一样
GBK:一个中文占2个字节
UTF-8:一个中文占3个字节
3.注意:字节流确实是万能流,但是不要边读边看(输出到控制台)
要是复制,只要字节读不丢,复制完就能正常显示
字符流在操作文本文档时[编码一致的情况下],边读边看,没问题
1.概述:字符输入流:Reader->抽象类
2.子类:FileReader->读字符
3.构造:
FileReader(File file)
FileReader(String path)
4.方法:
int read() -> 一次读取一个字符
int read(char[] cbuf) -> 一次读取一个字符数组
int read(char[] cbuf, int offset, int length)-> 一次读取一个字符数组一部分
cbuf:要读取的字符数组
offset:从数组的哪个索引开始读
length:读多少个
void close():关流
public class Demo01_FileReader {
/**
* int read() -> 一次读取一个字符
*/
public static void main(String[] args) throws Exception {
FileReader fr = new FileReader("day22\\io\\reader.txt");
/*int read01 = fr.read();
System.out.println((char) read01);
int read02 = fr.read();
System.out.println((char) read02);
int read03 = fr.read();
System.out.println((char) read03);
int read04 = fr.read();
System.out.println(read04);*/
int len;
while((len = fr.read())!=-1){
System.out.println((char) len);
}
fr.close();
}
}
public class Demo02_FileReader {
/**
* int read(char[] cbuf) -> 一次读取一个字符数组,返回的是读取的个数
*/
public static void main(String[] args) throws Exception {
FileReader fr = new FileReader("day22\\io\\reader.txt");
char[] chars = new char[2];
/*int read01 = fr.read(chars);
//System.out.println(read01);
System.out.println(new String(chars,0,read01));
int read02 = fr.read(chars);
//System.out.println(read02);
System.out.println(new String(chars,0,read02));*/
//定义变量,接收读取的个数
int len;
while((len = fr.read(chars))!=-1){
System.out.println(new String(chars,0,len));
}
fr.close();
}
}
1.概述:字符输出流:Writer->抽象类
2.子类:FileWriter
3.构造:
FileWriter(File file)
FileWriter(String fileName)
FileWriter(String fileName, boolean append) -> 追加续写
4.方法:
void write(int c) -> 一次写一个字符
void write(char[] cbuf) -> 一次写一个字符数组
void write(char[] cbuf, int off, int len) -> 一次写一个字符数组一部分
void write(String str) -> 直接写字符串
void write(String str, int off, int len)-> 一次写一个字符串一部分
void flush() -> 刷新缓冲区
void close() ->关流
5.注意:
字符流:底层自带一个缓冲区
我们要是写数据的话,写的数据会先放到缓冲区中,我们需要将数据从缓冲区中刷到硬盘上
public class Demo01_FileWriter {
public static void main(String[] args)throws Exception {
FileWriter fw = new FileWriter("day22\\io\\writer.txt");
// void write(char[] cbuf) -> 一次写一个字符数组
char[] chars = {'你','好','柳','岩'};
fw.write(chars);
//刷新缓冲区
//fw.flush();
/*
关流-> close方法自带刷新功能,先刷新,后关流
*/
fw.close();
}
}
public class Demo02_FileWriter {
public static void main(String[] args)throws Exception {
FileWriter fw = new FileWriter("day22\\io\\writer.txt",true);
fw.write("夏商与西周");
fw.write("\r\n");
fw.write("东周分两段");
fw.write("\r\n");
fw.write("春秋和战国");
fw.write("\r\n");
fw.write("一统秦两汉");
fw.write("\r\n");
fw.write("三分魏蜀吴");
fw.write("\r\n");
fw.write("二晋前后延");
fw.write("\r\n");
fw.write("南北朝并立");
fw.write("\r\n");
fw.write("隋唐五代传");
fw.write("\r\n");
fw.write("宋元明清后");
fw.write("\r\n");
fw.write("王朝至此完");
fw.write("\r\n");
//关流
fw.close();
}
}
1.flush:刷新,刷新完之后,流对象还能使用
2.close:先刷新,后关流,close之后流对象不能使用了
public class Demo03_FileWriter {
public static void main(String[] args)throws Exception {
FileWriter fw = new FileWriter("day22\\io\\writer.txt");
fw.write("夏商与西周");
//刷新
fw.flush();
fw.write("东周分两段");
fw.flush();
//关流
fw.write("涛哥和柳岩");
fw.close();
//fw.write("那一夜,你没有拒绝我");此处报错,因为流已经被关闭,不能再使用了
}
}
public class Demo04_FileWriter {
public static void main(String[] args) {
FileWriter fw = null;
try {
fw = new FileWriter("day22\\io\\writer.txt");
fw.write("静静和晓楠");
} catch (Exception e) {
e.printStackTrace();
}finally {
/*
如果fw对象没有new出来,fw就是null
如果fw是null,就不用我们自己close了
只有fw对象new出来了,我们才要自己close
*/
if (fw!=null){
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
1.格式:
try(IO流对象){
可能出现异常的代码
}catch(异常对象 对象名){
}
2.注意:用以上格式处理IO异常,jvm会自动管理IO流对象
public class Demo05_FileWriter {
public static void main(String[] args) {
try(FileWriter fw = new FileWriter("day22\\io\\writer.txt");) {
fw.write("静静和晓楠");
} catch (Exception e) {
e.printStackTrace();
}
}
}
1.缓冲流和普通流有什么区别:
a.缓冲流底层有缓冲区,缓冲区默认大小为8192
b.缓冲流在读写的时候,都会将数据先放到缓冲区中,所以缓冲区的读写动作,不是直接调用的native方法,而是在内存中进行读写,内存中的读写要比跟系统做交互的读写效率要高,而且缓冲流的读写方法都不是native的
c.我们使用缓冲流可以尽量减少直接对系统进行读写操作,也减少了系统资源的占用
2.字节缓冲输出流:BufferedOutputStream
a.构造:
BufferedOutputStream(OutputStream out)
OutputStream:抽象类,所以需要传递子类对象
如果想利用字节缓冲输出流做追加,可以利用FileOutputStream来实现
b.用法:和FileOutputStream一毛一样
3.字节缓冲输入流:BufferedInputStream
a.构造:
BufferedInputStream(InputStream in)
InputStream:抽象类,所以需要传递子类对象
b.用法:和FileInputStream一毛一样
public class Demo01_Copy {
public static void main(String[] args)throws Exception {
//method01();
method02();
}
private static void method02() throws Exception{
long start = System.currentTimeMillis();
//1.创建FileInputStream用于读取文件
FileInputStream fis = new FileInputStream("E:\\Idea\\io\\集合.avi");
BufferedInputStream bis = new BufferedInputStream(fis);
//2.创建FileOutputStream用于将读取到的文件写到指定位置
FileOutputStream fos = new FileOutputStream("E:\\Idea\\io\\新集合.avi");
BufferedOutputStream bos = new BufferedOutputStream(fos);
//3.定义一个数组
byte[] bytes = new byte[1024];
//4.定义一个变量,接收读取的字节个数
int len;
while((len = bis.read(bytes))!=-1){
//5.将读取到的字节写到指定位置
bos.write(bytes,0,len);
}
long end = System.currentTimeMillis();
System.out.println(end-start);
//关流-> 先开后关
bos.close();
bis.close();
}
private static void method01() throws IOException {
long start = System.currentTimeMillis();
//1.创建FileInputStream用于读取文件
FileInputStream fis = new FileInputStream("E:\\Idea\\io\\集合.avi");
//2.创建FileOutputStream用于将读取到的文件写到指定位置
FileOutputStream fos = new FileOutputStream("E:\\Idea\\io\\新集合.avi");
//3.定义一个数组
byte[] bytes = new byte[1024];
//4.定义一个变量,接收读取的字节个数
int len;
while((len = fis.read(bytes))!=-1){
//5.将读取到的字节写到指定位置
fos.write(bytes,0,len);
}
long end = System.currentTimeMillis();
System.out.println(end-start);
//关流-> 先开后关
fos.close();
fis.close();
}
}
1.构造:
BufferedWriter(Writer out)
Writer:抽象类,需要传递子类
2.方法:
和FileWriter一毛一样
3.特有方法:
newLine()->换行
public class Demo02_BufferedWriter {
public static void main(String[] args)throws Exception {
BufferedWriter bw =
new BufferedWriter(new FileWriter("day22\\io\\buffered.txt",true));
bw.write("离离原上草");
bw.newLine();
bw.write("一岁一枯荣");
bw.newLine();
bw.write("野火烧不尽");
bw.newLine();
bw.write("春风吹又生");
bw.newLine();
bw.close();
}
}
1.构造:
BufferedReader(Reader r)
Reader:抽象类,需要传递子类对象
2.方法:
和FileReader一毛一样
3.特有方法:
String readLine()-> 一次读一行
public class Demo03_BufferedReader {
public static void main(String[] args)throws Exception {
BufferedReader br = new BufferedReader(new FileReader("day22\\io\\buffered.txt"));
/* String s1 = br.readLine();
System.out.println(s1);
String s2 = br.readLine();
System.out.println(s2);
String s3 = br.readLine();
System.out.println(s3);
String s4 = br.readLine();
System.out.println(s4);
String s5 = br.readLine();
System.out.println(s5);//null*/
//定义一个变量,接收读取的内容
String line;
while((line = br.readLine())!=null){
System.out.println(line);
}
br.close();
}
}
将in.txt中的内容排好序,写到另外一个新文件中
c.侍中、侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。愚以为宫中之事,事无大小,悉以咨之,然后施行,必得裨补阙漏,有所广益。
h.愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎;陛下亦宜自谋,以咨诹善道,察纳雅言,深追先帝遗诏,臣不胜受恩感激。
d.将军向宠,性行淑均,晓畅军事,试用之于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。
b.宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。
a.先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。
i.今当远离,临表涕零,不知所言。
f.臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
g.先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐付托不效,以伤先帝之明,故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。
e.亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。
实现步骤:
1.创建BufferedReader,用于读取in.txt的内容
2.创建ArrayList集合,用于存储读取出来的内容
3.调用Collections.sort,进行排序
4.创建BufferedWriter,用于将集合中排好序的内容写到out.txt中
5.遍历ArrayList集合,边遍历,边写
6.关流
public class Demo04_Test {
public static void main(String[] args)throws Exception {
//1.创建BufferedReader,用于读取in.txt的内容
BufferedReader br = new BufferedReader(new FileReader("day22\\io\\in.txt"));
//2.创建ArrayList集合,用于存储读取出来的内容
ArrayList<String> list = new ArrayList<>();
String line;
while((line = br.readLine())!=null){
list.add(line);
}
//3.调用Collections.sort,进行排序
Collections.sort(list);
//4.创建BufferedWriter,用于将集合中排好序的内容写到out.txt中
BufferedWriter bw = new BufferedWriter(new FileWriter("day22\\io\\out.txt"));
//5.遍历ArrayList集合,边遍历,边写
for (String s : list) {
bw.write(s);
bw.newLine();
}
//6.关流
bw.close();
br.close();
}
}
计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。[按照某种规则,将字符存储到计算机中,称为编码] 。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码 。比如说,按照A规则存储,同样按照A规则解析,那么就能显示正确的文本f符号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象。
Character Encoding
: 就是一套自然语言的字符与二进制数之间的对应规则。Charset
:也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。计算机要准确的存储和识别各种字符集符号,需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBK字符集、Unicode字符集等。
可见,当指定了编码,它所对应的字符集自然就指定了,所以编码才是我们最终要关心的。
1.如果想要不出现乱码问题,编码和解码遵循的编码规则要一样
2.在GBK中,一个中文占2个字节
3.在UTF-8中,一个中文占3个字节
1.作用:在读取的时候,可以指定按照什么编码去读
2.构造:
InputStreamReader(InputStream in, String charsetName)
in:抽象类,传递子类
charsetName:指定的编码表,不区分大小写的
3.使用:
和FileReader一样
public class Demo01_InputStreamReader {
public static void main(String[] args) throws Exception{
InputStreamReader isr = new InputStreamReader(new FileInputStream("E:\\Idea\\io\\a.txt"),"gbk");
int read = isr.read();
System.out.println((char)read);
isr.close();
}
}
1.作用:按照指定的编码规则去写数据,指定什么规则,就按照什么规则去保存数据
2.构造:
OutputStreamWriter(OutputStream out, String charsetName)
out:抽象类,传递子类
charsetName:指定的编码表,不区分大小写的
3.使用:
和FileWriter一样
public class Demo02_OutputStreamWriter {
public static void main(String[] args)throws Exception {
OutputStreamWriter osr = new OutputStreamWriter(new FileOutputStream("E:\\Idea\\io\\b.txt"),"GBK");
osr.write("你");
osr.close();
}
}
1.概述:
PrintStream:打印流
2.方法:
println():原样输出,输出之后自动换行
print():原样输出,输出之后不会换行
3.构造:
PrintStream(String fileName)
fileName:文件路径
public class Test02 {
public static void main(String[] args)throws Exception {
PrintStream ps = new PrintStream("day22\\io\\print.txt");
ps.println("柳岩");
ps.println("涛哥");
ps.close();
}
}
使用场景:
可以用于将运行结果,过程打印到日志文件中
System中的setOut方法
setOut(PrintStream ps)
所谓的改变流向:
让System.out.println()输出不在控制台上,转到指定的文件中
public class Test03 {
public static void main(String[] args)throws Exception {
PrintStream ps = new PrintStream("day22\\io\\print.txt");
System.out.println("select * from category");
System.setOut(ps);
System.out.println("select * from category");
ps.close();
}
}
今日重点:
1.会使用序列化流读写对象
2.会使用Properties集合中的load方法解析properties配置文件
3.会手动导jar包,使用Commons-io
4.会使用Lombok完成一个标准的javabean
5.知道客户端和服务端之间的交互过程
1.作用:读写对象
2.写对象(序列化流):ObjectOutputStream
3.读对象(反序列化流):ObjectInputStream
1.序列化流:ObjectOutputStream -> 写对象
2.构造:
ObjectOutputStream(OutputStream out)
OutputStream:抽象类,需要传递子类
3.方法:
void writeObject(Object obj) -> 写对象
4.注意:
想将一个对象序列化到文件中,此对象需要实现Serializable接口
public class Person implements Serializable {
private String name;
private Integer age;
public Person() {
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Demo01_Serializable {
public static void main(String[] args) throws Exception{
//创建序列化流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day23/io/person.txt"));
oos.writeObject(new Person("柳岩",36));
oos.close();
}
}
1.反序列化:ObjectInputStream -> 读对象
2.构造:
ObjectInputStream(InputStream in)
InputStream:抽象类,所以需要传递子类对象
3.方法:
Object readObject() -> 读对象
public class Demo02_Serializable {
public static void main(String[] args) throws Exception{
//创建反序列化流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day23/io/person.txt"));
Object o = ois.readObject();
//向下转型
Person p = (Person)o;
System.out.println(p);
ois.close();
}
}
1.将成员变成静态的
2.瞬态关键字:transient
比如:
private transient Integer age
1.问题描述:
如果对象的源码改动了,但是没有重新序列化,直接反序列化,就会爆出序列号冲突异常:InvalidClassException
解决:
方式1:源码改动,重新序列化一下子
方式2:直接将序列号定死:
在要被序列化的类中加上:private static final long serialVersionUID = 42L;
1.问题描述:
如果序列化多个对象,当反序列化时不知道反序列化多少次才能全部将对象读出来时,容易出现:EOFException(文件意外到达结尾异常)
2.解决:
将多个对象放到一个集合中,然后将集合对象放到文件中
然后反序列化这一个集合,然后再遍历集合,获取集合中的对象
public class Demo01_Serializable {
public static void main(String[] args) throws Exception{
//创建序列化流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day23/io/person.txt"));
//oos.writeObject(new Person("柳岩",36));
//oos.writeObject(new Person("涛哥",18));
//oos.writeObject(new Person("晓楠",16));
//创建ArrayList集合
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("柳岩",36));
list.add(new Person("涛哥",18));
list.add(new Person("晓楠",16));
oos.writeObject(list);
oos.close();
}
}
public class Demo02_Serializable {
public static void main(String[] args) throws Exception{
//创建反序列化流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day23/io/person.txt"));
//读取集合
ArrayList<Person> list = (ArrayList<Person>) ois.readObject();
for (Person person : list) {
System.out.println(person);
}
ois.close();
}
}
1.Properties中的load方法:
void load(InputStream inStream) -> 将流中的数据加载到Properties集合中
2.使用场景:
读取properties配置文件的
3.注意:
将来我们写代码要追求高内聚,低耦合
耦合度:类和类之间的联系紧密程度
4.解决:
我们可以将硬数据放到文件中,然后我们用代码动态解析文件中的数据,获取文件中的数据
这样做,到时候修改硬数据直接去文件中改,源码不用动,有效地减低了耦合度
1.创建一个properties配置文件
2.怎么创建这个properties配置文件?
右键->new->file->取名xxx.properties->ok
3.properties文件中的内容怎么写:
a.内容数据都是key=value形式
b.key和value都是String,但是不能加""
c.不能有空格
d.一个键值对写完之后,要换行,才能写下一个键值对
e.尽量不要写中文
username=root
password=1234
public class Test02_Properties {
public static void main(String[] args)throws Exception {
/*
void load(InputStream inStream) -> 将流中的数据加载到Properties集合中
*/
//1.创建Properties集合
Properties properties = new Properties();
//2.创建字节输入流
FileInputStream in = new FileInputStream("day23\\io\\pro.properties");
//3.将流中的数据加载到Properties集合中
properties.load(in);
//4.遍历
System.out.println(properties.getProperty("username"));
System.out.println(properties.getProperty("password"));
}
}
IO技术开发中,代码量很大,而且代码的重复率较高。如果我们要遍历目录,拷贝目录就需要使用方法的递归调用,也增大了程序的复杂度。
Apache软件基金会,开发了IO技术的工具类`commonsIO`,大大简化IO开发。
Apahce软件基金会属于第三方,(Oracle公司第一方,我们自己第二方,其他都是第三方)我们要使用第三方开发好的工具,需要添加jar包。
1.jar包的介绍:
jar包就是一个压缩包,只不过后缀名叫xxx.jar,压缩包中都是第三方开发好的工具类,都是以class文件存在
2.jar包怎么导:
a.在当前模块下创建文件夹,取名为lib
b.将要使用的jar粘贴到lib下
c.将jar包中的class文件解压到当前模块环境下(只有解压出来,才能使用jar包中的工具类)
对着lib包或者jar包->右键->add as library->level(选择module)->name会变空,不要管->点ok
IOUtils类
- 静态方法:IOUtils.copy(InputStream in,OutputStream out)传递字节流,实现文件复制。
- 静态方法:IOUtils.closeQuietly(任意流对象)悄悄的释放资源,自动处理close()方法抛出的异常。
public class Test01_IOUtils {
public static void main(String[] args) throws FileNotFoundException {
/*
- 静态方法:IOUtils.copy(InputStream in,OutputStream out)传递字节流,实现文件复制。
- 静态方法:IOUtils.closeQuietly(任意流对象)悄悄的释放资源,自动处理close()方法抛出的异常。
*/
//IOUtils.copy(new FileInputStream("E:\\Idea\\io\\1.jpg"),new FileOutputStream("E:\\Idea\\io\\柳岩.jpg"));
System.out.println("============================");
FileWriter fw = null;
try {
fw = new FileWriter("day23\\io\\writer.txt");
fw.write("静静和晓楠");
} catch (Exception e) {
e.printStackTrace();
}finally {
/*
如果fw对象没有new出来,fw就是null
如果fw是null,就不用我们自己close了
只有fw对象new出来了,我们才要自己close
*/
if (fw!=null){
IOUtils.closeQuietly(fw);
}
}
}
}
FileUtils类
- 静态方法:FileUtils.copyDirectoryToDirectory(File src,File dest);
传递File类型的目录,进行整个目录的复制,自动进行递归遍历。
参数:
src:要复制的文件夹路径
dest:要将文件夹粘贴到哪里去
- 静态方法:writeStringToFile(File file,String str)写字符串到文本文件中。
- 静态方法:String readFileToString(File file)读取文本文件,返回字符串。
public class Test02_FileUtils {
public static void main(String[] args)throws Exception {
/*
- 静态方法:FileUtils.copyDirectoryToDirectory(File src,File dest);
传递File类型的目录,进行整个目录的复制,自动进行递归遍历。
参数:
src:要复制的文件夹路径
dest:要将文件夹粘贴到哪里去
*/
//FileUtils.copyDirectoryToDirectory(new File("E:\\Idea\\io\\aa"),new File("E:\\Idea\\io\\haha"));
//- 静态方法:writeStringToFile(File file,String str)写字符串到文本文件中。
//FileUtils.writeStringToFile(new File("day23\\io\\commons.txt"),"涛哥和柳岩那个啥的故事");
//- 静态方法:String readFileToString(File file)读取文本文件,返回字符串。
String s = FileUtils.readFileToString(new File("day23\\io\\commons.txt"));
System.out.println(s);
}
}
Lombok通过增加一些“处理程序”,可以让java变得简洁、快速。
Lombok能以注解形式来简化java代码,提高开发效率。开发中经常需要写的javabean,都需要花时间去添加相应的getter/setter,也许还要去写构造器、equals等方法,而且需要维护。
Lombok能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法。出现的神奇就是在源码中没有getter和setter方法,但是在编译生成的字节码文件中有getter和setter方法。这样就省去了手动重建这些代码的麻烦,使代码看起来更简洁些。
5.2 lombok使用
添加lombok的jar包:lombok-1.18.8.jar。
为IDEA添加lombok插件(连接网络使用)
安装完毕后,重启IDEA。
@ToString
@NoArgsConstructor和@AllArgsConstructor
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
private String name;
private int age;
}
public class Test01 {
public static void main(String[] args) {
Person person = new Person();
person.setName("涛哥");
person.setAge(16);
System.out.println(person.getName()+"..."+person.getAge());
System.out.println("=========================");
Person person1 = new Person("三上",26);
System.out.println(person1.getName()+"..."+person1.getAge());
}
}
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的命令:ipconfig
测试是否能连接其他计算机的命令:ping ip地址
e:特殊的网址:代表的是本机地址,到了哪里都不会变,代表自己
127.0.0.1
localhost
localhost:端口号/项目名/资源
[协议]
TCP:面向连接协议
需要先确认连接,才能进行数据交互
三次握手:
- 第一次握手,客户端向服务器端发出连接请求,等待服务器确认。
- 第二次握手,服务器端向客户端回送一个响应,通知客户端,服务端收到了连接请求。
- 第三次握手,客户端再次向服务器端发送确认信息,确认连接。
好处:数据安全,能给数据的传输提供一个安全的传输环境
坏处:效率低
UDP:面向无连接协议
好处:效率高
坏处:传输的数据不安全,容易丢失数据包
[端口号]
每一个应用程序的唯一标识
用两个字节表示的整数,它的取值范围是0~65535。其中,0~1023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号。如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败。
TCP协议中的三次握手和四次挥手
三次握手: - 第一次握手,客户端向服务器端发出连接请求,等待服务器确认。 - 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。 - 第三次握手,客户端再次向服务器端发送确认信息,确认连接。
四次挥手: - 第一次挥手:客户端向服务器端提出结束连接,让服务器做最后的准备工作。此时,客户端处于半关闭状态,即表示不再向服务器发送数据了,但是还可以接受数据。 - 第二次挥手:服务器接收到客户端释放连接的请求后,会将最后的数据发给客户端。并告知上层的应用进程不再接收数据。 - 第三次挥手:服务器发送完数据后,会给客户端发送一个释放连接的报文。那么客户端接收后就知道可以正式释放连接了。 - 第四次挥手:客户端接收到服务器最后的释放连接报文后,要回复一个彻底断开的报文。这样服务器收到后才会彻底释放连接。这里客户端,发送完最后的报文后,会等待2MSL,因为有可能服务器没有收到最后的报文,那么服务器迟迟没收到,就会再次给客户端发送释放连接的报文,此时客户端在等待时间范围内接收到,会重新发送最后的报文,并重新计时。如果等待2MSL后,没有收到,那么彻底断开。
步骤:
1.创建Socket对象,指明要连接的服务端的ip和端口号
2.调用Socket对象中的getOutputStream,获取OutputStream,用于往服务端发请求(写数据)
3.调用Socket对象中的getInputStream,获取InputStream,用于读取服务端发送过来的数据(读数据)
4.关流
public class Client {
public static void main(String[] args)throws Exception {
//1.创建Socket对象,指明要连接的服务端的ip和端口号
Socket socket = new Socket("127.0.0.1", 6666);
//2.调用Socket对象中的getOutputStream,获取OutputStream,用于往服务端发请求(写数据)
OutputStream os = socket.getOutputStream();
os.write("我想现在一个片儿".getBytes());
//3.调用Socket对象中的getInputStream,获取InputStream,用于读取服务端发送过来的数据(读数据)
InputStream in = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = in.read(bytes);
System.out.println(new String(bytes,0,len));
//4.关流
in.close();
os.close();
socket.close();
}
}
步骤:
1.创建ServerSocket对象,设置端口号
2.调用ServerSocket中的accept方法,等待和获取客户端连接,返回Socket
3.调用Socket中的getInputStream,用于读取客户端发过来的请求
4.调用Socket中的getOutputStream,用于往客户端写响应信息
5.关流
public class Server {
public static void main(String[] args)throws Exception {
//1.创建ServerSocket对象,设置端口号
ServerSocket ss = new ServerSocket(6666);
//2.调用ServerSocket中的accept方法,等待和获取客户端连接,返回Socket
Socket socket = ss.accept();
//3.调用Socket中的getInputStream,用于读取客户端发过来的请求
InputStream in = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = in.read(bytes);
System.out.println(new String(bytes,0,len));
//4.调用Socket中的getOutputStream,用于往客户端写响应信息
OutputStream os = socket.getOutputStream();
os.write("我给你一个片儿,金瓶梅拿走".getBytes());
//5.关流
os.close();
in.close();
socket.close();
ss.close();
}
}
public class Client {
public static void main(String[] args)throws Exception {
//1.创建Socket对象
Socket socket = new Socket("127.0.0.1", 6666);
//2.创建FileInputStream,读取本地上的图片
FileInputStream fis = new FileInputStream("E:\\Idea\\io\\24.jpg");
//3.调用socket中的getOutputStream,将读取过来的图片写到服务器端
OutputStream os = socket.getOutputStream();
//4.边读边写
byte[] bytes = new byte[1024];
int len;
while((len = fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
//给服务端写一个结束标记,不让服务端等着了
socket.shutdownOutput();
System.out.println("=============以下代码是读取响应===========");
//5.调用socket中的getInputStream,用于读取服务端发过来的响应
InputStream in = socket.getInputStream();
byte[] bytes1 = new byte[1024];
int read = in.read(bytes1);
System.out.println(new String(bytes1,0,read));
//6.关流
in.close();
os.close();
fis.close();
socket.close();
}
}
public class Server {
public static void main(String[] args)throws Exception {
//1.创建ServerSocket对象
ServerSocket ss = new ServerSocket(6666);
//2.调用accept方法,监听,获取连接的客户端对象
Socket socket = ss.accept();
//3.调用getInputStream.读取客户端发过来的文件
InputStream in = socket.getInputStream();
//4.创建FileOutputStream,用于将读取过来的图片写到服务端本地
String name = System.currentTimeMillis()+""+new Random().nextInt()+".jpg";
FileOutputStream fos = new FileOutputStream("E:\\Idea\\io\\upload\\"+name);
//5.边读边写
byte[] bytes = new byte[1024];
int len;
while((len = in.read(bytes))!=-1){
fos.write(bytes,0,len);
}
System.out.println("=========以下代码是往客户端响应数据========");
//6.响应数据
OutputStream os = socket.getOutputStream();
os.write("上传成功".getBytes());
//7.关流
os.close();
fos.close();
in.close();
socket.close();
ss.close();
}
}
public class Server {
public static void main(String[] args) throws Exception {
//1.创建ServerSocket对象
ServerSocket ss = new ServerSocket(6666);
while (true) {
//2.调用accept方法,监听,获取连接的客户端对象
Socket socket = ss.accept();
new Thread(new Runnable() {
@Override
public void run() {
InputStream in = null;
FileOutputStream fos = null;
OutputStream os = null;
try {
//3.调用getInputStream.读取客户端发过来的文件
in = socket.getInputStream();
//4.创建FileOutputStream,用于将读取过来的图片写到服务端本地
String name = System.currentTimeMillis() + "" + new Random().nextInt() + ".jpg";
fos = new FileOutputStream("E:\\Idea\\io\\upload\\" + name);
//5.边读边写
byte[] bytes = new byte[1024];
int len;
while ((len = in.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
System.out.println("=========以下代码是往客户端响应数据========");
//6.响应数据
os = socket.getOutputStream();
os.write("上传成功".getBytes());
} catch (Exception e) {
e.printStackTrace();
} finally {
//7.关流
CloseUtils.closeQuietly(os,fos,in,socket);
}
}
}).start();
}
}
}
异常回顾:
父类中的方法没有抛异常,子类重写之后不能抛
父类中的方法抛异常了,子类重写之后可抛可不抛
public class CloseUtils {
public static void closeQuietly(OutputStream os, FileOutputStream fos, InputStream in, Socket socket){
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
1.所谓的标准javabean其实就是指的是自己定义的实体类
2.一个标准的javabean包含:
私有属性
无参构造
有参构造
get/set方法
1.在开发中,我们是分包分层的,其实分层就是依靠创建不同的package,不同的类要放到不同的包下,好维护
2.在开发中如何分包分层:
com.atguigu.web -> 专门放和前端打交道的类
com.atguigu.service-> 专门放和业务打交道的类
com.atguigu.dao-> 专门放和数据库打交道的类
com.atguigu.javabean-> 专门放实体类
com.atguigu.utils-> 专门放工具类
javabean如何产生:一个javabean的出现,需要根据数据库中的表来确定
1.面向对象思想:强调的是对象,调用对象中的方法帮我们去做事儿,侧重点在找对象
2.函数式编程思想:对面向对象思想进一步简化,不注重过程,只注重结果
3.Lambda表达式格式:
()->{}
():代表的是重写方法的参数列表
->:将参数传递到方法体中
{}:代表的是重写方法的方法体
public class Test01_Lambda {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("我到达朝鲜了");
}
}).start();
System.out.println("====================");
new Thread(()-> {
System.out.println("我到达朝鲜了");
}).start();
System.out.println("====================");
new Thread(()-> System.out.println("我到达朝鲜了")).start();
}
}
1.必须有重写方法
2.必须有函数式接口做方法参数传递
函数式接口:接口中必须有且只有一个抽象方法的接口
检测函数式接口:在接口上面,加上@FunctionalInterface
1.观察是否是函数式接口做方法参数传递
2.如果是,可以考虑搞成Lambda表达式
3.先写一个匿名内部类
4.从new接口开始到重写方法的方法名结束,选中,删除,别忘记删除右半个大括号
5.在重写方法的参数后面,加上->
6.再看看根据省略规则,能不能进一步删除
1.重写方法的参数类型可以省略
2.如果重写方法的参数只有一个,所在的小括号可以干掉
3.如果方法体中只有一句代码,所在的大括号可以干掉,分号干掉
4.如果方法体中只有一句代码,而且还是带return的,那么return,方法体大括号,分号都直接干掉
public class Test02_Lambda {
public static void main(String[] args) {
/*
Thread(Runnable r)
*/
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("哈哈哈");
}
}).start();
System.out.println("========Lambda表达式=========");
new Thread(() -> {
System.out.println("哈哈哈哈");
}).start();
System.out.println("==========最终写法=============");
new Thread(() -> System.out.println("哈哈哈哈")).start();
}
}
/*@Data
@AllArgsConstructor
@NoArgsConstructor*/
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Test03_Lambda {
public static void main(String[] args) {
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("柳岩",36));
list.add(new Person("涛哥",18));
list.add(new Person("晓楠",16));
Collections.sort(list, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge()-o2.getAge();
}
});
System.out.println("============Lambda表达式=============");
Collections.sort(list, (Person o1, Person o2)-> {
return o1.getAge()-o2.getAge();
});
System.out.println("============Lambda表达式最终写法=============");
Collections.sort(list, (o1,o2)-> o1.getAge()-o2.getAge());
System.out.println(list);
}
}
@FunctionalInterface
public interface USB {
public void open(String s);
}
public class Test01 {
public static void main(String[] args) {
method(new USB() {
@Override
public void open(String s) {
System.out.println(s+"开启了");
}
});
System.out.println("==========Lambda表达式=========");
method((String s)-> {
System.out.println(s+"开启了");
});
System.out.println("==========Lambda表达式=========");
method(s-> System.out.println(s+"开启了"));
}
public static void method(USB usb){
usb.open("鼠标");
}
}