File类
- File类和四大家族没有关系,所以File类不能完成文件的读和写。
- File对象代表什么?
- 文件和目录路径名的抽象表示形式。
- 一个File对象有可能对应的是目录,也有可能是文件。
代码示例
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class FileTest01 {
public static void main(String[] args) {
// 创建一个file对象 指定一个路径
File file = new File("/Users/a1/Desktop/Java/Simon_JavaSE/test");
// 判断该路径下文件是否存在
System.out.println(file.exists());
if (!file.exists()){ // 文件不存在,
try {
// 以文件的形式新建
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
// 以目录(文件夹)形式新建
// file.mkdir();
}
File file1 = new File("/Users/a1/Desktop/Java/Simon_JavaSE/a/b/c/test.text");
System.out.println(file1.exists());
if (!file1.exists()){ // 不存在
// 多重目录(文件夹)的形式新建
file1.mkdirs();
}
// 获取文件的父路径
String parentPath = file.getParent();
System.out.println("获取父路径:" + parentPath);// /Users/a1/Desktop/Java/Simon_JavaSE
File parentFile = file.getParentFile();
System.out.println("获取绝对路径:" + parentFile.getAbsolutePath());
// 获取绝对路径
File file2 = new File("src/temp3");
System.out.println("获取绝对路径:" + file2.getAbsolutePath());
// 获取文件名
System.out.println("文件名:" + file.getName());
// 判断是否是一个目录
System.out.println(file.isDirectory());
// 判断是否是一个文件
System.out.println(file.isFile());
// 获取文件最后一次修改时间
long hm = file.lastModified(); //从1970年到现在的总毫秒数
Date time = new Date(hm);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String strTime = sdf.format(time);
System.out.println(strTime);
// 获取文件大小
System.out.println(file.length());
// 获取当前目录下所有的子文件
File file4 = new File("/Users/a1/Desktop/Java/Simon_JavaSE");
File[] fileList = file4.listFiles();
// foreach
for (File fl : fileList){
System.out.println(fl.getAbsolutePath());
System.out.println(fl.getName());
}
}
}
拷贝目录demo
import java.io.*;
public class CopyCatalogue {
public static void main(String[] args) {
// 拷贝源
File srcFile = new File("/Users/a1/Desktop/Java/Simon_JavaSE/JavaTest");
// 拷贝目标
File disFile = new File("/Users/a1/Desktop/Java/Simon_JavaSE/JavaTest-Copy");
// 调用方法进行拷贝
copyDir(srcFile,disFile);
}
/**
* 拷贝目录
* @param srcFile 拷贝源
* @param disFile 拷贝目标
*/
private static void copyDir(File srcFile, File disFile) {
if (srcFile.isFile()){
// srcFile是一个文件时,递归结束。
// 是文件需要拷贝,一边读一边写...
FileInputStream fin = null;
FileOutputStream fos = null;
try {
// 读取这个文件
fin = new FileInputStream(srcFile);
// 写到这个文件中
String absolutePath = disFile.getAbsolutePath();
String path = (absolutePath.endsWith("/") ? absolutePath: absolutePath + "/") + srcFile.getAbsolutePath().substring(45);
fos = new FileOutputStream(path);
// 一边读一边写
byte[] bytes = new byte[1024 * 1024]; // 一次复制1MB
int readCount = 0;
while ((readCount = fin.read(bytes)) != -1){
fos.write(bytes,0,readCount);
}
// 刷新
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fin != null){
try {
fin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return;
}
if (srcFile.isFile()){
return;
}
// 获取拷贝源下面的子目录
File[] files = srcFile.listFiles();
for (File file : files){
// 获取所有文件的绝对路径
if (file.isDirectory()){
String srcDir = file.getAbsolutePath();
String disAbsolutePath = disFile.getAbsolutePath();
String desDir = disAbsolutePath.endsWith("/") ? disAbsolutePath : disAbsolutePath + "/" + srcDir.substring(45);
File newFile = new File(desDir);
if (!newFile.exists()){
newFile.mkdirs();
}
}
// 递归调用
copyDir(file,disFile);
}
}
}
序列化和反序列化
参与序列化和反序列化的对象,必须实现Serializable接口。
-
通过源代码发现Serializable接口只是一个标志接口:
- public interface Serializable{}
- 这个接口当中什么代码都没有,起标识、标志的作用;java虚拟机看到这个类实现了这个接口,会对这个类进行特殊待遇。
- Serializable这个标志接口是给java虚拟机参考的,java虚拟机看到这个接口之后,会为该类自动生成一个序列化版本号。
-
transient关键字:
- 表示游离的,不参与序列化。
-
java语言中是采用什么机制区分类的
- 1,通过类名进行比对,如果类名不一样,肯定不是同一个类
- 2,如果类名一样,靠序列化版本号进行区分。
-
自动生成序列化版本号的缺陷:
- 自动生成的序列化版本号缺点是:一旦代码确定之后,不能进行后续修改,因为只有修改,必然会重新编译,
此时会生成全新的序列化版本号,这个时候java虚拟机会认为这是一个全新的类。(如果没有重新序列化,
只进行反序列化操作,会报异常)。
- 自动生成的序列化版本号缺点是:一旦代码确定之后,不能进行后续修改,因为只有修改,必然会重新编译,
开发中建议序列版本号手动写出,不建议自动生成。
代码示例
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class ObjectOutputStreamTest01 {
public static void main(String[] args) {
// 创建java对象
Student student = new Student(1231,"张小五");
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
ObjectOutputStream oosList = null;
ObjectInputStream oisList = null;
try {
// 序列化
oos = new ObjectOutputStream(new FileOutputStream("Student"));
// 序列化对象
oos.writeObject(student);
// 刷新
oos.flush();
// 反序列化 对象
ois = new ObjectInputStream(new FileInputStream("Student"));
// 开始反序列化
Object obj = ois.readObject();
System.out.println(obj);
// ----------------------------------------------------------------------------
// 序列化
oosList = new ObjectOutputStream(new FileOutputStream("StudentList"));
// 创建集合对象
List list = new ArrayList<>();
// 创建学生对象
Student student1 = new Student(12,"张小六");
Student student2 = new Student(13,"王小六");
Student student3 = new Student(14,"李小六");
Student student4 = new Student(15,"胡小六");
// 添加元素
list.add(student1);
list.add(student2);
list.add(student3);
list.add(student4);
// 序列化一个集合
oosList.writeObject(list);
// 刷新
oosList.flush();
// 反序列化集合
oisList = new ObjectInputStream(new FileInputStream("StudentList"));
Object redObj = oisList.readObject();
// 开始反序列化
if (redObj instanceof List){ // 如果是List集合
// 进行类型转换
List objs = (List) redObj;
// 变量输出
for (Student o : objs){
System.out.println(o);
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (oos != null){
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (ois != null){
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (oosList != null){
try {
oosList.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (oisList != null){
try {
oisList.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
class Student implements Serializable {
// java虚拟机看到Serializable接口之后,会为该类自动生成一个序列化版本号。
// 当Student这个类源代码改动了,需要重新编译,编译之后生成新的字节码文件。
// 并且class文件再次运行的时候,java虚拟机生成的序列版本号也会发生相应的改变。
// 如果没有重新序列化的时候,进行反序列化时会报异常。
// 序列化版本号在没有手动写出的时候,系统会提供默认序列化版本号
// 建议序列版本号手动写出,不建议自动生成
private static final long serialVersionUID = 124234343342l;
// idea工具 生成序列化版本号:" alt + 回车"
private int no;
// private String name;
private transient String name; //name不参与序列化操作
public Student() {
}
public Student(int no, String name) {
this.no = no;
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}
IO+Properties的联合使用:
Properties是一个Map集合,key和value都是String类型。
-
这种设计理念的好处:
- 遇到经常要改动的数据,可以单独写到一个文件中,使用程序动态读取;将来只需要修改这个文件的内容,
java代码不需要改动,不需要重新编译,服务器也不需要重启;就可以拿到动态信息。
- 遇到经常要改动的数据,可以单独写到一个文件中,使用程序动态读取;将来只需要修改这个文件的内容,
-
类似于以上机制的这种文件被称为配置文件。
-
配置文件中的内容格式如下, 我们把这种配置文件称为:属性配置文件。
key1=value key2=value ...
-
java规范中有要求:属性配置文件建议以.properties结尾,但不是必须的。
Properties是专门存放属性配置文件内容的一个类。(在属性配置文件中#是注释)
代码示例
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
public class IoPropertiesTest01 {
public static void main(String[] args) {
// 新建一个输入流对象
FileReader reader = null;
try {
// 在src文件夹下新建一个userInfo文档
// 内容填充: name=zhangsan password=123466 (记得换行)
reader = new FileReader("src/userInfo");
// 新建一个Map集合
Properties pro = new Properties();
// 调用Properties对象的load方法将文件中的数据加载到Map集合中。
pro.load(reader); //文件中的数据顺着管道加载到Map集合中:等号左边做key、右边做value
// 通过key获取value
System.out.println(pro.getProperty("name"));
System.out.println(pro.getProperty("password"));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
上篇:JavaSE进阶九 IO流一
下篇:JavaSE进阶十 线程一