Java基础总结---IO流

来源:互联网 发布:金钻淘宝店有哪些 编辑:程序博客网 时间:2024/06/05 11:58

二. IO流

一. 自己的理解

1.IO流的分类(比较熟悉的)

1. 字节流和字符流--最开始是字节流,也就是二进制流.但是为了便于人的读写,使用字符流将其转化为可读的Unicode编码 字节流--(抽象父类)InputStream,OutputStream. (具体子类) : 对象IO流-- ObjectInputStream,ObjectOutputStream.             文件IO流--FileInputStream,FileOutputStream. // 太久没用都忘了 字符流--Reader,Writer.(抽象类) (具体子类):文件IO流--FileReader,FileWriter2. 处理流--对上面流进行包装包装流--BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter. 转换流--InputStreamReader,OutputStreamWriter.

二. 不熟悉的地方

1.字节流的使用

1. 字节输出流的使用
class OStream {        // 这里直接抛出IOException,抛出异常,为了版面整洁,下面也一样    public static void main(String[] args) throws IOException{        // 创建一个新文件        File file = new File("/home/z/IOStream.txt");        // OutputStream是一个抽象类,不能创建具体实例.        // 创建字节输出流对象OutputStream        OutputStream os = new FileOutputStream(file);        // 创建一个字节数组,字节数组会转换成什么.        byte[] b = new byte[]{49,65,97};        // 开始写入        os.write(b);        // 关闭资源        os.close();    }}
2. 字节输入流的使用
class IStream{    public static void main(String[] args) throws IOException{        // 获取文件位置        File file = new File("/home/z/IOStream.txt");        // 创建对象        InputStream is = new FileInputStream(file);        // 创建一个 字节数组用来读取文件内容,如果文件很大,byte数组可以设置很大.        byte[] b = new byte[8];        int i; // 这里用i去接收读取的返回值,但是直接判断is.read(b)!=-1也可以.        // 读文件的时候如果到达最后没有内容,read()方法会返回-1,所以用这个来作为条件        while(( i = is.read(b)) != -1){            // 输出到控制台,也可以运用上输出流将其写入文件            // 因为i是int型,所以输出来是一个Unicode整数.要用char来强转            System.out.print((char)i+" ");        }        // 关闭资源        is.close();    }   }

输出结果:1 A a

2.字符流的使用

1. 字符输出流的使用
class CharWriter{    public static void main(String[] args) throws IOException{        // 创建文件对象        File file = new File("/home/z/writer.txt");        // 创建字符输出流Writer对象,这里Writer也是一个抽象类,只能new具体子类实例        Writer writer = new FileWriter(file);        // 之前的字节流只能将ASCII的字符写出,不能写出中文.        //本来想尝试是否能写出字符串形式的中文,结果发现OutputStream的write()方法参数只能传输字节数组,一个int值        OutputStream os = new FileOutputStream(file);        // 这里int值超过byte的范围0~127,在char的范围类.在String的        os.write(34443);        // 在文件中查看会是一个\8B 或者是一个乱码.所以字节流是不能写出中文的        os.close();        // 使用Writer向文件中写出字符串形式的中文        writer.write("你好");        // 关闭资源        writer.close();    }}

writer.txt中的内容是:你好

2. 字符输入流的使用
class CharReader{    public static void main(String[] args) throws IOException{        //创建文件对象        File file = new File("/home/z/writer.txt");        // 创建字符输入流Reader对象,Reader也是一个抽象类        Reader reader = new FileReader(file);        // 从文件中读取内容,读取的内容都是整数,都是需要强转成char类型,才能变成字符.        int i;        while((i = reader.read()) != -1){            System.out.println((char)i);        }        // 关闭资源        reader.close();    }}

输出结果是:

3.对象字节流的使用

1. 对象输出流
/** * 创建一个类,如果要实现写出对象,则类需要实现Serializable借口 */class Animal implements Serializable{    private int age;    private String name;    public Animal(int age, String name){        this.age = age;        this.name = name;    }    public int getAge(){        return age;    }    // 重写toString()方法.    @Override    public String toString() {        return "Animal [age=" + age + ", name=" + name + "]";    }}class ObOStream{    public static void main(String[] args) throws IOException{        // 创建一个对象        Animal animal = new Animal(10,"cat");        // 创建一个对象输出流ObjectOutputStream        // 无参构造器是protected,一般是不能访问的.所以需要用到下面的构造器        // public ObjectOutputStream(OutputStream out)         FileOutputStream fos = new FileOutputStream(new File("/home/z/object.txt"));        ObjectOutputStream oos = new ObjectOutputStream(fos);        // 这么写出到文件中会出现乱码,刚开始想可能是缓存的问题,但这里是没有用到缓冲区的.        // 这里是一个经常犯错的地方.        oos.writeObject(animal);        oos.close();    }}

百度之后,才发现写出对象的时候用的是字节流,之前说过,字节流是二进制的,所以我们写出数据的时候是用二进制写出的.当我们去用文本编辑器打开时,是不能将二进制类型转换成Unicode类型的.只有当用字符流写出时文本编辑器才会分辨出Unicode编码.

所以在进行纯文本的输入输出的时候,一般是使用字符流,其余的例如音频,视频,图片等都使用字节流

2. 对象输出流下面用输入流读取.虽然写出的是二进制,不能识别.但是用输入流读取的时候也是二进制流,所以读出的时候就是写入的时候的样子.
class ObIStream{    public static void main(String[] args) throws IOException,ClassNotFoundException{        // 创建文件输入流        FileInputStream fis = new FileInputStream(new File("/home/z/object.txt"));        // 创建对象输入流,并将fis作为参数传入        ObjectInputStream ois = new ObjectInputStream(fis);        // 从文件中读取数据.转换为Animal对象对象,        // 读取多个对象的话怎么去判断结束条件.        Animal animal = (Animal)ois.readObject();        ois.close();        // 直接调用重写的toString()方法.显示在控制台        System.out.println(animal.toString());    }}

输出结果:
Animal [age=10, name=cat]

3. 多个对象的输出流.
class ManyObOStream{    public static void main(String[] args) throws IOException{        // 两种思路是一样的,因为这个对象都能存储多个对象,且只持有一个引用.        // 1.用一个对象数组将同一个类型的数组存储起来,写入到文件中        // 2.用一个list将对象加入到集合中,下面使用list        ArrayList<Animal> list = new ArrayList<>();        // 产生多个不同的对象,使用for循环来产生下标        for(int i = 0; i < 10; i++){            int age = i;            String name = "cat"+i;            // 创建不同的Animal对象            Animal a = new Animal(age, name);            // 添加到list中            list.add(a);        }        // 创建对象输出流对象        FileOutputStream fos = new FileOutputStream(new File("/home/z/manyObject.txt"));        ObjectOutputStream oos = new ObjectOutputStream(fos);        // 将list写出到文件中        oos.writeObject(list);        oos.close();    }}
4. 多个对象输入流,将其显示到控制台
class ManyObIStream{    public static void main(String[] args) throws IOException,ClassNotFoundException{        // 这里输入流与之前的没有什么区别,只是将之前的读出的对象改为ArrayList类型        FileInputStream fis = new FileInputStream(new File("/home/z/manyObject.txt"));        ObjectInputStream ois = new ObjectInputStream(fis);        ArrayList<Animal> list = (ArrayList<Animal>) ois.readObject();        ois.close();        // 将list里面数据输出        for(int i = 0; i < list.size(); i++){            System.out.println(list.get(i).toString());        }    }}

输出结果:
Animal [age=0, name=cat0]
Animal [age=1, name=cat1]
Animal [age=2, name=cat2]
Animal [age=3, name=cat3]
Animal [age=4, name=cat4]
Animal [age=5, name=cat5]
Animal [age=6, name=cat6]
Animal [age=7, name=cat7]
Animal [age=8, name=cat8]
Animal [age=9, name=cat9]

当需要将多个对象输出到文件中时,可以将多个对象封装到一个数组或者集合中,这样写出一个数组或者集合时,将多个对象一起写出到文件中.
有个问题:ArrayList是一个引用指向它,用下标去维护.写出到文件的时候,根据输出的结果可以看出, Java 将当前引用的所有引用指向的对象都写出到了文件中.所以这里也可以实现Java中的深克隆.即内容相同,引用却不同,也就是产生了一个新的对象. 浅克隆是指只复制了引用,实际的对象是没有变的.

// TODO

为什么要定义一个int i ;(i= is.read()) != -1, 可以直接用 is.read() != -1 来判断的.

4. 处理流的使用
比较熟悉的主要是缓冲流:
字节流:BufferedInputStream,BufferedOutputStream.
字符流:BufferedReader,BufferedWriter.

class BufferedChar{    public static void main(String[] args) throws IOException{        public static void main(String[] args) throws IOException {            // 重复写入一个txt文件,使用字符流,计算时间,看缓冲流和不用缓冲流的时间差            int c1 = 0; // 用来计算不用缓冲读取的次数            int c2 = 0; // 用来计算用缓冲读取的次数            // 创建字符输出流对象            FileWriter fw = new FileWriter(new File("/home/z/buffer.txt"));            FileReader fr = new FileReader(new File("/home/z/buffer.txt"));            // 获取系统的当前时间            long start1 = System.currentTimeMillis();            // 使用for循环来不停的写入            for(int i = 0; i < 100000; i++){                fw.write("你好,我是一个字符");            }            while((fr.read()) != -1) {                c1++;                fr.read();            }            long end1 = System.currentTimeMillis();            BufferedWriter bw = new BufferedWriter(new FileWriter(new File("/home/z/buffer2.txt")));            BufferedReader br = new BufferedReader(new FileReader(new File("/home/z/buffer2.txt")));            char[] c = new char[1024];            long start2 = System.currentTimeMillis();            for(int i = 0; i < 100000; i++) {                bw.write("你好,我是一个字符");            }            while(br.read() != -1) {                c2++;                br.read(c);// 但是这里不能输出实际读取的字符            }            long end2 = System.currentTimeMillis();            System.out.println("不用缓冲的读写总时间="+(end1-start1)+"c1="+c1);            System.out.println("使用缓冲区的读写时间="+(end2-start2)+"c2="+c2);        }    }}

输出结果:
不用缓冲的读写总时间=95 c1=449666
使用缓冲区的读写时间=46 c2=869

最开始在读取的时候将读取的内容在控制台输出,如果次数过多,会造成时间差很大.所以去掉输出语句后,发现差距并不大,但是从c1 和 c2可以看出来,次数明显的减少.不过使用缓冲区的时候不能将读取的内容显示出来,只有一个readLine()方法,能够将读取的内容显示,不过readLine()是一个无参构造参数,只能根据一行来读取.

主要是在进行IO读取的时候如果数据比较大,那么对IO流的访问会很频繁,而IO流的访问时间一般会很长,所以为了降低对IO流的访问,所以将数据先存储在缓冲流里面,等读取的数据满了之后一次性写出.

5.转换流的使用

InputStreamReader:将字节流转换为字符流(An InputStreamReader is a bridge from byte streams to character streams)
OutputStreamWriter:将字符流转换为字节流(An OutputStreamWriter is a bridge from character streams to byte streams)

这里为什么会有区别?个人理解是:一般读取数据的时候用的比较多的是输入流,即InputStream,比如从网络获取的数据都是字节流.但是读取来的数据需要进行解析,就是将字节流转换为字符流,这样人们就能获取到里面的字符型数据. 而输出流的时候是人们写入字符型的数据,写出的时候将其转换为字节流,相当于二进制流,传输比较方便.所以输出流的时候需要字符转字节.

6.流的混合使用

在别的博客上看到了一个总结:

1. 用InputStream去获取输入流2. 用InputStreamReader将字节流转换为字符流3. 用BufferedReader开始一次性读取多个字符.

7.一些见过的流
1. DataInputStream,DataOutputStream: 不知道和其他流的区别在哪.
2. PrintStream: 标准输出流,System.out就是一个PrintStream. 不仅可以将内容输出到控制台,也可以将内容输出到文件中.

原创粉丝点击