转换流

在学习字符流(FileReader、FileWriter)的时候,其中说如果需要指定编码和缓冲区大小时,可以在字节流的基础上,构造一个InputStreamReader或者OutputStreamWriter,这又是什么意思呢?

OutputStreamWriter类

查阅OutputStreamWriter的API介绍,OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的字符编码表,将要写入流中的字符编码成字节。它的作用的就是,将字符串按照指定的编码表转成字节,再使用字节流将这些字节写出去。

代码演示:

 public static void writeCN() throws Exception { 
//创建与文件关联的字节输出流对象 
        FileOutputStream fos = new FileOutputStream("D:\\cn8.txt"); 
//创建可以把字符转成字节的转换流对象,并指定编码 
        OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8"); 
//调用转换流,把文字写出去,其实是写到转换流的缓冲区中 
        osw.write("你好");//写入缓冲区。 
        osw.close(); 
    }

OutputStreamWriter流对象,它到底如何把字符转成字节输出的呢?

其实在OutputStreamWriter流中维护自己的缓冲区,当我们调用OutputStreamWriter对象的write方法时,会拿着字符到指定的码表中进行查询,把查到的字符编码值转成字节数存放到OutputStreamWriter缓冲区中。然后再调用刷新功能,或者关闭流,或者缓冲区存满后会把缓冲区中的字节数据使用字节流写到指定的文件中。

InputStreamReader类

查阅InputStreamReader的API介绍,InputStreamReader 是字节流通向字符流的桥梁:它使用指定的字符编码表读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。

代码演示 

package io; 
 
import java.io.FileInputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
 
/** 
 * Created by Administrator on 2017/7/19. 
 */ 
public class InputStreamReaderDemo { 
    public static void main(String[] args) throws IOException { 
//演示字节转字符流的转换流 
        readCN(); 
    } 
 
    public static void readCN() throws IOException { 
//创建读取文件的字节流对象 
        InputStream in = new FileInputStream("d:\\cn8.txt"); 
//创建转换流对象 
//InputStreamReader isr = new InputStreamReader(in);这样创建对象,会用本地默认码表读取,将会发生错误解码的错误 
        InputStreamReader isr = new InputStreamReader(in, "utf-8"); 
//使用转换流去读字节流中的字节 
        int ch = 0; 
        while ((ch = isr.read()) != -1) { 
            System.out.println((char) ch); 
        } 
//关闭流 
        isr.close(); 
    } 
}

注意:在读取指定的编码的文件时,一定要指定编码格式,否则就会发生解码错误,而发生乱码现象。

转换流和子类区别

发现有如下继承关系:

OutputStreamWriter 
  |--FileWriter 
InputStreamReader 
  |--FileReader;

父类和子类的功能有什么区别呢?

OutputStreamWriter和InputStreamReader是字符和字节的桥梁:也可以称之为字符转换流。字符转换流原理:字节流+编码表。

FileWriter和FileReader:作为子类,仅作为操作字符文件的便捷类存在。当操作的字符文件,使用的是默认编码表时可以不用父类,而直接用子类就完成操作了,简化了代码。

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//默认字符集。 
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字符集。 
FileReader fr = new FileReader("a.txt");

这三句代码的功能是一样的,其中第三句最为便捷。注意:一旦要指定其他编码时,绝对不能用子类,必须使用字符转换流。什么时候用子类呢?

条件:1、操作的是文件。2、使用默认编码。

总结

字节--->字符 : 看不懂的--->看的懂的。 需要读。输入流。 InputStreamReader

字符--->字节 : 看的懂的--->看不懂的。 需要写。输出流。 OutputStreamWriter

缓冲流

在我们学习字节流与字符流的时候,大家都进行过读取文件中数据的操作,读取数据量大的文件时,读取的速度会很慢,很影响我们程序的效率,那么,我想提高速度,怎么办?

Java中提高了一套缓冲流,它的存在,可提高IO流的读写速度。缓冲流,根据流的分类,分为字节缓冲流与字符缓冲流。

字节缓冲流

字节缓冲流根据流的方向,共有2个

  • 写入数据到流中,字节缓冲输出流 BufferedOutputStream
  • 读取流中的数据,字节缓冲输入流 BufferedInputStream

它们的内部都包含了一个缓冲区,通过缓冲区读写,就可以提高了IO流的读写速度

字节缓冲输出流BufferedOutputStream

通过字节缓冲流,进行文件的读写操作 写数据到文件的操作

构造方法

public BufferedOutputStream(OutputStream out)创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
package io; 
 
import java.io.BufferedOutputStream; 
import java.io.FileOutputStream; 
import java.io.IOException; 
 
/** 
 * Created by Administrator on 2017/7/19. 
 */ 
public class BufferedOutputStreamDemo01 { 
    public static void main(String[] args) throws IOException { 
//写数据到文件的方法 
        write(); 
    } 
/* 
* 写数据到文件的方法 
* 1,创建流 
* 2,写数据 
* 3,关闭流 
*/ 
    private static void write() throws IOException { 
//创建基本的字节输出流 
        FileOutputStream fileOut = new FileOutputStream("abc.txt"); 
//使用高效的流,把基本的流进行封装,实现速度的提升 
        BufferedOutputStream out = new BufferedOutputStream(fileOut); 
//2,写数据 
        out.write("hello".getBytes()); 
//3,关闭流 
        out.close(); 
    } 
}

字节缓冲输入流 BufferedInputStream

刚刚我们学习了输出流实现了向文件中写数据的操作,那么,现在我们完成读取文件中数据的操作

构造方法 

public BufferedInputStream(InputStream in)
/* 从文件中读取数据 
* 1,创建缓冲流对象 
* 2,读数据,打印 
* 3,关闭 
*/ 
    private static void read() throws IOException { 
//1,创建缓冲流对象 
        FileInputStream fileIn = new FileInputStream("abc.txt"); 
//把基本的流包装成高效的流 
        BufferedInputStream in = new BufferedInputStream(fileIn); 
//2,读数据 
        int ch = -1; 
        while ((ch = in.read()) != -1) { 
//打印 
            System.out.print((char) ch); 
        } 
//3,关闭 
        in.close(); 
    }

使用基本的流与高效的流完成复制文件

我们一直在说,高效的流速度快并高效,怎么体现呢?需要通过一个复制文件耗时的比较过程,来体验一下高效流带来的快感。

package io; 
/* 
 
* 需求:将d:\\test.avi文件进行复制 
* 采用4种方式复制 
* 方式1: 采用基本的流,一次一个字节的方式复制 共耗时 224613毫秒 
* 方式2: 采用基本的流,一个多个字节的方式赋值 共耗时 327毫秒 
* 方式3: 采用高效的流,一次一个字节的方式复制 共耗时 2047毫秒 
* 方式4: 采用高效的流,一个多个字节的方式赋值 共耗时 96毫秒 
* 
 
* 数据源: d:\\test.avi 
* 目的地1: d:\\copy1.avi 
* 目的地2: d:\\copy2.avi 
* 目的地3: d:\\copy3.avi 
* 目的地4: d:\\copy4.avi 
* 
 
* 实现的步骤: 
* 1,指定数据源 
* 2,指定目的地 
* 3,读数据 
* 4,写数据 
* 5,关闭流 
* 
*/ 
 
import java.io.*; 
 
public class CopyAVI { 
    public static void main(String[] args) throws IOException { 
//开始计时 
        long start = System.currentTimeMillis(); 
//方式1: 采用基本的流,一次一个字节的方式复制 
//method1("d:\\test.avi", "d:\\copy1.avi"); 
//方式2: 采用基本的流,一个多个字节的方式赋值 
//method2("d:\\test.avi", "d:\\copy2.avi"); 
//方式3: 采用高效的流,一次一个字节的方式复制 
//method3("d:\\test.avi", "d:\\copy3.avi"); 
//方式4: 采用高效的流,一个多个字节的方式赋值 
        method4("d:\\test.avi", "d:\\copy4.avi"); 
//结束计时 
        long end = System.currentTimeMillis(); 
//打印耗时多少毫秒 
        System.out.println("共耗时 " +(end - start)+ "毫秒"); 
    } 
//方式4: 采用高效的流,一个多个字节的方式赋值 
    private static void method4(String src, String dest) throws IOException { 
//1,指定数据源 
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(src)); 
//2,指定目的地 
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest)); 
//3,读数据 
        byte[] buffer = new byte[1024]; 
        int len = -1; 
        while ( (len = in.read(buffer)) != -1) { 
//4,写数据 
            out.write(buffer, 0, len); 
        } 
//5,关闭流 
        in.close(); 
        out.close(); 
    } 
//方式3: 采用高效的流,一次一个字节的方式复制 
    private static void method3(String src, String dest) throws IOException { 
//1,指定数据源 
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(src)); 
//2,指定目的地 
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest)); 
//3,读数据 
        int ch = -1; 
        while ((ch=in.read()) != -1) { 
//4,写数据 
            out.write(ch); 
        } 
//5,关闭流 
        in.close(); 
        out.close(); 
    } 
 
//方式2: 采用基本的流,一个多个字节的方式赋值 
    private static void method2(String src, String dest) throws IOException { 
//1,指定数据源 
        FileInputStream in = new FileInputStream(src); 
//2,指定目的地 
        FileOutputStream out = new FileOutputStream(dest); 
//3,读数据 
        byte[] buffer = new byte[1024]; 
        int len = -1; 
        while ( (len=in.read(buffer)) != -1) { 
//4,写数据 
            out.write(buffer, 0, len); 
        } 
//5,关闭流 
        in.close(); 
        out.close(); 
    } 
 
//方式1: 采用基本的流,一次一个字节的方式复制 
    private static void method1(String src, String dest) throws IOException { 
//1,指定数据源 
        FileInputStream in = new FileInputStream(src); 
//2,指定目的地 
        FileOutputStream out = new FileOutputStream(dest); 
//3,读数据 
        int ch = -1; 
        while (( ch=in.read()) != -1) { 
//4,写数据 
            out.write(ch); 
        } 
//5,关闭流 
        in.close(); 
        out.close(); 
    } 
}

字符缓冲流

  • 字符缓冲输入流 BufferedReader
  • 字符缓冲输出流 BufferedWriter

完成文本数据的高效的写入与读取的操作

字符缓冲输出流 BufferedWriter

将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

方法:void newLine() 根据当前的系统,写入一个换行符

package io; 
 
/* 
* BufferedWriter 字符缓冲输出流 
* 方法 
* public void newLine()写入一个行分隔符 
* 
* 需求: 通过缓冲输出流写入数据到文件 
* 分析: 
* 1,创建流对象 
* 2,写数据 
* 3,关闭流 
* 
*/ 
 
import java.io.BufferedWriter; 
import java.io.FileWriter; 
import java.io.IOException; 
 
public class BufferedWriterDemo { 
    public static void main(String[] args) throws IOException { 
//创建流 
//基本字符输出流 
        FileWriter fileOut = new FileWriter("file.txt"); 
//把基本的流进行包装 
        BufferedWriter out = new BufferedWriter(fileOut); 
//2,写数据 
        for (int i=0; i<5; i++) { 
            out.write("hello"); 
            out.newLine(); 
        } 
//3,关闭流 
        out.close(); 
    } 
}

字符缓冲输入流 BufferedReader

从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

方法 :public String readLine() 读取一个文本行,包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null

package io; 
 
/* 
* BufferedReader 字符缓冲输入流 
* 
 
* 方法: 
* String readLine() 
* 需求:从文件中读取数据,并显示数据 
*/ 
 
import java.io.BufferedReader; 
import java.io.FileReader; 
import java.io.IOException; 
 
public class BufferedReaderDemo { 
    public static void main(String[] args) throws IOException { 
//1,创建流 
        BufferedReader in = new BufferedReader(new FileReader("file.txt")); 
//2,读数据 
//一次一个字符 
//一次一个字符数组 
//一次读取文本中一行的字符串内容 
        String line = null; 
        while( (line = in.readLine()) != null ){ 
            System.out.println(line); 
        } 
//3,关闭流 
        in.close(); 
    } 
}

使用字符缓冲流完成文本文件的复制

刚刚我们学习完了缓冲流,现在我们就使用字符缓冲流的特有功能,完成文本文件的复制

package io; 
 
/* 
* 采用高效的字符缓冲流,完成文本文件的赋值 
* 
 
* 数据源: file.txt 
* 目的地: copyFile.txt 
* 
 
* 分析: 
* 1,指定数据源, 是数据源中读数据,采用输入流 
* 2,指定目的地,是把数据写入目的地,采用输出流 
* 3,读数据 
* 4,写数据 
* 5,关闭流 
*/ 
 
import java.io.*; 
 
public class CopyTextFile { 
    public static void main(String[] args) throws IOException { 
//1,指定数据源, 是数据源中读数据,采用输入流 
        BufferedReader in = new BufferedReader(new FileReader("file.txt")); 
//2,指定目的地,是把数据写入目的地,采用输出流 
        BufferedWriter out = new BufferedWriter(new FileWriter("copyFile.txt")); 
//3,读数据 
        String line = null; 
        while ( (line = in.readLine()) != null ) { 
//4,写数据 
            out.write(line); 
//写入换行符号 
            out.newLine(); 
        } 
//5,关闭流 
        out.close(); 
        in.close(); 
    } 
}

流的操作规律

IO流中对象很多,解决问题(处理设备上的数据时)到底该用哪个对象呢?  

把IO流进行了规律的总结(四个明确):

明确一:要操作的数据是数据源还是数据目的。

  • 源:InputStream    Reader
  • 目的:OutputStream Writer

先根据需求明确要读,还是要写。 

明确二:要操作的数据是字节还是文本呢?

源:

  • 字节:InputStream
  • 文本:Reader

目的:

  • 字节:OutputStream
  • 文本:Writer

已经明确到了具体的体系上。 

明确三:明确数据所在的具体设备。

源设备:

  • 硬盘:文件  File开头。
  • 内存:数组,字符串。
  • 键盘:System.in;
  • 网络:Socket

目的设备:

  • 硬盘:文件  File开头。
  • 内存:数组,字符串。
  • 屏幕:System.out
  • 网络:Socket

完全可以明确具体要使用哪个流对象。

明确四:是否需要额外功能呢?

额外功能:

  • 转换吗?转换流。InputStreamReader OutputStreamWriter
  • 高效吗?缓冲区对象。BufferedXXX

InputStream

FileInputStream

BufferedInputStream 

OuputStream

FileOutputStream

BufferedOuputStream 

Writer

OutputStreamWriter

FileWriter

BufferedWriter

Reader

InputStreamReader

FileReader

BufferedReader

总结

字节流

字节输入流 InputStream

  • FileInputStream 操作文件的字节输入流
  • BufferedInputStream高效的字节输入流

字节输出流 OutputStream

  • FileOutputStream 操作文件的字节输出流
  • BufferedOutputStream 高效的字节输出流

字符流

字符输入流 Reader

  • FileReader 操作文件的字符输入流
  • BufferedReader 高效的字符输入流
  • InputStreamReader 输入操作的转换流(把字节流封装成字符流)

字符输出流 Writer

  • FileWriter 操作文件的字符输出流
  • BufferedWriter 高效的字符输出流
  • OutputStreamWriter 输出操作的转换流(把字节流封装成字符流)

方法

读数据方法:

  • read() 一次读一个字节或字符的方法
  • read(byte[] char[]) 一次读一个数组数据的方法
  • readLine() 一次读一行字符串的方法(BufferedReader类特有方法)
  • readObject() 从流中读取对象(ObjectInputStream特有方法)

写数据方法:

  • write(int) 一次写一个字节或字符到文件中
  • write(byte[] char[]) 一次写一个数组数据到文件中
  • write(String) 一次写一个字符串内容到文件中
  • writeObject(Object ) 写对象到流中(ObjectOutputStream类特有方法)
  • newLine() 写一个换行符号(BufferedWriter类特有方法)

向文件中写入数据的过程

  1. 创建输出流对象
  2. 写数据到文件
  3. 关闭输出流

从文件中读数据的过程

  1. 创建输入流对象
  2. 从文件中读数据
  3. 关闭输入流

文件复制的过程

  1. 创建输入流(数据源)
  2. 创建输出流(目的地)
  3. 从输入流中读数据
  4. 通过输出流,把数据写入目的地
  5. 关闭流

Properties类

Properties类表示了一个持久的属性集。Properties可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。

特点:

  • Hashtable的子类,map集合中的方法都可以用。
  • 该集合没有泛型。键值都是字符串。
  • 它是一个可以持久化的属性集。键值可以存储到集合中,也可以存储到持久化的设备(硬盘、U盘、光盘)上。键值的来源也可以是持久化的设备。
  • 有和流技术相结合的方法。
load(InputStream)  把指定流所对应的文件中的数据,读取出来,保存到Propertie集合中 
load(Reader)   
store(OutputStream,commonts)把集合中的数据,保存到指定的流所对应的文件中,参数commonts代表对描述信息 
stroe(Writer,comments);

代码演示:

package io; 
 
import java.util.Properties; 
import java.util.Set; 
/* 
 * 
 * Properties集合,它是唯一一个能与IO流交互的集合 
 * 
 * 需求:向Properties集合中添加元素,并遍历 
 * 
 * 方法: 
 * public Object setProperty(String key, String value)调用 Hashtable 的方法 put。 
 * public Set<String> stringPropertyNames()返回此属性列表中的键集, 
 * public String getProperty(String key)用指定的键在此属性列表中搜索属性 
 */ 
public class PropertiesDemo01 { 
    public static void main(String[] args) { 
        //创建集合对象 
        Properties prop = new Properties(); 
        //添加元素到集合 
        //prop.put(key, value); 
        prop.setProperty("周迅", "张学友"); 
        prop.setProperty("李小璐", "贾乃亮"); 
        prop.setProperty("杨幂", "刘恺威"); 
 
        //System.out.println(prop);//测试的使用 
        //遍历集合 
        Set<String> keys = prop.stringPropertyNames(); 
        for (String key : keys) { 
            //通过键 找值 
            //prop.get(key) 
            String value = prop.getProperty(key); 
            System.out.println(key+"==" +value); 
        } 
    } 
}

将集合中内容存储到文件 

package io; 
 
import java.io.FileWriter; 
import java.io.IOException; 
import java.util.Properties; 
 
//需求:使用Properties集合,完成把集合内容存储到IO流所对应文件中的操作 
//分析: 
//1,创建Properties集合 
//2,添加元素到集合 
//3,创建流 
//4,把集合中的数据存储到流所对应的文件中 
//stroe(Writer,comments) 
//store(OutputStream,commonts) 
//把集合中的数据,保存到指定的流所对应的文件中,参数commonts代表对描述信息 
//5,关闭流 
// 
//代码演示: 
public class PropertiesDemo02 { 
    public static void main(String[] args) throws IOException { 
        //1,创建Properties集合 
        Properties prop = new Properties(); 
        //2,添加元素到集合 
        prop.setProperty("周迅", "张学友"); 
        prop.setProperty("李小璐", "贾乃亮"); 
        prop.setProperty("杨幂", "刘恺威"); 
 
        //3,创建流 
        FileWriter out = new FileWriter("prop.properties"); 
        //4,把集合中的数据存储到流所对应的文件中 
        prop.store(out, "save data"); 
        //5,关闭流 
        out.close(); 
    } 
}

读取文件中的数据,并保存到集合

package io; 
 
import java.io.FileInputStream; 
import java.io.IOException; 
import java.util.Properties; 
 
//需求:从属性集文件prop.properties 中取出数据,保存到集合中 
//        分析: 
//        1,创建集合 
//        2,创建流对象 
//        3,把流所对应文件中的数据 读取到集合中 
//        load(InputStream)  把指定流所对应的文件中的数据,读取出来,保存到Propertie集合中 
//        load(Reader) 
//        4,关闭流 
//        5,显示集合中的数据 
//        代码演示: 
public class PropertiesDemo03 { 
    public static void main(String[] args) throws IOException { 
        //1,创建集合 
        Properties prop = new Properties(); 
        //2,创建流对象 
        FileInputStream in = new FileInputStream("prop.properties"); 
//FileReader in = new FileReader("prop.properties"); 
        //3,把流所对应文件中的数据 读取到集合中 
        prop.load(in); 
        //4,关闭流 
        in.close(); 
        //5,显示集合中的数据 
        System.out.println(prop); 
 
    } 
}

注意:使用字符流FileReader就可以完成文件中的中文读取操作了。

序列化流与反序列化流 

用于从流中读取对象的操作流 ObjectInputStream 称为 反序列化流;用于向流中写入对象的操作流 ObjectOutputStream 称为 序列化流

特点:用于操作对象。可以将对象写入到文件中,也可以从文件中读取对象。

对象序列化流ObjectOutputStream

ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。

只能将支持 java.io.Serializable 接口的对象写入流中

代码演示:

package io; 
 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.ObjectOutputStream; 
 
public class ObjectStreamDemo { 
    public static void main(String[] args) throws IOException, ClassNotFoundException { 
        /* 
         * 将一个对象存储到持久化(硬盘)的设备上。 
         */ 
        writeObj();//对象的序列化。 
    } 
    public static void writeObj() throws IOException { 
        //1,明确存储对象的文件。 
        FileOutputStream fos = new FileOutputStream("obj.object"); 
        //2,给操作文件对象加入写入对象功能。 
        ObjectOutputStream oos = new ObjectOutputStream(fos); 
        //3,调用了写入对象的方法。 
        oos.writeObject(new Person("wangcai",20)); 
        //关闭资源。 
        oos.close(); 
    } 
}

Person类

package io; 
 
import java.io.Serializable; 
 
public class Person implements Serializable { 
    private String name; 
    private int age; 
    public Person() { 
        super(); 
    } 
    public Person(String name, int age) { 
        super(); 
        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 + "]"; 
    } 
}

对象反序列化流ObjectInputStream

 ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。支持 java.io.Serializable接口的对象才能从流读取。

 代码演示:

package io; 
 
import java.io.FileInputStream; 
import java.io.IOException; 
import java.io.ObjectInputStream; 
 
public class ObjectStreamDemo1 { 
    public static void main(String[] args) throws IOException, ClassNotFoundException { 
        readObj();//对象的反序列化。 
    } 
    public static void readObj() throws IOException, ClassNotFoundException { 
        //1,定义流对象关联存储了对象文件。 
        FileInputStream fis = new FileInputStream("obj.object"); 
        //2,建立用于读取对象的功能对象。 
        ObjectInputStream ois = new ObjectInputStream(fis); 
        Person obj = (Person)ois.readObject(); 
        System.out.println(obj.toString()); 
    } 
}

序列化接口 

当一个对象要能被序列化,这个对象所属的类必须实现Serializable接口。否则会发生异常NotSerializableException异常。
同时当反序列化对象时,如果对象所属的class文件在序列化之后进行的修改,那么进行反序列化也会发生异常InvalidClassException。发生这个异常的原因如下:

  • 该类的序列版本号与从流中读取的类描述符的版本号不匹配
  • 该类包含未知数据类型
  • 该类没有可访问的无参数构造方法

Serializable标记接口。该接口给需要序列化的类,提供了一个序列版本号。serialVersionUID. 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。

代码修改如下,修改后再次写入对象,读取对象测试。 

public class Person implements Serializable { 
    //给类显示声明一个序列版本号。 
    private static final long serialVersionUID = 1L; 
    private String name; 
    private int age; 
    public Person() { 
        super(); 
         
    } 
    public Person(String name, int age) { 
        super(); 
        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 + "]"; 
    } 
}

瞬态关键字transient 

当一个类的对象需要被序列化时,某些属性不需要被序列化,这时不需要序列化的属性可以使用关键字transient修饰。只要被transient修饰了,序列化时这个属性就不会被序列化了。
同时静态修饰也不会被序列化,因为序列化是把对象数据进行持久化存储,而静态的属于类加载时的数据,不会被序列化。
代码修改如下,修改后再次写入对象,读取对象测试。

public class Person implements Serializable { 
    /* 
     * 给类显示声明一个序列版本号。 
     */ 
    private static final long serialVersionUID = 1L; 
    private static String name; 
    private transient/*瞬态*/ int age; 
     
    public Person() { 
        super(); 
         
    } 
     
    public Person(String name, int age) { 
        super(); 
        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 + "]"; 
    } 
}

打印流

打印流添加输出数据的功能,使它们能够方便地打印各种数据值表示形式.

打印流根据流的分类:

  • 字节打印流 PrintStream
  • 字符打印流 PrintWriter

方法:

  • void print(String str): 输出任意类型的数据,
  • void println(String str): 输出任意类型的数据,自动写入换行操作
package io; 
 
import java.io.IOException; 
import java.io.PrintWriter; 
 
/* 
* 需求:把指定的数据,写入到printFile.txt文件中 
* 
* 分析: 
*     1,创建流 
*     2,写数据 
*     3,关闭流 
*/ 
public class PrintWriterDemo { 
    public static void main(String[] args) throws IOException { 
        //创建流 
        //PrintWriter out = new PrintWriter(new FileWriter("printFile.txt")); 
        PrintWriter out = new PrintWriter("printFile.txt"); 
        //2,写数据 
        for (int i=0; i<5; i++) { 
            out.println("helloWorld"); 
        } 
        //3,关闭流 
        out.close(); 
    } 
}

打印流完成数据自动刷新

可以通过构造方法,完成文件数据的自动刷新功能

构造方法:开启文件自动刷新写入功能

  • public PrintWriter(OutputStream out, boolean autoFlush)
  • public PrintWriter(Writer out, boolean autoFlush)
package io; 
 
import java.io.FileWriter; 
import java.io.IOException; 
import java.io.PrintWriter; 
 
/* 
 * 分析: 
 *     1,创建流 
 *     2,写数据 
 */ 
public class PrintWriterDemo2 { 
    public static void main(String[] args) throws IOException { 
        //创建流 
        PrintWriter out = new PrintWriter(new FileWriter("printFile.txt"), true); 
        //2,写数据 
        for (int i=0; i<5; i++) { 
            out.println("helloWorld"); 
        } 
        //3,关闭流 
        out.close(); 
    } 
}

commons-IO

1、导入classpath

  • 加入classpath的第三方jar包内的class文件才能在项目中使用
  • 创建lib文件夹
  • 将commons-io.jar拷贝到lib文件夹
  • 导入jar包

2、FilenameUtils
这个工具类是用来处理文件名(译者注:包含文件路径)的,他可以轻松解决不同操作系统文件名称规范不同的问题
常用方法:

  • getExtension(String path):获取文件的扩展名;
  • getName():获取文件名;
  • isExtension(String fileName,String ext):判断fileName是否是ext后缀名;

3、FileUtils
提供文件操作(移动文件,读取文件,检查文件是否存在等等)的方法。
常用方法:

  • readFileToString(File file):读取文件内容,并返回一个String;
  • writeStringToFile(File file,String content):将内容content写入到file中;
  • copyDirectoryToDirectory(File srcDir,File destDir);文件夹复制
  • copyFile(File srcFile,File destFile);文件夹复制

代码演示:

package io; 
 
import org.apache.commons.io.FileUtils; 
 
import java.io.*; 
 
/* 
 * 完成文件的复制 
 */ 
public class CommonsIODemo01 { 
    public static void main(String[] args) throws IOException { 
        //method1("D:\\test.avi", "D:\\copy.avi"); 
        //通过Commons-IO完成了文件复制的功能 
        FileUtils.copyFile(new File("D:\\test.avi"), new File("D:\\copy.avi")); 
 
        //通过Commons-IO完成了文件夹复制的功能 
        //D:\java 复制到 C:\\abc文件夹下 
        FileUtils.copyDirectoryToDirectory(new File("D:\\java"), new File("C:\\abc")); 
    } 
}

 

发布评论

分享到:

IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

Java基础学习笔记二十一 多线程详解
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。