IO流及序列化

字符输入流

当使用字节流读取汉字时,会一个字节一个字节读取,读取到的数据为int类型。如果读取的文本文件有汉字,则有可能会出现问题,因为不同的编码格式,每个汉字占用的字节数是不同的,所以如果要把读取到的数据转换为汉字时,可能会报错。如果读取后直接使用字节流写入到一个文件里,则不会出现问题。

public class ReadDemo {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("a.txt");
       //读取a.txt中的内容,直接写入到b.txt中
        byte[] bytes = new byte[1024];
        int length;
        FileOutputStream fos=new FileOutputStream("b.txt");
        while ((length = fis.read(bytes))!=-1){
            fos.write(bytes,0,length);
        }
    }
}

字符输入流则不会出现以上问题。如果读完数据要查看,则使用字符流,如果单纯的拷贝 推荐使用字节流,如果使用字符流copy非文本文件可能会出现问题

 FileReader reader = new FileReader("a.txt");
        int len ;
        char [] chars = new char[1024];
        while ((len=reader.read(chars))!=-1){
            System.out.println(new String(chars, 0, len));//注意如果使用println则会每隔1024字符换行
        }

字符输出流

可以使用writer() 方法写入文件一段内容。

可以写入单个字符,或者字符串,或者char类型的数组,还可以指定写入长度。

调用writer()方法以后,内容不会立刻写入到文件,此时需要调用flush()或者close()方法刷新文件。

package com.atguigu.io;

import java.io.FileWriter;
import java.io.IOException;

public class WriterDemo {
    public static void main(String[] args) throws IOException {
        FileWriter writer = new FileWriter("b.txt");
        writer.write(20320);//在b.txt中写入“你”这个汉字。
        writer.write("好好学习,天天向上");//也可以直接写入字符串
        writer.flush();//调用flush方法刷新文件
    }
}

用writer 指定长度copy文件内容

package com.atguigu.io;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class WriterDemo {
    public static void main(String[] args) throws IOException {
        FileReader fr= new FileReader("a.txt");
        FileWriter writer = new FileWriter("b.txt");
        char [] chars = new char[1024];
        int length;
        while ((length=fr.read(chars))!=-1){
            writer.write(chars,0,length);
        }
    }
}

缓冲流

缓冲流也被称为高效流,能够提高IO操作的效率,缓冲流其实是对普通IO流的封装

字节缓冲流:BufferedInputStream,BufferOutputStream、

字符缓冲流:BufferedReader,BufferedWriter

字节缓冲流,测试使用缓冲流和普通字节流的拷贝速度

package com.atguigu.bufferedio;

import java.io.*;

public class BufferedDemo1 {
    public static void main(String[] args) throws IOException {
        //两个普通的字节流
        FileInputStream fis = new FileInputStream("1.exe");
        FileOutputStream fos = new FileOutputStream("2.exe");
        //缓冲流是对普通流的包装
        BufferedInputStream bis = new BufferedInputStream(fis);
        BufferedOutputStream bot = new BufferedOutputStream(fos);

        long start = System.currentTimeMillis();//返回以毫秒为单位的当前时间
       // test1(fis, fos);//23160
       // test2(fis,fos);//9
       test3(bis,bot);//170
        long end = System.currentTimeMillis();
        System.out.println(end-start);
        //关闭IO流(先开的后关闭,后开的先关闭)
        bot.close();
        bis.close();
        fos.close();
        fis.close();

    }
    //测试使用普通字节流一次读取一个字节的拷贝速度
    public static void test1(FileInputStream fis, FileOutputStream fos) throws IOException {
        int content;
        while ((content = fis.read()) != -1) {
            fos.write(content);
        }
    }
    //测试使用普通字节流一次读取1M的速度
    public static void test2(FileInputStream fis, FileOutputStream fos) throws IOException {
        int length;
        byte[] content = new byte[1024*1024];
        while ((length = fis.read(content)) != -1) {
            fos.write(content,0,length);
        }
    }
    //测试使用缓冲流拷贝速度
    public static void test3(BufferedInputStream bis, BufferedOutputStream bos) throws IOException {
        int content;
        while ((content = bis.read()) != -1) {
            bos.write(content);
        }
    }
}

可以发现使用缓冲流也不一定会提高拷贝速度,程序优化有个最优方式,IO流使用之后都要关闭(先开的后关闭,后开的先关闭)。

字符缓冲流的基本方法与普通字符流调用方式一致,不再阐述,我们来看它们具备的特有方法。

  • BufferedReader:public String readLine(): 读一行文字。
  • BufferedWriter:public void newLine(): 写一行行分隔符,由系统属性定义符号。

转换流

将字节流和字符流相互转换

InputStreamReader / OutputStreamWriter

在创建FileReader对象读取一个文件的时候,是无法指定文件的编码方式的,有可能出现写入时的编码方式和读取时的编码方式不一致的情况,导致乱码

package com.atguigu.convertio;

import java.io.*;

public class convertDemo {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("b.txt");
        FileOutputStream fos = new FileOutputStream("a.txt");
        //指定以字节流的形式打开GBK编码的文本文件
        InputStreamReader isr = new InputStreamReader(fis,"utf8");
        OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");
        char[] chars = new char[10];
        int length;
        while ((length=isr.read(chars))!=-1){
            osw.write(chars,0,length);
        }
        osw.close();
        isr.close();
        fos.close();
        fis.close();
    }
}

序列化和反序列化

如何把Java对象写入到文件里?字节流 字符流

序列化:将Java对象转换为字节或者字符,用来保存或者传输的过程。

ObjectOutputStream 将对象转换成为二进制并写入到文件。

Java对象转换为字节,对象所有的信息都会保留,可以用来保留对象。

Java对象转换为字符串,信息会丢失,用来保留对象的属性以及跨平台传输数据。

被transient 关键字修饰的变量,在对象变成二进制的时候不会被写入。

反序列化:将字节或者字符串加载成为Java对象来使用的过程。

ObjectInputStream 将二进制的文件加载成Java对象。

使用 ObjectInputStream 和 ObjectOutputStream 实现 Java对象 和 字节之间相互转换.
不是所有的对象都能直接变成二进制被写入到文件里。对象需要实现 Serializable 接口
Serializable 接口没有抽象方法,只是对类进行一个标记,表示这个类可以被序列化!

序列化和反序列化的注意事项:
1.将对象写入到二进制文件以后,如果直接使用 ObjectInputStream 加载是可以加载成功的
2. 生成二进制文件以后,手动修改了这个文件,会报错!
3. 生成二进制文件以后,修改了代码,添加或者删除了一个属性,再重新加载文件。

InvalidClassException出现的三种情况:
前提是生成 二进制文件以后,如果做一下几种操作,会触发异常

  1. 修改了 java文件,添加了不以 transient 修饰的变量,或者删除了任意的变量。
    但是如果是修改变量的值,而没有新增变量,不会报错。
  2. java类里的 SerialVersionUID 版本和 文件里读取的版本不一致。
  3. 如果一个类它的父类没有可以访问的无参构造方法,也会报错。

如果子类实现了 Serializable 接口,子类序列化时,父类里定义的属性不会被写入;

如果父类实现了 Serializable 接口,子类序列化时,父类里定义的属性会被写入。

Properties 类

HashTable 是线程安全的效率低,HashMap线程不安全效率高
HashTable不允许放置null,HashMapkeyifangnull值键值对。

java.util.Properties 继承于Hashtable ,来表示一个持久的属性集。它使用键值结构存储数据,每个键及其对应值都是一个字符串。该类也被许多Java类使用,比如获取系统属性时,System.getProperties 方法就是返回一个Properties对象。

Properties 可以像Map一样存入键值对,但是通常不手动调用put给键值对赋值。

Properties 通常用来读取一个 配置文件,后缀名通常是 .properties

通常是以键值对的形式保存数据,键和值之间可以使用 = 或者 : 连接

FileReader reader = new FileReader("config.properties");
        prop.load(reader);//按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。

getProperty(String key, String defaultValue) 用指定的键在属性列表中搜索属性。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值