一、数据流
输入输出的数据带有类型,文件中不旦保留了数据内容本身,还保留了所存储数据的类型,不是纯文本文件,使用很少,简单了解。
二、重定向标准输入输出流
Java的标准输入输出分别通过System.in和System.out来代表,在默认情况下它们分别指向键盘和显示器,当程序通过System.in来获取输入时,实际上是从键盘读取输入;当程序通过System.out执行输出时,程序总是输出到屏幕。
在System类里提供了如下三个重定向方法,用来改变标准输入输出的方向:
- static void setErr(PrintStream err):重定向“标准”错误输出流。
- static void setIn(InputStream in):重定向“标准”输入流。
static void setOut(PrintStream out):重定向“标准”输出流。
class Test{public static void main(String[] args) throws IOException {// 默认输出到显示器System.out.println("hello");//合起来写PrintStream ps = System.out;//创建一个PrintStream对象ps.println("a");//分开写ps.println(1);// 标准输出流不需要手动close()// 创建PrintStream输出流,指向test.txt文件PrintStream printStream = new PrintStream(new FileOutputStream("test.txt"));// 将标准输出重定向到printStream输出System.setOut(printStream);// 输出printStream.println("hello");//向test.txt文件写hello}}
三、File类
1.理解File
File类是java.io包下代表与平台无关的文件和目录,是文件和目录的抽象表现形式(即一个File对象对应一个文件或一条路径),在程序中操作文件和目录都可以通过File类来完成。要注意的是,不管是文件还是目录都是使用File类来操作的,File能新建、删除、重命名文件和目录,但File不能访问文件内容本身。如果需要访问文件内容本身,需要使用输入输出流。
2.File常用方法
class Test{public static void main(String[] args) throws IOException {File f1 = new File("D:\\file");//创建一个File对象System.out.println(f1.exists());//判断该文件是否存在if (!f1.exists()){f1.createNewFile();//不存在则以文件形式创建}if (!f1.exists()){f1.mkdir();//不存在则以目录形式创建}File f2 = new File("D:\\a\\b\\c\\d");if (!f2.exists()){f2.mkdirs();//以多重目录形式创建}System.out.println(f2.getParent());//获取父路径System.out.println(f2.getParentFile().getAbsolutePath());//获取父文件的绝对路径System.out.println("文件名:" + f1.getName());//获取文件名System.out.println(f1.isDirectory());//判断是否为一个目录System.out.println(f1.isFile());//判断是否为一个文件// 获取文件最后一次修改时间long count = f1.lastModified();//返回的是从1970年到现在的毫秒数// 将总毫秒数转化为日期(日期格式化)Date time = new Date(count);SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String strTime = date.format(count);System.out.println(strTime);System.out.println(f1.length());//获取文件大小//获取当前目录下的所有子文件File f = new File("D:");File[] files = f.listFiles();//返回的是一个File数组for (File file : files) {System.out.println(file.getName());}}}
四、对象序列化
1.序列化的含义和意义
对象序列化机制允许把内存中的Java对象转换成与平台无关的二进制流,从而将对象保存到磁盘中,或允许在网络中直接传输对象,以备以后重新恢复成原来的对象。序列化机制使得对象可以脱离程序的运行而独立存在。
对象的序列化(Serialize)指将一个Java对象写入IO流中,与此对应的是,对象的反序列化(Deserialize)则指从IO流中恢复该Java对象。
如果需要让某个对象支持序列化机制,则必须让它的类是可序列化的(serializable)。为了让某个类是可序列化的,该类必须实现如下两个接口之一:Serializable
- Externalizable
Java中的很多类已经实现了Serializable,该接口是一个标记接口,标记接口中无方法,它只是表明该类的实例是可序列化的,当Java虚拟机看到该类实现了Serializable接口后,会为该类自动生成一个序列化版本号。
2.序列化和反序列化的实现
class Student implements Serializable{int age;String name;public Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}}public class Test{public static void main(String[] args) throws IOException, ClassNotFoundException {// 序列化// 创建Java对象Student s = new Student(23, "sundegan");// 创建序列化流ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test"));// 序列化对象oos.writeObject(s);// 刷新oos.flush();// 关闭oos.close();//反序列化ObjectInputStream ois = new ObjectInputStream(new FileInputStream("test"));Object obj = ois.readObject();System.out.println(obj);ois.close();}}//Student{age=23, name='sundegan'}
3.序列化多个对象
将对象放到集合中,序列化集合对象。如果不使用集合,直接序列化多个对象会报错。
class Student implements Serializable{int age;String name;public Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}}public class Test{public static void main(String[] args) throws IOException, ClassNotFoundException {// 序列化多个对象List<Student> list = new ArrayList<>();list.add(new Student(1,"a"));list.add(new Student(2,"b"));list.add(new Student(3,"c"));ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test"));oos.writeObject(list);oos.flush();oos.close();//反序列化ObjectInputStream ois = new ObjectInputStream(new FileInputStream("test"));List<Student> stuList = (List<Student>) ois.readObject();for (Student s : stuList) {System.out.println(s);}ois.close();}}//Student{age=1, name='a'}//Student{age=2, name='b'}//Student{age=3, name='c'}
4.transient关键字
transient关键字表示游离的,用该关键字修饰的成员不参与序列化。
class Student implements Serializable{int age;transient String name;//name属性不会被序列化public Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}}
5.序列化版本号
5.1 序列化版本号作用
序列化是Java中实现持久化存储的一种方法;为数据传输提供了线路级对象表示法。 Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。
首先我们要知道java语言中采用什么机制来区分类,不同的人编写了同样的一个类,但是这两个类其实并不等于同一个类。
1.首先通过类名比较,如果类名一样则靠序列号区分。
java虚拟机看到Serilezable接口后,会默认的生成一个序列化版本号,序列化版本号也可以手动提供。
自动生成序列化版本号的好处:虚拟机可以根据序列化版本号区分开这两个类。
自动生成序列化版本号的缺陷:一旦代码确定之后,不能进行后续的修改。因为修改之后就会重新的编译,
此时会生成新的序列化版本号,java虚拟机会认为这是一个全新的类。
所有凡是一个类实现了Serializable接口,建议给这个类提供一个固定不变的序列化版本号
这样在后续如果修改了代码,Java虚拟机也会认为这是同一个类。
5.2 手动添加序列化版本号
ublic class Users {//手动序列化版本号方法private static final long serialVersionUID = 1l;}
5.3 IDEA自动生成序列化版本号配置
- 进入Setting

- 在自定义类的时候,将光标放到类名上,按alt+enter快捷键提示自动添加序列化版本号

- 最后效果如下
public class Person implements java.io.Serializable{private static final long serialVersionUID = 6342241044575234092L;}
五、IO和Properties联合使用
IO:文件的读写。
Properties:是一个Map集合,key和value都是String类型。1.作用
可以将代码中一些经常发生变化的信息放到文件当中,Java程序动态地去读取文件信息,信息发生改变时只需去更改文件内容,而不需要修改代码,可以避免Java程序的重新编译和服务器的重新部署,就可以拿到动态的信息。2.例子
将userinfo文件里的数据加载到Properties对象中。username=adminpassword=123
使用以上机制的文件称为配置文件,并且当文件中的内容格式是(不要有空格):public class Test{public static void main(String[] args) throws IOException {// 新建一个输入流对象FileReader reader = new FileReader("userinfo");// 新建一个Map集合Properties pro = new Properties();// 调用Properties对象的load方法将文件中的数据加载到Map集合pro.load(reader);//文件数据加载到map集合中,等号=左边做key,右边做value// 通过key获取valueSystem.out.println(pro.getProperty("username"));System.out.println(pro.getProperty("password"));}}
key1=value1
key2=value2
的时候,我们把这种配置文件称为属性配置文件。Java规范中有要求:属性配置文件建议以.properties为后缀名,但这不是必须的。这种以.properties为后缀的文件在Java中被称为属性配置文件,其中Properties是专门存放属性配置文件内容的一个类。
