day22.IO流
课前回顾:
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集合中
File创建文件文件夹
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.IO流介绍以及输入输出以及流向的介绍
1.概述:
I:In-> 输入-> 读进来
O:Out-> 输出->写出去
2.什么是IO流技术
将数据从一个设备上传输到另外一个设备上的技术
3.为什么要学IO流
之前我们学过数组,集合,这两个都是存储数据的,而且是临时存储,程序运行完毕,程序会从内存中释放出来,此时集合和数组中的数据就没了
我们就想,如何将数据永久保存呢?我们可以将数据放到硬盘的文件中,只要硬盘不废,数据就还在.想用的时候,从硬盘的文件中读出来使用
IO流技术就可以将内存中的数据保存到硬盘上,用的时候还可以从硬盘上将数据读回来使用
2.IO流的流向
1.输出流:从内存出发,将数据写到硬盘的文件中
2.输入流:将数据从硬盘的文件中读到内存中
3.IO流分类
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方法,读数据
4.OutputStream中子类[FileOutputStream]的介绍以及方法的简单介绍
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 {
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 {
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 {
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");
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("涛哥和那个啥的故事\r\n".getBytes());
fos.close();
}
}
第二章.字节流_字节输入流
1.InputStream子类[FileInputStream]的介绍以及方法的使用
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() -> 关流
2.一次读取一个字节
public class Demo01_FileInputStream {
public static void main(String[] args)throws Exception {
FileInputStream fis = new FileInputStream("day22\\io\\filein.txt");
int len;
while((len = fis.read())!=-1){
System.out.println((char) len);
}
fis.close();
}
}
1.循环读取的时候,不要再判断的时候读一次,输出的时候再读一次
2.如果一个流对象被close了,此对象不能再使用了
3.IO流对象,如果将文件中的内容读完了,就不能再次使用此对象读了
3.读取-1的问题
1.每个文件最后(末尾),都有一个结束标记,此结束标记看不见,摸不着
4.一次读取一个字节数组以及过程
public class Demo03_FileInputStream {
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("day22\\io\\filein.txt");
byte[] bytes = new byte[6];
int len;
while((len = fis.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
fis.close();
}
}
5.字节流实现图片复制分析
6.字节流实现图片复制代码实现
public class Demo04_Copy {
public static void main(String[] args)throws Exception {
FileInputStream fis = new FileInputStream("E:\\Idea\\io\\5.jpg");
FileOutputStream fos = new FileOutputStream("E:\\Idea\\io\\李成敏.jpg");
byte[] bytes = new byte[1024];
int len;
while((len = fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
fos.close();
fis.close();
}
}
第三章.字符流
1.字节流读取中文的问题
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.注意:字节流确实是万能流,但是不要边读边看(输出到控制台)
? 要是复制,只要字节读不丢,复制完就能正常显示
? 字符流在操作文本文档时[编码一致的情况下],边读边看,没问题
2.FileReader的介绍以及使用
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 {
public static void main(String[] args) throws Exception {
FileReader fr = new FileReader("day22\\io\\reader.txt");
int len;
while((len = fr.read())!=-1){
System.out.println((char) len);
}
fr.close();
}
}
public class Demo02_FileReader {
public static void main(String[] args) throws Exception {
FileReader fr = new FileReader("day22\\io\\reader.txt");
char[] chars = new char[2];
int len;
while((len = fr.read(chars))!=-1){
System.out.println(new String(chars,0,len));
}
fr.close();
}
}
3.FileWriter的介绍以及使用
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");
char[] chars = {'你','好','柳','岩'};
fw.write(chars);
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();
}
}
4.FileWriter的刷新功能和关闭功能
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();
}
}
5.IO异常处理的方式
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 {
if (fw!=null){
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
6.JDK7之后io异常处理方式->(扩展)
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 {
method02();
}
private static void method02() throws Exception{
long start = System.currentTimeMillis();
FileInputStream fis = new FileInputStream("E:\\Idea\\io\\集合.avi");
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream("E:\\Idea\\io\\新集合.avi");
BufferedOutputStream bos = new BufferedOutputStream(fos);
byte[] bytes = new byte[1024];
int len;
while((len = bis.read(bytes))!=-1){
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();
FileInputStream fis = new FileInputStream("E:\\Idea\\io\\集合.avi");
FileOutputStream fos = new FileOutputStream("E:\\Idea\\io\\新集合.avi");
byte[] bytes = new byte[1024];
int len;
while((len = fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
long end = System.currentTimeMillis();
System.out.println(end-start);
fos.close();
fis.close();
}
}
第五章.字符缓冲流
1.字符缓冲输出流_BufferedWriter
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();
}
}
2.字符缓冲输入流_BufferedReader
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 line;
while((line = br.readLine())!=null){
System.out.println(line);
}
br.close();
}
}
3.字符缓冲流练习
将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 {
BufferedReader br = new BufferedReader(new FileReader("day22\\io\\in.txt"));
ArrayList<String> list = new ArrayList<>();
String line;
while((line = br.readLine())!=null){
list.add(line);
}
Collections.sort(list);
BufferedWriter bw = new BufferedWriter(new FileWriter("day22\\io\\out.txt"));
for (String s : list) {
bw.write(s);
bw.newLine();
}
bw.close();
br.close();
}
}
第六章.转换流
1.字符编码
计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。[按照某种规则,将字符存储到计算机中,称为编码] 。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码 。比如说,按照A规则存储,同样按照A规则解析,那么就能显示正确的文本f符号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象。
- 字符编码
Character Encoding : 就是一套自然语言的字符与二进制数之间的对应规则。
2.字符集
- 字符集
Charset :也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。
计算机要准确的存储和识别各种字符集符号,需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有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辅助字符,使用四字节编码。
1.如果想要不出现乱码问题,编码和解码遵循的编码规则要一样
2.在GBK中,一个中文占2个字节
3.在UTF-8中,一个中文占3个字节
3.转换流_InputStreamReader
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();
}
}
4.转换流_OutputStreamWriter
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打印流基本使用
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();
}
}
使用场景:
可以用于将运行结果,过程打印到日志文件中
2.改变输出语句流向
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();
}
}
回顾
day23.IO流_网编
今日重点:
1.会使用序列化流读写对象
2.会使用Properties集合中的load方法解析properties配置文件
3.会手动导jar包,使用Commons-io
4.会使用Lombok完成一个标准的javabean
5.知道客户端和服务端之间的交互过程
第一章.序列化流
1.序列化流和反序列化流介绍
1.作用:读写对象
2.写对象(序列化流):ObjectOutputStream
3.读对象(反序列化流):ObjectInputStream
2.序列化流_ObjectOutputStream
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();
}
}
3.反序列化_ObjectInputStream
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();
}
}
4.不想被序列化操作(了解)
1.将成员变成静态的
2.瞬态关键字:transient
比如:
private transient Integer age
5.反序列化时出现的问题以及分析以及解决
1.问题描述:
如果对象的源码改动了,但是没有重新序列化,直接反序列化,就会爆出序列号冲突异常:InvalidClassException
解决:
方式1:源码改动,重新序列化一下子
方式2:直接将序列号定死:
在要被序列化的类中加上:private static final long serialVersionUID = 42L;
6.扩展(经验值)
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"));
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();
}
}
第二章.Properties集合结合IO使用(扩展)
1.Properties结合IO流使用方法
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 {
Properties properties = new Properties();
FileInputStream in = new FileInputStream("day23\\io\\pro.properties");
properties.load(in);
System.out.println(properties.getProperty("username"));
System.out.println(properties.getProperty("password"));
}
}
第三章.Commons-io工具包(扩展)
1.介绍
IO技术开发中,代码量很大,而且代码的重复率较高。如果我们要遍历目录,拷贝目录就需要使用方法的递归调用,也增大了程序的复杂度。
Apache软件基金会,开发了IO技术的工具类`commonsIO`,大大简化IO开发。
2.添加第三方jar包
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
3.工具包的使用
IOUtils类
- 静态方法:IOUtils.copy(InputStream in,OutputStream out)传递字节流,实现文件复制。
- 静态方法:IOUtils.closeQuietly(任意流对象)悄悄的释放资源,自动处理close()方法抛出的异常。
public class Test01_IOUtils {
public static void main(String[] args) throws FileNotFoundException {
System.out.println("============================");
FileWriter fw = null;
try {
fw = new FileWriter("day23\\io\\writer.txt");
fw.write("静静和晓楠");
} catch (Exception e) {
e.printStackTrace();
}finally {
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 {
String s = FileUtils.readFileToString(new File("day23\\io\\commons.txt"));
System.out.println(s);
}
}
第四章.Lombok使用(扩展)
1.lombok介绍
Lombok通过增加一些“处理程序”,可以让java变得简洁、快速。
Lombok能以注解形式来简化java代码,提高开发效率。开发中经常需要写的javabean,都需要花时间去添加相应的getter/setter,也许还要去写构造器、equals等方法,而且需要维护。
Lombok能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法。出现的神奇就是在源码中没有getter和setter方法,但是在编译生成的字节码文件中有getter和setter方法。这样就省去了手动重建这些代码的麻烦,使代码看起来更简洁些。
5.2 lombok使用
2.lombok常用注解
@Getter和@Setter
- 作用:生成成员变量的get和set方法。
- 写在成员变量上,指对当前成员变量有效。
- 写在类上,对所有成员变量有效。
- 注意:静态成员变量无效。
@ToString
- 作用:生成toString()方法。
- 注解只能写在类上。
@NoArgsConstructor和@AllArgsConstructor
- @NoArgsConstructor:无参数构造方法。
- @AllArgsConstructor:满参数构造方法。
- 注解只能写在类上。
@EqualsAndHashCode
- 作用:生成hashCode()和equals()方法。
- 注解只能写在类上。
@Data
- 作用:生成get/set,toString,hashCode,equals,无参构造方法
- 注解只能写在类上。
@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());
}
}
第五章.网络编程
1.软件结构
- C/S结构 :全称为Client/Server结构,是指客户端和服务器结构。常见程序有QQ、红蜘蛛、飞秋等软件。
B/S结构 :全称为Browser/Server结构,是指浏览器和服务器结构。常见浏览器有IE、谷歌、火狐等。
两种架构各有优势,但是无论哪种架构,都离不开网络的支持。网络编程,就是在一定的协议下,实现两台计算机的通信的程序。
2.服务器概念
是安装了服务器软件的计算机
网络通信协议:两台计算机在做数据交互时要遵守的规则,协议会对数据的格式,速率等进行规定,只有都遵守了这个协议,才能完成数据交互
两台计算机想完成数据交互,需要遵守网络通信协议
3.通信三要素
[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后,没有收到,那么彻底断开。
4.实现简单客户端和服务端的交互
4.1.编写客户端
步骤:
1.创建Socket对象,指明要连接的服务端的ip和端口号
2.调用Socket对象中的getOutputStream,获取OutputStream,用于往服务端发请求(写数据)
3.调用Socket对象中的getInputStream,获取InputStream,用于读取服务端发送过来的数据(读数据)
4.关流
public class Client {
public static void main(String[] args)throws Exception {
Socket socket = new Socket("127.0.0.1", 6666);
OutputStream os = socket.getOutputStream();
os.write("我想现在一个片儿".getBytes());
InputStream in = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = in.read(bytes);
System.out.println(new String(bytes,0,len));
in.close();
os.close();
socket.close();
}
}
4.2.编写服务端
步骤:
1.创建ServerSocket对象,设置端口号
2.调用ServerSocket中的accept方法,等待和获取客户端连接,返回Socket
3.调用Socket中的getInputStream,用于读取客户端发过来的请求
4.调用Socket中的getOutputStream,用于往客户端写响应信息
5.关流
public class Server {
public static void main(String[] args)throws Exception {
ServerSocket ss = new ServerSocket(6666);
Socket socket = ss.accept();
InputStream in = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = in.read(bytes);
System.out.println(new String(bytes,0,len));
OutputStream os = socket.getOutputStream();
os.write("我给你一个片儿,金瓶梅拿走".getBytes());
os.close();
in.close();
socket.close();
ss.close();
}
}
5.文件上传
5.1.文件上传客户端以及服务端实现
public class Client {
public static void main(String[] args)throws Exception {
Socket socket = new Socket("127.0.0.1", 6666);
FileInputStream fis = new FileInputStream("E:\\Idea\\io\\24.jpg");
OutputStream os = socket.getOutputStream();
byte[] bytes = new byte[1024];
int len;
while((len = fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
socket.shutdownOutput();
System.out.println("=============以下代码是读取响应===========");
InputStream in = socket.getInputStream();
byte[] bytes1 = new byte[1024];
int read = in.read(bytes1);
System.out.println(new String(bytes1,0,read));
in.close();
os.close();
fis.close();
socket.close();
}
}
public class Server {
public static void main(String[] args)throws Exception {
ServerSocket ss = new ServerSocket(6666);
Socket socket = ss.accept();
InputStream in = socket.getInputStream();
String name = System.currentTimeMillis()+""+new Random().nextInt()+".jpg";
FileOutputStream fos = new FileOutputStream("E:\\Idea\\io\\upload\\"+name);
byte[] bytes = new byte[1024];
int len;
while((len = in.read(bytes))!=-1){
fos.write(bytes,0,len);
}
System.out.println("=========以下代码是往客户端响应数据========");
OutputStream os = socket.getOutputStream();
os.write("上传成功".getBytes());
os.close();
fos.close();
in.close();
socket.close();
ss.close();
}
}
5.2.文件上传服务端实现(多线程)
public class Server {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(6666);
while (true) {
Socket socket = ss.accept();
new Thread(new Runnable() {
@Override
public void run() {
InputStream in = null;
FileOutputStream fos = null;
OutputStream os = null;
try {
in = socket.getInputStream();
String name = System.currentTimeMillis() + "" + new Random().nextInt() + ".jpg";
fos = new FileOutputStream("E:\\Idea\\io\\upload\\" + name);
byte[] bytes = new byte[1024];
int len;
while ((len = in.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
System.out.println("=========以下代码是往客户端响应数据========");
os = socket.getOutputStream();
os.write("上传成功".getBytes());
} catch (Exception e) {
e.printStackTrace();
} finally {
CloseUtils.closeQuietly(os,fos,in,socket);
}
}
}).start();
}
}
}
异常回顾:
父类中的方法没有抛异常,子类重写之后不能抛
父类中的方法抛异常了,子类重写之后可抛可不抛
5.3.关流工具类
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();
}
}
}
}
第六章.标准javabean
1.javabean的介绍
1.所谓的标准javabean其实就是指的是自己定义的实体类
2.一个标准的javabean包含:
私有属性
无参构造
有参构造
get/set方法
1.在开发中,我们是分包分层的,其实分层就是依靠创建不同的package,不同的类要放到不同的包下,好维护
2.在开发中如何分包分层:
com.atguigu.web -> 专门放和前端打交道的类
com.atguigu.service-> 专门放和业务打交道的类
com.atguigu.dao-> 专门放和数据库打交道的类
com.atguigu.javabean-> 专门放实体类
com.atguigu.utils-> 专门放工具类
2.javabean在开发中有啥用
javabean如何产生:一个javabean的出现,需要根据数据库中的表来确定
第七章.Lambda表达式
1.函数式编程思想和Lambda表达式定义格式
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();
}
}
2.Lambda表达式使用前提
1.必须有重写方法
2.必须有函数式接口做方法参数传递
函数式接口:接口中必须有且只有一个抽象方法的接口
检测函数式接口:在接口上面,加上@FunctionalInterface
3.新手怎么写Lambda表达式
1.观察是否是函数式接口做方法参数传递
2.如果是,可以考虑搞成Lambda表达式
3.先写一个匿名内部类
4.从new接口开始到重写方法的方法名结束,选中,删除,别忘记删除右半个大括号
5.在重写方法的参数后面,加上->
6.再看看根据省略规则,能不能进一步删除
4.Lambda表达式的省略规则
1.重写方法的参数类型可以省略
2.如果重写方法的参数只有一个,所在的小括号可以干掉
3.如果方法体中只有一句代码,所在的大括号可以干掉,分号干掉
4.如果方法体中只有一句代码,而且还是带return的,那么return,方法体大括号,分号都直接干掉
public class Test02_Lambda {
public static void main(String[] args) {
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();
}
}
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);
}
}
5.Lambda表达式练习
@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("鼠标");
}
}
|