黑马程序员技术交流社区
标题: 【石家庄校区】Lambda、IO流、File类、缓冲流和序列化流等 [打印本页]
作者: wlxHeiMa追梦 时间: 2018-8-7 17:18
标题: 【石家庄校区】Lambda、IO流、File类、缓冲流和序列化流等
本帖最后由 wlxHeiMa追梦 于 2018-8-7 17:30 编辑
Lambda、IO流、File类、缓冲流和序列化流等
序列化流(对象流)
1. 序列化流分为两种 : 序列化和反序列化
1.1 什么是序列化?
把对象以流的方式写入到文件中保存,叫做对象的序列化,也可以叫做写对象.对象被写入到文件中保存,因为对象中包含的不仅仅是字符,也可以包含视频.音频.文件.等等,所以文件中存储的形式统统为字节形式.
ObjectOutputStream : 对象的序列化流
1.2 什么是反序列化?
磁盘文件中的字节序列, 以流的方式读取到内存中变成对象字节转对象.把文件中保存的对象,以流的方式读取出来,叫做对象的反序列化,也叫做读对象.因为文件中保存的对象都是以字节形式保存的,所以用字节流读取.
ObjectInputStream :对象的反序列化流
一. ObjectOutputStream类(对象字节输出流)
定义.使用格式.包含方法.方法使用场景
OutputStream的子类 :
概念 : ObjectOutputStream类(对象字节输出流): : 将Java对象的原始数据类型写出到文件,实现对象的持久存储
创建一个指定OutputStream的ObjectOutputStream
序列化的具体操作步骤 :
1. 一个对象如果想要被序列化, 必须满足两个条件:
1.1 :该类必须实现 java.io.Serializable 接口, Serializable 是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException异常 。注意事项 : 没有序列化异常
1.2 : 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用transient 关键字修饰。
编程单词汇总 :
(1) : close 关闭
(2) : address 地址
(3) : Stream : 流
(4) : write : 写
(5) : final : 最终的
(6) : read : 阅读
(7) : Stack : 栈
(8) : Object : 对象
(9) : InputStream : 输入流
(10) : readobject : 读取对象
(11) : getname : 获得名称
(12) : getAge : 获得年龄
InputStream的子类 :
ObjectInputStream类: 对象字节输入流:
ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。
反序列化操作 :
如果能找到一个对象的class文件,我们可以进行反序列化操作,调用ObjectInputStream 读取对象的方法
public final Object readObject () : 读取一个对象。
反序列化的前提 :
1. 类必须实现Serializable
2.必须存在类对应的class文件
【File类、递归】
一 File类
1.1概述
类是文件和目录路径名的抽象表示,主要用于文件和目录的创建.查找和删除等操作.
注 : File : 把路径名用String字符串的形式表现了出来.
1.2 构造方法
public File(Stringpathname) :通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
public File(Fileparent, String child) :从父抽象路径名和子路径名字符串创建新的 File实例。
问题汇总:
1. 什么是绝对路径?
回答: 从盘符开始,路径一直到所选择的文件名称.
2. 什么是相对路径?
回答: 所选择的文件名称或者文件名相对于上一个文件夹名. 这个所选择的文件名称就是相对路径.
3. 什么是父子路径?
回答: 在一个完整路径中,从哪里截取,在完整路径中截取的前半段就是父路径,截取的后半段就是子路径.
注意事项:
1. 文件返回的大小,用字节数表示(int 数字).文件有具体的大小,文件夹没有,所以返回的结果是0(不能获取目录的大小)
2. 一个File对象代表硬盘中实际存在的一个文件或者目录.
3. 无论该路径下是否存在文件或者目录,都不影响File对象的创建
1.3 常用方法
判断功能的方法 :
public boolean exists():此File表示的文件或目录是否实际存在。
public booleanisDirectory() :此File表示的是否为目录。
public boolean isFile():此File表示的是否为文件(不要与文件夹混淆,只是文件)。
创建删除功能的方法:
public booleancreateNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
public boolean delete():删除由此File表示的文件或目录。
public boolean mkdir() :创建由此File表示的目录???
public boolean mkdirs():创建由此File表示的目录,包括任何必需但不存在的父目录????.
1.4 目录的遍历
public String[ ] list():返回一个String数组,表示该File目录中的所有子文件或目录。
public File[ ]listFiles() :返回一个File数组,表示该File目录中的所有的子文件或目录。
区别在于: list只打印当前的文件或文件夹名称
listFiles打印完整的路径名称,从盘符开始.
【递归】
递归概述:
递归:指在当前方法内调用自己的这种现象。
递归的分类:
递归分为两种,直接递归和间接递归。
直接递归称为方法自身调用自己。
间接递归可以A方法调用B方法,B方法调用C方法,C方法调用A方法。
注意事项:
递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出。
在递归中虽然有限定条件,但是递归次数不能太多。否则也会发生栈内存溢出。
构造方法,禁止递归
递归是我们编程思想中很重要的一部分,今天我以一些小案例,简单介绍一下递归的使用(数学逻辑推导).
描述:
猴子吃桃子问题(改编版),猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第二天又将仅剩下的桃子吃掉了一半,又多吃了一个。以后每天都吃了前一天剩下的一半多一个。到第n天,只剩下一个桃子。试求第x(x<n)天共有多少桃子?
一、分析:
从描述中我们可以得出以下几个结论:
1. x天剩下的桃子,即x天的桃子数;
2. 假设x天桃子数为S,那么从描述中可得:S(n)=1;
3. 从描述中得出规律:S(n-1)=[S(n)+1]*2,S(n-2)=[ S(n-1)+1]*2 ……S(x)=[S(x+1)+1]*2
二、从分析得计算数学公式:
S(x)=[S(x+1)+1]*2
file:///C:/Users/29316/AppData/Local/Temp/msohtmlclip1/01/clip_image002.png
三、编程步骤:
1. 从分析可以看出,我们需要键盘键入两个变量:x和n;
2. 定义一个方法(含两个参数x和n),进行递归调用
3. 传入x和n,得出结果
四、示例代码如下:
[Java] 纯文本查看 复制代码
public class PeachDiGuiTest01 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("请输入剩下一个桃子的天数");
int n=sc.nextInt();
System.out.println("要想计算第x天剩下的桃子,请告诉我x:");
int x = sc.nextInt();
int result=getPeachSum(n,x);
System.out.println(result);
}
private static int getPeachSum(int n,int x) {
if(x==n){
return 1;
}
return (getPeachSum(n,x+1)+1)*2;
}
}
五、总结:递归简单来说:从编程角度说:就是自己调用自己。从数学角度说:就是从已知推出未知的过程。递归之所以重要,就是因为它可以推出未知,毕竟生活中,未知远大于已知,因此,递归思想就越发显得重要。六、附加代码这是一些比较简单的使用递归的代码,方便我们更好的理解递归。
1) 递归求和(1-100)
[AppleScript] 纯文本查看 复制代码
public class DiGuiDemo {
public static void main(String[] args) {
//计算1~num的和,使用递归完成
int num = 100;
// 调用求和的方法
int sum = getSum(num);
// 输出结果
System.out.println(sum);
}
/*
通过递归算法实现.
参数列表:int
返回值类型: int
*/
public static int getSum(int num) {
/*
num为1时,方法返回1,
相当于是方法的出口,num总有是1的情况
*/
if(num == 1){
return 1;
}
/*
num不为1时,方法返回 num +(num‐1)的累加
递归调用getSum方法
*/
2)递归求阶乘(5!)
[Java] 纯文本查看 复制代码
public class DiGuiDemo {
//计算n的阶乘,使用递归完成
public static void main(String[] args) {
int n = 5;
// 调用求阶乘的方法
int value = getValue(n);
// 输出结果
System.out.println("阶乘为:"+ value);
}
/*
通过递归算法实现.
参数列表:int
返回值类型: int
*/
public static int getValue(int n) {
// 1的阶乘为1
if (n == 1) {
return 1;
}
/*
n不为1时,方法返回 n! = n*(n‐1)!
递归调用getValue方法
*/
return n * getValue(n ‐ 1);
}
}
3)文件搜索
[Java] 纯文本查看 复制代码
public class DiGuiDemo3 {
public static void main(String[] args) {
// 创建File对象
File dir = new File("D:\\aaa");
// 调用打印目录方法
printDir(dir);
}
public static void printDir(File dir) {
// 获取子文件和目录
File[] files = dir.listFiles();
// 循环打印
for (File file : files) {
if (file.isFile()) {
// 是文件,判断文件名并输出文件绝对路径
if (file.getName().endsWith(".java")) {
System.out.println("文件名:" + file.getAbsolutePath());
}
} else {
// 是目录,继续遍历,形成递归
printDir(file);
}
}
}
}
IO流
一.什么是IO流?
(1) : 输入(In)
(2) : 输出(Out)流
(3) : 流: 数据流
作用 :
输入(In): 把数据从硬盘读取到内存
输出(Out) : 把数据从内存读取到硬盘
(这里的入和出都是相对于内存来说的)
二.IO流的分类
总共分为两类: 字节流 和 字符流
2.1 字节流 : 读写字节: byte, 可以读写所有类型的文件,包括视频, 图片, 音频, 文本等
字节流分为两个类:
字节输入流 :java.io.InputStream 抽象类
字节输出流 :java.io.OutputStream 抽象类
2.2 字符流 : (读写字符: char,String, 只能读写文本文件)
字符流分为两个类:
字符输入流: java.io.Reader 抽象类
字符输出流: java.io.Writer 抽象类
三.字节流
基本常识:
计算机中的一切皆为字节.
计算机中, 无论文本, 视频, 音频, 图片...一切都是以"字节byte"形式存储的
也就是以数字形式存储的, 而数字可以用不同进制表示,计算机能看懂的是二进制数字.
3.1 字节输出流: OutputStream和FileOutputStream
java.io.OutputStream抽象类:字节输出流 (顶层类) :
OutputStream 内包含五个成员方法,其中五个成员方位分为两类: 成员方法及写字节的成员方法
成员方法 (包含两个):
(1) : close : 释放资源.一般在方法代码末尾.
(2) : flush : 刷新缓冲区(对于字节流来说没有任何作用)
写字节的成员方法(包含三个) :
(1): abstract void write(int b): 一次写一个字节 (参数是int是为了代码中写表示byte的整数方便不用强转)
(2): void write(byte[] b): 一次写一个字节数组
(3): void write(byte[] b, int off, int len): 一次写一个字节数组的一部分
字节输出流 : 一次写一个字节到文件
Java程序将数据写入文件的原理 :
Java程序 -> JVM虚拟机 -> OS操作系统 -> OS调用写数据的方法 -> 将数据写入文件
使用字节输出流写数据到文件的步骤(一共为三步)
1. 创建对象: 创建FileOutputStream对象, 构造方法中传递文件路径
2. 写入数据: 使用FileOutputStream对象调用write(int b) 方法, 将字节写入文件
3. 释放资源: 使用FileOutputStream对象调用close() 方法, 关闭流对象释放资源
文件存储原理和记事本打开文件的原理
基本常识 :
(1) 向文件中写入字节数据时, 写入的是什么进制的数据?
向文件中写入字节数据时, 十进制的数字会被转换为"二进制"的数字写入文件.计算机能看懂的是二进制数字.
(2) 写入文件的是数字, 但文本编辑器打开后为什么会显示为字符?
文本编辑器打开文本文件时, 会先查询编码表, 将二进制数字转换为对应的字符进行显示
0-127: 查询ASCII码表
其他: 查询系统默认码表
Windows简体中文系统的程序打开是按GBK 码表
IDEA中使用的是 UTF-8 码表
ASCII编码表: 1个byte就是一个字符
GBK编码表: 2个byte数字组成一个汉字."你": -60, -29
UTF-8编码表: 3个byte数字组成一个汉字."你": -28, -67, -96
字节输出流: 一次写多个字节
java.io.FileOutputStream类:文件字节输出流 (向文件写数据)
void write(byte[] b): 一次写一个字节数组
void write(byte[] b,int off, int len): 一次写一个字节数组的一部分
重点 :
java.lang.String类:
byte[] getBytes(): 使用平台的默认字符集将此String编码为byte数组. 使用当前编译平台的默认字符集将String类型的数据用byte数据类型表达出来.
什么是字符集?
字节输出流: 续写操作
(1) 什么是续写操作?
在文件已有内容之后, 接着写入内容 (续写).
(2) 如何在文件中写入换行, Windows系统的换行符号是什么?
换行符:
Windows系统:"\r\n"
Linux系统: "\n"
MacOS系统: "\r"
带有 "续写" 功能的构造方法,不会清空文件
FileOutputStream(Stringname, boolean append): 通过文件路径创建文件字节输出流, true可以续写
FileOutputStream(Filefile, boolean append): 通过File对象创建文件字节输出流, true可以续写
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |