文章目录
File:文件类,用来操作文件或文件夹(目录/路径)
-
创建文件
-
创建单层目录
-
创建多层目录
-
判断是否是文件
-
判断是或是路径
-
判断是否隐藏
public static void main(String[] args) throws IOException {
//1.创建File对象并关联了文件
//a:通过完整的路径实现
File file1 = new File("D:\\workspace\\BigData1715N19\\src\\com\\qianfeng\\test\\Demo1.java");
//b:通过父目录,子目录实现
File file2 = new File("D:\\workspace\\BigData1715N19","src\\com\\qianfeng\\test\\Demo1.java");
//c:先得到父目录的File对象
File file3 = new File("D:\\workspace\\BigData1715N19");
File file4 = new File(file3,"src\\com\\qianfeng\\test\\Demo1.java");
// * 创建文件
File file5 = new File("D:\\workspace\\BigData1715N19\\temp4.txt");
// file5.createNewFile();
//创建目录---这里只能创建目录
File file6 = new File("D:\\workspace\\BigData1715N19\\aa\\bb\\cc\\dd\\ee.txt");
// * 创建单层目录
//file6.mkdir();
// * 创建多层目录--也可以创建一层目录
file6.mkdirs();
// * 判断是否是文件
System.out.println(file3.isFile());
// * 判断是或是路径
System.out.println(file3.isDirectory());
// * 判断是否隐藏
System.out.println(file3.isHidden());
//获取文件的最后修改时间
long lastTime = file5.lastModified();
System.out.println(lastTime);
//进行格式的转换
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = simpleDateFormat.format(new Date(lastTime));
System.out.println(time);//2018-09-20 15:09:04
}
- 获取根目录
- 获取指定路径下的文件或文件夹
public static void main(String[] args) {
//* 获取根目录--获取的是当前主机的根目录
File[] files = File.listRoots();
for (File file : files) {
System.out.println(file);
}
System.out.println("***********");
//* 获取指定路径下的文件或文件夹---
//1.不包括自层 2.得到的是当前层的全部内容,包括文件和文件夹 3.不是全路径,知识文件或文件夹的名字
File file = new File("D:\\workspace\\BigData1715N19");
String[] strings = file.list();
for (String string : strings) {
System.out.println(string);
}
System.out.println("***********");
//获取的是当前目录的文件或文件夹的全路径(是以File对象的形式)
File[] files2 = file.listFiles();
for (File file2 : files2) {
System.out.println(file2);
}
}
递归:有条件的自己调用自己(方法)
-
条件:
- 要给一个出口负责结束当前的递归
- 循环次数不能太多,否则占用的内存过多,死机
-
死循环:1.自己调用自己(方法) 2.方法之间相互调用
求:1-100之间的和
public class Demo10 {
public static void main(String[] args) {
// int sum=0;
// for(int i=0;i<=100;i++){
// sum+=i;
// }
//使用递归
Dog.run();
}
}
class Dog{
static int sum = 0;
static int i=0;
public static void run(){
sum+=i;
System.out.println(sum);
if (i++ == 100) {
return;
}
run();
}
}
求1-10之间的所有偶数的积与所有奇数的积的差
public class Demo11 {
public static void main(String[] args) {
int value = getValue();
System.out.println(value);
}
static int jishuji = 1,oushuji = 1,i=1;
public static int getValue(){
//求偶数的积
if (i%2==0) {
oushuji*=i;
}
//求奇数的积
if (i%2!=0) {
jishuji*=i;
}
//得到差值
if (i++ == 10) {
return oushuji-jishuji;
}
//自己调用自己
int a = getValue();
return a;
}
}
字符缓冲流
字符缓冲流:又叫字符缓冲区,是为了提高读写的能力,本身没有读写的能力,要想进行读写,必须依靠字符流实现.
-
可以将缓缓流比作催化剂或者高速的小车
-
字符缓冲流分类:
- 字符缓冲读入流:BufferedReader 辅助读,没有读的能力
- 字符缓冲写出流:BufferedWriter 辅助写,没有写的能力
实例1
public static void main(String[] args) throws IOException {
//1.创建缓冲写入流,并关联写出流
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("temp1.txt"));
//2.写
bufferedWriter.write("bingbing1");
/*
* 换行,优点:有跨平台型
*/
bufferedWriter.newLine();
bufferedWriter.write("bingbing2");
//3.关闭流.a:关闭写出流 b:刷新 c:关闭缓冲写出流
bufferedWriter.close();
}
实例2
public class Demo3 {
public static void main(String[] args) throws IOException {
/*
* 1.字符缓冲读入流:BufferedReader 辅助读,没有读的能力
*/
//1.创建字符缓冲读入流的对象
BufferedReader reader = new BufferedReader(new FileReader("temp1.txt"));
//2.读
//a:一次读一个字符
// int num;
// while ((num = reader.read()) != -1) {
// System.out.print((char)num);
// }
//b:一次读多个字符
// int num;
// char[] arr = new char[4];
// while ((num = reader.read(arr)) != -1) {
// System.out.print(new String(arr,0,num));
// }
//c:一次读一行-readLine()
//特点:不会将当前的换行符返回 ;返回值就是我们读到的内容,以字符串的形式返回,当返回null的时候,说明读完了
String data = null;
while ((data = reader.readLine()) != null) {
System.out.print(data);
System.out.println();//打印到控制台时使用的换行符
}
//3.关闭流
reader.close();
}
}
实例3:使用字符缓冲流实现文件的拷贝
要求:
- 将Demo1.java的内容复制到Demo1copy.java
- 读的方式要采用三种
public class Demo4 {
public static void main(String[] args) throws IOException {
//1.创建缓冲读入流和缓冲写出流
BufferedReader bufferedReader = new BufferedReader(new FileReader("src/com/qianfeng/test/Demo1.java"));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("Demo1copy.java"));
//2.读写
//a:一个字符一个字符
// int num;
// while ((num = bufferedReader.read()) != -1) {
// bufferedWriter.write(num);
// }
//b:一次读多个字符
// int num;
// char[] arr = new char[10];
// while ((num = bufferedReader.read(arr)) != -1) {
// bufferedWriter.write(arr,0,num);
// }
//c:一次读一行
String data = null;
while ((data = bufferedReader.readLine()) != null) {
bufferedWriter.write(data);
bufferedWriter.newLine();
}
//3.关闭流
bufferedReader.close();
bufferedWriter.close();
}
}
设置行号
LineNumberReader:是BufferedReader的子类,不能读,但是可以提高效率,特有功能:设置行号,获取行号
public static void main(String[] args) throws IOException {
//1.创建缓冲流
LineNumberReader lineNumberReader = new LineNumberReader(new FileReader("src/com/qianfeng/test/Demo2.java"));
//设置行号:
//注意点:默认从0开始设置,从1开始计数
lineNumberReader.setLineNumber(0);
//2.读
String data = null;
while ((data = lineNumberReader.readLine()) != null) {
System.out.print(lineNumberReader.getLineNumber());//获取行号
System.out.print(data);
System.out.println();
}
//3.关闭流
lineNumberReader.close();
}
模拟BufferedReader
分析:
- 要属于流的体系
- 要有一个Reader类型的成员变量
- 要有一个带参数的方法接收外部的流对象
- 模拟readLine()方法,实现读一行的功能
- 重写close()方法
public class Demo6 {
public static void main(String[] args) throws IOException {
MyBufferedReader myBufferedReader = new MyBufferedReader(new FileReader("temp1.txt"));
String data = null;
while ((data = myBufferedReader.readLine()) != null) {
System.out.print(data);
System.out.println();
}
myBufferedReader.close();
}
}
//1.要属于流的体系
class MyBufferedReader extends Reader{
//2.要有一个Reader类型的成员变量
Reader reader;
//3.要有一个带参数的方法接收外部的流对象
public MyBufferedReader(Reader reader) {
this.reader = reader;
}
//4.模拟readLine()方法,实现读一行的功能
public String readLine() throws IOException {
//a:准备一个临时的可变字符串存储当前行的内容
StringBuffer stringBuffer = new StringBuffer();
//b:开始读
int num;
while ((num = reader.read()) != -1) {
if (num == '\r') {//继续读
continue;
}else if (num == '\n') {//停止读
return stringBuffer.toString();
}else {
stringBuffer.append((char)num);
}
}
//c:当文本没有内容时的处理:
if (stringBuffer.length() == 0) {
return null;
}
//d:当文本只有一行,没有换行符
return stringBuffer.toString();
//e:这里写提高效率的代码
}
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
// TODO Auto-generated method stub
return 0;
}
//5.重写close()方法
@Override
public void close() throws IOException {
//关闭读入流
this.reader.close();
//将自己关闭
//this.close();
}
}
两种设计模式
装饰设计模式
-
装饰设计模式:基于已经实现的功能,提供增强的功能.
-
装饰设计模式的由来就来自于对缓冲流的实现.
-
特点:从缓冲流的角度讲解
- 使流原来的继承体更加的简单
- 提高了效率
- 由于是在原有的基础上提高增强的功能,所以他还要属于原来的体系
-
演示:如果自己设计装饰设计模式,怎么处理?
- 原来的类 Test
- 装饰类 BTest
-
步骤:
- 让BTest 继承自Test
- 在BTest内有一个Test类型的成员变量
- 通过BTest内一个带参数的构造方法接收外部传入的一个Test类型的对象,交给内部的Test的属性
- 在实现功能的时候,调用传入的Test类型的对象实现原有的功能,自己实现增强的功能.
适配器设计模式
-
适配器设计模式:通常可以变相的理解成装饰设计模式
-
实例:要求在子类中只使用play方法
-
分析:
-
Dog是继承了ZiMidel类,ZiMidel类实现了Inter接口
-
当Dog类想要实现Inter接口的一个方法的时候,如果直接实现Inter接口,就必须将所有的方法都实现,
-
如果在Dog类与Inter接口之间插入一个类,让这个类去实现Inter接口的所有方法,作为这个类的子类只需要实现自己需要的方法
-
我们将中间的这个类就可以成为适配器类
-
interface Inter{
public void play();
public void song();
public void run();
public void eat();
public void jump();
}
//适配器类
class ZiMidel implements Inter{
@Override
public void play() {
// TODO Auto-generated method stub
}
@Override
public void song() {
// TODO Auto-generated method stub
}
@Override
public void run() {
// TODO Auto-generated method stub
}
@Override
public void eat() {
// TODO Auto-generated method stub
}
@Override
public void jump() {
// TODO Auto-generated method stub
}
}
//创建狗类,我只想让她实现play方法?
class Dog extends ZiMidel{
public void play() {
// TODO Auto-generated method stub
}
}
class Cat extends ZiMidel{
public void song() {
}
}
字符流:传输的是字节,只能用于字符的传输
- 字符读入流:Reader
- read() read(数组)
- 字符写出流:Writer
- write(int c) write(char[] arr) write(String s)
- 缓冲字符读入流:BufferedReader
- readLine()
- 缓冲字符写出流:Bufferedwriter
- newLine()
- 字节流:传输的是字节,可以传输所有的内容
- 字节输入流:Inputstream
- 字节输出流:OutputStream
- 缓冲字节输入流:BufferedInputStream
- 缓冲字节输出流:BufferedOutputStream
public static void main(String[] args) throws IOException {
//写
writeFile();
//读1
//readFile1();
//读2
//readFile2();
//读3
readFile3();
}
//写
public static void writeFile() throws IOException{
//创建字节写出流
OutputStream outputStream = new FileOutputStream("temp2.txt");
outputStream.write("bingbing".getBytes());//使用默认的格式编码
outputStream.close();
}
//读1--一次一个字节
public static void readFile1() throws IOException {
FileInputStream fileInputStream = new FileInputStream("temp2.txt");
int num;
while ((num = fileInputStream.read()) != -1) {
System.out.print((char)num);
}
fileInputStream.close();
}
//读2--一次多个字节
public static void readFile2() throws IOException {
FileInputStream fileInputStream = new FileInputStream("temp2.txt");
int num;
byte[] arr = new byte[4];
while ((num = fileInputStream.read(arr)) != -1) {
System.out.print(new String(arr,0,num));
}
fileInputStream.close();
}
//读3--一次全部读出
public static void readFile3() throws IOException {
FileInputStream fileInputStream = new FileInputStream("temp2.txt");
//获取的所有的字节数
//注意:如果文本的字节数太大不建议使用
int nums = fileInputStream.available();
int num;
byte[] arr = new byte[nums];
num = fileInputStream.read(arr);
System.out.print(new String(arr,0,num));
fileInputStream.close();
}
实例1:使用字节流实现图片的复制
public static void main(String[] args) throws IOException {
//1.创建字节输入流,输出流
FileInputStream fileInputStream = new FileInputStream("100.jpg");
FileOutputStream fileOutputStream = new FileOutputStream("100copy.jpg");
//2.完成读写
int num;
while ((num = fileInputStream.read()) != -1) {
fileOutputStream.write(num);
}
//3.关闭流
fileInputStream.close();
fileOutputStream.close();
}
实例2:使用字节缓冲流实现图片的复制
public static void main(String[] args) throws IOException {
//1.创建字节输入流,输出流
FileInputStream fileInputStream = new FileInputStream("100.jpg");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
FileOutputStream fileOutputStream = new FileOutputStream("100copy1.jpg");
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
//2.完成读写
int num;
while ((num = bufferedInputStream.read()) != -1) {
bufferedOutputStream.write(num);
}
//3.关闭流
bufferedInputStream.close();
bufferedOutputStream.close();
}
标准输入输出流
- 标准输入流:System.in:此流已经被打开,准备提供数据.这个流默认对应键盘(输入源)的输入或由主机或用户提供的输入源
- 标准输出流:System.out.
实例:要求可以从键盘不断的接收字节
public static void myReadLine(InputStream inputStream) throws IOException{
StringBuffer stringBuffer = new StringBuffer();
while (true) {
int num = inputStream.read();
if (num == '\r') {
continue;
}else if ( num == '\n') {
System.out.println(stringBuffer.toString());
//当输入over的时候认为是结束
if (stringBuffer.toString().equals("over")) {
break;
}
//清除上一次的内容
stringBuffer.delete(0, stringBuffer.length());
}else {
stringBuffer.append((char)num);
}
}
}
转换流:本身是字符流
-
分类:
- InputStreamReader:从字节输入流到字符读入流
- OutputStreamWriter:从字节输出流到字符写出流
-
场景:要使用字符缓冲流的readLine(),newLine()方法服务于字节流
实例:
使用字符缓冲流的readLine(),newLine()等方法实现在控制台一次读一行数据
public static void main(String[] args) throws IOException {
//将标准输入流转成字符缓冲读入流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
//将标准输出流转成字符缓冲写出流
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));
//读写
String data = null;
while ((data = bufferedReader.readLine()) != null) {
bufferedWriter.write(data);
bufferedWriter.newLine();
//手动刷新
bufferedWriter.flush();
//当输入over的时候结束
if (data.equals("over")) {
break;
}
}
//关闭流
bufferedReader.close();
bufferedWriter.close();
}
设备之间数据的传输:
输入输出源
- 设备分成输入源和输出源,
- 输入源:给内存提供数据的设备
- 输出源:从内存接收数据的设备
- 1
- 输入源:键盘
- 输出源:控制台
- 2
- 输入源:键盘
- 输出源:文件
- 3
- 输入源:文件
- 输出源:控制台
- 4
- 输入源:文件
- 输出源:文件
- 1
code
public static void main(String[] args) throws IOException {
//将键盘作为输入源
BufferedReader bufferedReader1 = new BufferedReader(new InputStreamReader(System.in));
//将文件作为输入源
BufferedReader bufferedReader2 = new BufferedReader(new FileReader("src/com/qianfeng/test/Demo1.java"));
//将文件作为输出源
BufferedWriter bufferedWriter1 = new BufferedWriter(new FileWriter("temp.txt"));
//将控制台作为输出源
BufferedWriter bufferedWriter2 = new BufferedWriter(new OutputStreamWriter(System.out));
//读写
// * 输入源:键盘
// * 输出源:控制台
String data = null;
// while ((data = bufferedReader1.readLine()) != null) {
// bufferedWriter2.write(data);
// bufferedWriter2.newLine();
//
// bufferedWriter2.flush();
// }
// * 输入源:键盘
// * 输出源:文件
// while ((data = bufferedReader1.readLine()) != null) {
// bufferedWriter1.write(data);
// bufferedWriter1.newLine();
//
// bufferedWriter1.flush();
// }
// * 输入源:文件
// * 输出源:控制台
// while ((data = bufferedReader2.readLine()) != null) {
// bufferedWriter2.write(data);
// bufferedWriter2.newLine();
//
// bufferedWriter2.flush();
// }
// * 输入源:文件
// * 输出源:文件
while ((data = bufferedReader2.readLine()) != null) {
bufferedWriter1.write(data);
bufferedWriter1.newLine();
bufferedWriter1.flush();
}
//资源关闭
bufferedReader1.close();
bufferedReader2.close();
bufferedWriter1.close();
bufferedWriter2.close();
}
更换输入源,输出源
- 注意:这里是临时更换,只能在当前程序中使用更换后的输入输出源,如果在其他的程序中会自动变回原来的键盘/控制台
实例:
从键盘到控制台 更换成 从文件到文件
public static void main(String[] args) throws IOException {
/*
* 更换输入源,输出源
* 注意:这里是临时更换,只能在当前程序中使用更换后的输入输出源,如果在其他的程序中会自动变回原来的键盘/控制台
*
* 实例:从键盘到控制台 更换成 从文件到文件
*/
//更换输入源 --从键盘到文件
System.setIn(new FileInputStream("src/com/qianfeng/test/Demo1.java"));
//更换输出源--从控制台到文件
System.setOut(new PrintStream("temp2.txt"));
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));
String data = null;
while ((data = bufferedReader.readLine()) != null) {
bufferedWriter.write(data);
bufferedWriter.newLine();
bufferedWriter.flush();
}
bufferedReader.close();
bufferedWriter.close();
}
字符打印流:
- 可以直接关联的设备(传入的参数)
- File类型的文件
- 字符串类型的文件
- 字节输出流
- 字符写出流
实例
public static void main(String[] args) throws IOException {
//实例:将数据从键盘接收传到控制台
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
//创建字符打印流
PrintWriter printWriter = new PrintWriter(System.out);
String data = null;
while ((data = bufferedReader.readLine()) != null) {
printWriter.println(data);
printWriter.flush();
}
bufferedReader.close();
printWriter.close();
}
序列流
把多个输入流的内容一次性的打印(操作)—字节流
实例
public static void main(String[] args) throws IOException {
//创建三个输入流
FileInputStream fileInputStream1 = new FileInputStream("src\\com\\qianfeng\\test\\Demo2.java");
FileInputStream fileInputStream2 = new FileInputStream("src\\com\\qianfeng\\test\\Demo2.java");
FileInputStream fileInputStream3 = new FileInputStream("src\\com\\qianfeng\\test\\Demo1.java");
//将三个输入流放入序列流
//方式一:先放入一个Vector
// Vector<FileInputStream> vector = new Vector<>();
// vector.add(fileInputStream1);
// vector.add(fileInputStream2);
// vector.add(fileInputStream3);
//
// //得到枚举器
// Enumeration<FileInputStream> e1 = vector.elements();
//方式二:先放入一个list
ArrayList<FileInputStream> list = new ArrayList<>();
list.add(fileInputStream1);
list.add(fileInputStream2);
list.add(fileInputStream3);
//将集合转换成枚举
Enumeration<FileInputStream> e2 = Collections.enumeration(list);
//创建序列流对象并关联相关的文件--参数是一个枚举器
//SequenceInputStream sequenceInputStream = new SequenceInputStream(e1);
SequenceInputStream sequenceInputStream = new SequenceInputStream(e2);
//创建输出流
FileOutputStream fileOutputStream = new FileOutputStream("temp2.txt");
//读写
byte[] arr = new byte[1024];
int num;
while ((num = sequenceInputStream.read(arr)) != -1) {
fileOutputStream.write(arr, 0, num);
fileOutputStream.flush();
}
sequenceInputStream.close();
fileOutputStream.close();
}
数据流:字节流
- DataInputStream: 数据输入流
- DataOutputStream: 数据输出流
- 注意:数据流要与字节输入流,输出流配合使用
实例
public static void main(String[] args) throws IOException {
//写
writeData();
//读
readData();
}
public static void writeData() throws IOException {
DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream("temp3.txt"));
//写
dataOutputStream.writeInt(97);//4个字节 00000000 00000000 000000000 011000001 00000001
dataOutputStream.writeBoolean(true);//1个
dataOutputStream.write(33);//1个
dataOutputStream.writeDouble(34.56);//8个
//关闭流
dataOutputStream.close();
}
public static void readData() throws IOException {
DataInputStream dataInputStream = new DataInputStream(new FileInputStream("temp3.txt"));
//这里的boolean型和int型的数据,在读的时候由于与之前写的顺序相反了,所以读取的数据错误
/*
* 注意点:1.读的顺序要与写的顺序一致 2.类型保持一致
*/
System.out.println(dataInputStream.readBoolean());// 00000000
System.out.println(dataInputStream.readInt());//00000000 000000000 011000001 00000001
System.out.println(dataInputStream.readByte());
System.out.println(dataInputStream.readDouble());
dataInputStream.close();
}
内存流(byte数组流):
- ByteArrayInputStream:写入内存,在内部有一个数组,数据被放在这里面
- ByteArrayOutputStream:将数据取出,放在字节数组里面
实例
public static void main(String[] args) throws IOException {
//创建输入流,关联一个byte型的数组,作为缓冲区数据
ByteArrayInputStream bais = new ByteArrayInputStream("hello world".getBytes());
//创建输出流-不需要指定参数
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] arr = new byte[1024];
int num;
while ((num = bais.read(arr)) != -1) {
baos.write(arr, 0, num);
}
System.out.println(new String(arr));
bais.close();
baos.close();
//注意:将流关闭了之后,还可以调用方法,不会报错.
baos.write(45);
}
Properties
这是一个类,可以理解成一个Map集合.存储的属性,属性以键值对的形式存在.键值对内部的键值必须是Stringng,所以不需要泛型.
- 为什么要在这里将Properties?
- 因为他的操作与流的关系非常的紧密.
优点:
1. 以键值对的形式存值
2. 内部封装了大量的方法,比如:load,stor,list等.方便操作.
实例
public static void main(String[] args) throws IOException {
//1.基本的操作
//function1();
//2.如果通过Properties获取系统的属性
//function2();
//3.理解Properties 的实际应用
function3();
}
//1.基本的操作
public static void function1(){
//创建Properties对象
Properties properties = new Properties();
//存值
properties.setProperty("01", "java");
properties.setProperty("02", "python");
properties.setProperty("01", "ok");
//取值
System.out.println(properties.getProperty("01"));
//获取所有的key
Set<String> set = properties.stringPropertyNames();
//遍历
//第一种--增强for循环
for (String key : set) {
System.out.println("key:"+key+"= value:"+properties.getProperty(key));
}
//第二种---迭代器
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
String key = (String) iterator.next();
System.out.println("key:"+key+"= value:"+properties.getProperty(key));
}
//注意点:当key不存在的时候,返回的是后面的默认值
String string = properties.getProperty("03", "iOS");
System.out.println(string);
}
//2.如果通过Properties获取系统的属性集合
public static void function2(){
//获取系统的属性集合
Properties properties = System.getProperties();
//遍历属性集合
Set<String> set = properties.stringPropertyNames();
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
String key = (String) iterator.next();
System.out.println("key:"+key+" = value:"+properties.getProperty(key));
}
//改变内部的值
properties.setProperty("user.language", "ch");
System.out.println(properties.getProperty("user.language"));
//重新获取一遍
//原理:会先到内存中找属性集合的对象,如果有,直接使用,如果没有,会重新初始化一个新的对象,获取属性集合.
Properties properties1 = System.getProperties();
System.out.println(properties1.getProperty("user.language"));
//将内容打印到控制台--list
properties1.list(System.out);
}
//3.理解Properties 的实际应用
public static void function3() throws IOException{
//创建属性集合对象
Properties properties = new Properties();
//创建输入流对象
FileReader fileReader = new FileReader("temp2.txt");
//将temp2.txt的内容加载到属性集合对象中
properties.load(fileReader);
//打印到控制台
//注意:要想打印的是正确的形式,必须保证txt文件本身是键值对的形式存在
properties.list(System.out);
//更改内容
properties.setProperty("01", "bingbingbang");
//将内容重新写回磁盘---借助输出流
FileWriter fileWriter = new FileWriter("temp2.txt");
properties.store(fileWriter, "bingbingchoule");//第二个参数是说明信息
fileReader.close();
fileWriter.close();
}
序列化流
将短期存储的数据实现长期存储的过程
短期与长期存储
* 短期存储:数据存放在内存中,数据会随着程序的关闭而释放----对象,数组,集合,变量
* 长期存储:数据存放在磁盘中,即使程序关闭了,数据依然存在----文件
序列化与逆序列化
* 序列化:将数据从内存存入磁盘,可以实现数据的持久化存储.
* 逆序列化:将数据从磁盘传回内存.
序列化步骤—以对象的序列化为实例
- 创建一个类
- 使用对应的流将对象存入磁盘—序列化—ObjectOutputStream
- 使用对应的流将数据从磁盘中取出放回内存—逆序列化-----ObjectInputStream
- 关闭流
-
注意:序列化流在工作时也要关联输入流和输出流
-
创建类用于序列化类通过实现java.io.Serializable接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。
-
可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。
-
解释:
- 一个类如果没有实现Serializable,进行序列化会报异常:NotSerializableException
-
实现了Serializable接口的类可以达到的目的:
- 可以进行序列化
- 进行序列化的类的元素都必须支持序列化
- 接口本身没有方法或字段,只是用来表示可序列化的语义
-
注意点:
-
ClassNotFoundException:当前的类没有找到
- 分析:将Person对象进行序列化之后,将Person类删除,再进行反序列化的时候出现了异常
- 原因:反序列化在执行的时候依赖字节码文件,当类没有了,字节码文件无法创建,反序列化失败
-
java.io.InvalidClassException无效的类
- 出现的原因:没有声明自己的serialVersionUID,而使用系统的.在进行反序列化的时候,类被改动了,系统认为现在的类
- 已经不是原来的类了(在使用系统的id进行识别的时候,重写给Person设置了id),认为此类无效
-
使用系统的serialVersionUID与自定义的ID的区别?
- 使用系统的,序列化和反序列化,id不能手动设置,使用的是编译器默认生成的,一旦类发生了改动,id会重新赋值
- 使用自定义的,序列化和反序列化,id不会发生改变,所以当反序列化的时候,即使对Person类进行了一些改动,也能继续反序列化
-
总结序列化,反序列化工程的注意点:
- 合理使用序列化流和反序列化流,要与输入流与输出流配合使用
- 进行序列化的类一定要实现Serializable接口,只要实现了接口就可以序列化.包括集合,包装类等
- 进行序列化的类要保证当前类与内部的类都要实现Serializable接口
-
实例
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
//序列化
//fun1();
//逆序列化
fun2();
}
//序列化
public static void fun1() throws FileNotFoundException, IOException{
//创建序列化流并关联文件
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("temp4.txt"));
//实现序列化
//注意:序列化后得到的内容不能直接查看,要看必须经过逆序列化
objectOutputStream.writeObject(new Person("bingbing",20));
//关闭流
objectOutputStream.close();
}
//逆序列化
public static void fun2() throws FileNotFoundException, IOException, ClassNotFoundException {
//创建逆序列化流并关联文件
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("temp4.txt"));
//实现逆序列化--读
Object object = objectInputStream.readObject();
Person person = (Person)object;
System.out.println(object);
//关闭流
objectInputStream.close();
}
}
//创建一个类
//这个类的对象要想进行序列化必须实现Serializable接口.
//类通过实现Serializable接口启动序列化功能.未实现此接口的类无法实现序列化或逆序列化.
//如果没有实现Serializable,会报异常NoSerializableException
//注意点:可序列化的对象的内部的元素也要都支持序列化.
class Person implements Serializable{
/**
* generated:由编译器自动生成的,后面加L表示long型数据
*
* */
private static final long serialVersionUID = 9100147150931711124L;
// /**
// * default:默认的方式,可以由用户自己指定,默认值是1L
// */
// private static final long serialVersionUID = 17489587495847L;
String name;
int age;
//int height;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Person [name=" + name + ", 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;
}
}