java之IO流3 Properties、字节缓冲流、字符缓冲流、转换流、序列化、打印流

目录

Properties

字节缓冲流

字符缓冲流

转换流

转换流的原理及使用

序列化

transient

打印流


Properties

是已经被淘汰的Hashtable<K,V>的子类,但是是唯一和IO相结合的集合

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

 

可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储

可以使用load方法把硬盘中保存的文件(键值对),读取到集合中使用

 

属性列表中每个键及其对应值都是一个字符串

Properties集合是一个双列集合,key和value默认都是字符串

 

 

演示及方法:

 /*

    Properties集合中有一些操作字符串的特有方法

        Object setProperty(String key,String value)调用Hashtable的方法put

        String getProperty(String key)通过key找value,相当于Map集合中的get(key)方法、

        set<String> stringPropertyName()返回此属性列表中的键值,其中该键值及其对应值是字符串,此方法相当于Map集合中的keySet方法

    */

    public static void main(String[] args) {

        Properties prop=new Properties();

        prop.setProperty("1","name1");

        prop.setProperty("2","name2");

        prop.setProperty("3","name3");

        //存储到set集合

        Set<String> set = prop.stringPropertyNames();

        //遍历

        for (String s : set) {

            System.out.println(s+"="+prop.getProperty(s));

        }

 //store方法

        /*

        void store(OutputStream out,String comments)

        void store(Write write,String comments)

        参数:

            out:字节输出流,不能写中文

            write:字符输出流可以写中文

            comments:注释,用来说明保存的文件是做什么用的,默认用Unicode编码不能用中文,一般用空字符串

        使用步骤:

            1、创建Properties对象,添加数据

            2、创建字节/字符输出流对象,构造方法中绑定目的文件

            3、使用Properties中的store,把集合中的临时数据,写入到硬盘中存储

            4、释放资源

        */

        try(FileWriter fw=new FileWriter("src\\io\\properties_demo\\test.txt")){

            prop.store(fw,"");

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

 

 

@Test

    public void test1() throws IOException {

        //load方法

        /*

        void load(InputStream inStream)

        void load(Reader reader)

        参数:

            InputStream inStream:字节输入流,不能读取含有中文的键值对

            Reader reader:字符输入流,能读取含有中文的键值对

        使用步骤:

            1、创建Properties集合对象

            2、使用Properties集合对象中的方法load读取保存键值对的文件

            3、遍历Properties集合

        注意:

            1、存储键值对的文件中,键与值默认的连接符号可以使用=或空格(其他符号)

            2、存储键值对的文件中,可以使用#进行注释,被注释的键值对不会被读取

            3、键与值默认都是字符串,不用再加引号

        */

        Properties properties=new Properties();

        properties.load(new FileReader("D:\\program testing\\javatest\\JavaHHHLevel\\src\\io\\properties_demo\\test.properties"));

        Set<String> set = properties.stringPropertyNames();

        for (String s : set) {

            System.out.println(s+"="+properties.getProperty(s));

        }

 

    }

字节缓冲流

BufferedOutputStream字节缓冲输出流 extends OutputStream

构造方法:

BufferedOutputStream(OutputStream out)创建一个新的缓冲输出流,以将数据写入指定的底层输出流。

BufferedOutputStream(OutputStream out,int size)创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入底层输出流

参数:

out:字节输出流,可以传入FileOutputStream

size:指定缓冲流内部缓冲区的大小,不指定默认

步骤:

1、创建FileOutputStream对象

2、创建BufferedOutputStream对象,构造方法中传递fos对象

3、使用BufferedOutputStream中的方法write,写入内部缓冲区

4、使用BufferedOutputStream中的方法flush,把内部缓冲区中的数据,刷新到文件中

5、释放资源(会自动调用flush)

*/

public class Demo1 {

    @Test

    public void test1() throws IOException {

        FileOutputStream fos=new FileOutputStream("D:\\program testing\\javatest\\JavaHHHLevel\\src\\io\\bufferede\\test.txt");

        BufferedOutputStream bos=new BufferedOutputStream(fos);

        bos.write("我将数据写入内部缓冲区中".getBytes());

        bos.flush();

        bos.close();

    }

}

 

 /*

    字节缓冲输入流BufferedInputStream extends InputStream

    构造方法除了名字是BufferedInputStream,其他跟输出流一样

    步骤:

    1、创建FileInputStream对象

    2、创建BufferedInputStream对象,构造方法中放入fis

    3、使用bis的read方法

    4、释放资源

    */

    @Test

    public void test2() throws IOException {

        FileInputStream fis=new FileInputStream("D:\\program testing\\javatest\\JavaHHHLevel\\src\\io\\bufferede\\test.txt");

        BufferedInputStream bis=new BufferedInputStream(fis);

        int len=0;

     /*   while ((len=bis.read())!=-1){

            System.out.println(len);

        }*/

        //read(byte[] b)从输入流中读取一定数量的字节并存储在缓冲区b

        byte[] bytes=new byte[3];

        while ((len=bis.read(bytes))!=-1){

            System.out.print(new String(bytes,0,len));

        }

        bis.close();

    }

到现在为止,最快的就是缓冲流+缓冲数组一起用

字符缓冲流

   /*

    BufferedWrite:字符缓冲输出流 extends Write

    构造方法:

    BufferedWrite(Write out)创建一个使用默认缓冲区的缓冲字符输出流

    BufferedWrite(Write out,int sz)创建一个使用指定缓冲区的缓冲字符输出流

    参数:同字节缓冲流,可以传FileWrite

 

    特有的成员方法:newline():写入一个行分隔符,会根据不同的系统,获取不同的行分隔符

 

    使用步骤和缓冲字节流一样

    */

    @Test

    public void test1() throws IOException {

        BufferedWriter bw=new BufferedWriter(new FileWriter("D:\\program testing\\javatest\\JavaHHHLevel\\src\\io\\bufferede\\test.txt"));

            bw.write("写一个啥呢?,我换个行吧");

            bw.write("\r\n");

            bw.write("我还想换个行");

            bw.newLine();//换行方法

            bw.write("换行成功了");

            bw.flush();

            bw.close();

        System.out.println();

    }

其中println也调用了newLine

/*

字符缓冲输入流:BufferedReader extends Reader

构造方法:BufferedReader(Reader in,int sz)

同样是一个默认缓冲区,一个指定缓冲区

可以传递FileReader

特有的成员方法

String readLine()读取一个文本行。就是读一行数据

有下列字符之一就认为是换行,\n,\r,\r\n

返回:

    包含该行内容的字符串,不包含任何终止符,如果已达末尾,则返回null

使用步骤都差不多

*/

public class Demo3 {

    @Test

    public void  test1() throws IOException {

        BufferedReader br=new BufferedReader(new FileReader("D:\\program testing\\javatest\\JavaHHHLevel\\src\\io\\bufferede\\test.txt"));

        System.out.println(br.readLine());

        String line;

        /*System.out.println((char)br.read());*/

        while ((line=br.readLine())!=null)

        {

            System.out.println(line);

        }

        br.close();

    }

}

 

转换流

/*转换流

字符编码:

    编码:字符-->字节

    解码:字节-->字符

字符集:一套自然语言与二进制数之间的对应规则

常用字符集:

ASCII:主要用于显示英语,基本ASCII 7bis表示一个字节,共128字符

扩展字符集8位表示一个字符共256字符,方便支持欧洲常用字符

ISO-8859-1:用于显示欧洲的语言,使用单字节编码,兼容ASCII

GBxxx字符集:GB表示国标,为显示中午而设计的一套字符集

GB2312:简称中文码表,小于127的字符意义与原来相同,但两个大于127的字符连在一起就表示一个汉字

可以表示7000多个汉字,此外各种符号包括全角字符也包含在内

GBK:最常用的中文码表,在GB2312上扩展而来,使用双字节编码,收录21003个汉字,兼容BG2312,支持繁体及日韩汉字等

GB18030:最新的中文字表,收录70244个汉字,采用多字节编码由1个、2个、或4、个字节组成,支持少数民族文字

Unicode字符集:为表达任意语言的任意字符而设计,是业界的一种标准,也就是统一码,标准万国码。

最多使用4个字节来表达每个字母、符号、或者文字。

有三种编码方式:UTF-8,UTF-16,UTF-32,-8最常用

互联网IETF小组要求所有互联网协议都要支持UTF-8所以,开发Web应用也要使用UTF-8,它使用一至四个字节为每个字符编码

规则:

    1、1-128个US-ASCII只需要一个字节编码

    2、拉丁文,二个字节

    3、大部分常用字(含中文),使用三个字节编码

    4、其他极少使用的Unicode辅助字符,使用四字节编码

编码引出的问题:

FileReader可以读取idea默认格式UTF-8的文件,但是读取系统默认编码GBK时会乱码

 

*/

 

 

utf-8读取GBK产生乱码的演示:

   FileReader fr=new FileReader("src\\io\\gbk编码文件.txt");

        int len;

        while ((len=fr.read())!=-1){

            System.out.print((char)len);

        }

        fr.close();

 

转换流的原理及使用

 

FileReader实际上是将FileInputStream转换成能看懂的字符,但是构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要指定这些值,可以现在FileInputStream上构造一个InputStreamReader

 

 

InputStreamReader类 extendsReader:是字节通向字符流的桥梁,它使用指定的charset读取字节并将其解码为字符

 

 

OutputStreamWriter类 extends Writer:是字符流通向字节流的桥梁:可以使用指定的charset将要写入流中的字符编码成字节

 

 

 

/*

OutputStreamWriter

构造方法:

OutputStreamWriter(OutputStream out)创建使用默认字符编码的OutputStreamWriter

OutputStreamWriter(OutputStream out,String charsetName)创建使用指定字符集的OutputStreamWriter

参数:

    out:字节输出流,可以用来写转换之后的字节到文件中

    charsetName:指定的编码表名称,不区分大小写

使用步骤:

1、创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码名称

2、使用write方法写到缓冲区

3、使用flush刷新到文件中

4、释放资源

*/

public class Demo9 {

    public static void main(String[] args) throws IOException {

        utf_8("你好,我是使用utf-8写的txt文件");

        gbk("你好,我是使用gbk写的txt文件");

    }

    private static void utf_8(String write) throws IOException {

        OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("src\\io\\utf_8编码文件.txt"),"utf-8");

        osw.write(write);

        osw.flush();

        osw.close();

    }

    private static void gbk(String write) throws IOException {

        OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("src\\io\\gbk编码文件.txt"),"gbk");

        osw.write(write);

        osw.flush();

        osw.close();

    }

}

 

 

 

 

 

 

/*

InputStreamReader

构造方法:

InputStreamReader(InputStream in)

InputStreamReader(InputStream in,charsetName)

使用步骤:

1、创建对象,传入字节输入流和指定的编码表名称

2、使用read方法读取文件

3、释放资源

注意:构造方法中指定的编码表名称要和文件的编码相同,否则会乱码

*/

public class Demo10 {

    public static void main(String[] args) throws IOException {

        utf_8();

        System.out.println();

        gbk();

    }

    private static void utf_8() throws IOException {

        InputStreamReader isr=new InputStreamReader(new FileInputStream("src\\io\\utf_8编码文件.txt"),"utf-8");

        int len=0;

        while ((len=isr.read())!=-1){

            System.out.print((char)len);

        }

        isr.close();

    }

    private static void gbk() throws IOException {

        InputStreamReader isr=new InputStreamReader(new FileInputStream("src\\io\\gbk编码文件.txt"),"gbk");

        int len=0;

        while ((len=isr.read())!=-1){

            System.out.print((char)len);

        }

        isr.close();

    }

}

 

序列化

序列化:把对象以流的方式写到文件中保存,叫写对象,也叫对象的序列化

反序列化:把文件中保存的对象,以流的方式读取出来,叫做读对象

 

 

 

 

 

序列化流:

/*

java.io.ObjectOutputStream extends OutputStream

也叫:对象的序列化流

构造方法:

ObjectOutputStream(OutputStream out)创建写入指定OutputStream的ObjectOutputStream

参数:

    out:字节输出流

特有的成员方法

    void writeObject(Object obj) 将指定的对象写入objectStream

使用步骤:

    1、创建对象,构造方法中传入OutputStream

    2、使用writeObject把对象写入到文件中

注意:类只有实现了Serializable接口才能被序列化,否则会抛出NotSerializableException异常

Serializable接口也叫标记型接口

当我们进行序列化和反序列化时,就会检测类上是否有这个标记

    有:就可以进行序列化和反序列化

    没有:就会出现NotSerializableException异常

*/

public class Demo1 {

    public static void main(String[] args) throws IOException {

        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("src\\io\\序列化流\\person.txt"));

        oos.writeObject(new Person("无名者",18));

        oos.close();

    }

/*

反序列化:

ObjectInputStream extends InputStream

作用:把文件中保存的对象,以流的方式读取出来使用

构造方法:

ObjectInputStream(InputStream in)

特有的成员方法:

readObject()

会抛出ClassNotFoundException

当找不到class文件时会抛出此异常

反序列化的前提:

    1、类必须实现Serializable

    2、必须存在类对应的class文件

使用步骤:

    1、创建对象,传入参数

    2、readObject方法

    3、释放资源

    4、使用读取出来的对象

*/

    @Test

    public void test1() throws IOException, ClassNotFoundException {

        ObjectInputStream ois=new ObjectInputStream(new FileInputStream("src\\io\\序列化流\\person.txt"));

        Object o = ois.readObject();

        System.out.println(o);

        ois.close();

    }

}

 

 

 

 

 

反序列化的产生的一些问题

InvalidClassException异常

当序列化一个对象后,更改了此对象,在反序列化的时候就会报这个异常

原因:每次修改类的定义就会给class文件生成一个新的序列号(serialVersionUID),当序列化一个对象的时候会把这个序列号添加进去,反序列化的时候就会比对txt文件和.class文件的序列号,当序列号不一致的时候就会报InvalidClassException

 

解决方案

无论是否对类的定义进行修改,都不生成新的序列号

格式在Serializable接口规定:

可序列化类可以通过声明名为“SerialVersionUID”的字段(该字段必须是静态的、最终的long型字段)显式声明自己的SerialVersionUID:

 

 

演示:

transient

static关键字修饰的变量优先于对象加载入内存,不能被序列化

例如age属性被static修饰后,序列化该对象,在反序列化后age输出得0

瞬态关键字:同样被transient修饰的变量不能被序列化,但是被其修饰的变量不会具有跟static一样的特性,用起来跟普通变量一样,只是不能被序列化,是一个序列化标记

打印流

 

sout就是一个打印流,java.io.PrintStream类 extends FilterOutputStream

PrintStream为其他输出流添加了功能,使他们能够方便地打印各种数据值表示形式

特点:

1、只负责数据的输出,不负责读取

2、与其他输出流不同,PrintStream永远不会抛出IOException

3、有特有的方法,print、println

void print(任意类型的值)

void println(任意类型的值并换行)

构造方法:

PrintStream(File file):输出的目的地是一个文件

PrintStream(OutputStream out):输出的目的地是一个字节输出流

PrintStream(String fileName):输出的目的地是一个文件路径

还有继承自OutputStream的方法等

注意:如果使用继承子父类的write方法写数据,那么查看数据的时候会查询编码表

如果使用自己的特有方法print/println方法写数据,写的数据原样输出

 

使用演示:

public class PrintStreamTest {

    public static void main(String[] args) throws FileNotFoundException {

        PrintStream ps=new PrintStream("src\\io\\print.txt");

        ps.write(97);

        ps.println(97);

        ps.println(true);

        ps.println("PrintStream流");

        ps.close();

    }

打印结果:

    /*

    可以改变输出语句的目的地(打印流的流向)

    输出语句,默认在控制台输出

    使用System.setOut方法改变输出语句的目改为的参数传递的打印流的目的地

    static void setOut(PrintStream out)

*/

    @Test

    public void test() throws FileNotFoundException {

        System.out.println("我是在控制台输出");

        PrintStream ps=new PrintStream("src\\io\\打印流目的.txt");

        System.setOut(ps);//把输出语句的目的地改变为打印流的目的地

        System.out.println("我在打印流的目的地中输出");

        ps.close();

    }

}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值