Java IO流大家族(总结)

目录

1.IO流的分类

1.1  通过流分类:输入流,输出流

1.2  通过数据单位不同分分类:字符流,字节流

1.3  抽象类

1.4  各抽象类的选用

2.文件流的使用

2.1  字节输出流:FileOutputStream

2.2 字节输入流:FileInputStream

2.3 缓冲区类(高效类):BufferedOutputStream,BufferedInputStream

3.转换流的使用

3.1 字节流转化为字符流:OutputStreamWriter,InputStreamReader

3.2 OutputStreamWriter,InputStreamReader的封装类(简化写法):FileWriter,FileReader

3.3 缓冲区类(高效类):BufferedWriter,BufferedReader

4.数据输入输出流 

5.内存操作流

6.打印流

7.标准输入输出流

8.随机访问流

9.合并流

10.序列化流反序列化流

11.Properties


1.IO流的分类

1.1  通过流分类:输入流,输出流

输入流:从接收器输入到java程序。

输出流:输出流接受输出字节并将这些字节发送到某个接收器,也就是从java程序输出到接收器。

1.2  通过数据单位不同分分类:字符流,字节流

在java版本中是先有字节流,再有字符流,1字符 = 2字节

字节流:每次传输一个字节,一个中文汉字是两个字节,会出现乱码。

字符流:每次传输两个字节,一般传输中文

1.3  抽象类

字节输出流:OutputStream

字节输入流:InputStream

字符输出流:Writer

字符输入流:Reader

1.4  各抽象类的选用

选用输入,输出流通过需求选用

选用字符,还是字节,一般用记事本打开是看得懂的用字符,看不懂的用字符。字节流更加适用于音频文件、图片、歌曲。

2.文件流的使用

2.1  字节输出流:FileOutputStream

向文件中写入数据

public static void main(String[] args) throws IOException {
        //追加写入,append为true追加
        FileOutputStream fos = new FileOutputStream("E:\\b.txt",true);

        byte[] b = {'a','b','c','d'};
        fos.write(97);//底层是二进制数据,记事本会找到对应的字符值
        fos.write("\n".getBytes());//加入换行,一般windows写法是\r\n,linux是\n,mac是\r
        fos.write("hello,world".getBytes());
        fos.write("\n".getBytes());
        fos.write(b,1,2);
        fos.write("\n".getBytes());

        fos.close();
    }

程序分为三部分:

(1)创建字节输出流对象:这一步创建了文件,创建了fos对象,并把fos对象指向了此文件

(2)写入数据

(3)释放资源:释放了文件所占用的相关资源,变成垃圾,通知系统回收

异常处理方式:

异常有很多变形,这里用try...catch...catch...finally...(这里fos可能为空,如当找不到指定的盘符是,或者说是我只有一个C盘,得到fos为空)

public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("E:\\b.txt",true);
            fos.write("异常处理".getBytes());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(fos != null){//fos不为空才执行,因为finally是默认执行的
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

2.2 字节输入流:FileInputStream

读取文件:一次读取一个字节:int read()

public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("E:\\b.txt");
        int by = 0;
        //读取,赋值,判断
        while((by=fis.read())!=-1){
            System.out.print((char) by);
        }
        fis.close();
    }

读取文件如果没有相应文件不会为你创建文件,这里用的 int read().一次传输一个字节,返回的是数据字节,当返回值为-1,则表示传输结束,汉字是两个字节,会被拆分,返回值的第一个字节都是负数,第二个字节可能是正数,也是合并的判断依据

英文传输返回值:
[97, 98, 99, 100, 101, 102]    
对应:abcdef
中文传输返回值:
[-26, -79, -119, -27, -83, -105, -26, -117, -122, -27, -120, -122, -28, -68, -96, -24, -66, -109]         
对应:汉字拆分传输(UTF-8编码表示字符最多占三个字节)

一次读取多个字节:public int read(byte[ ] b)

 public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("e:\\b.txt");

        byte[] by = new byte[1024];
        int len = 0;
        while((len = fis.read(by))!=-1){
            //避免读出的数据不满足数组大小
            System.out.print(new String(by,0,len));
        }

        fis.close();
    }

public int read(byte[ ] b):把读取的数据存到数组b里,返回值是实际读取到的字节个数,如果缓冲区没有了就返回-1

注意:  这里by数组的长度一般是1024或者1024的整数倍
          相对于一个字节的读取快了1024倍或者1024的整数倍,传输视频等大文件时使用

传输图片练习代码

public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("D:\\图片.jpeg");
        FileOutputStream fos = new FileOutputStream("E:\\copy.jpeg");

        byte[] by = new byte[1024];
        int len = 0;
        while((len = fis.read(by)) != -1){
            fos.write(by,0,len);
        }
        fos.close();
        fis.close();
    }

2.3 缓冲区类(高效类):BufferedOutputStream,BufferedInputStream

缓冲区类类似于一个杯子,用来装水(水是指OutputStream,InputStream),运行效率高,代码体现:

//向文件写入数据
public static void main(String[] args) throws IOException {
        BufferedOutputStream bos = new BufferedOutputStream(new             
                                  FileOutputStream("e:\\b.txt"));

        bos.write("hello".getBytes());
        bos.close();
    }
//从文件读取数据 
public static void main(String[] args) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new 
                          FileInputStream("e:\\b.txt"));

        byte[] by = new byte[1024];
        int len = 0;
        while ((len = bis.read(by)) != -1){
            System.out.println(new String(by,0,len));
        }
        bis.close();
    }

3.转换流的使用

3.1 可将字节流转化为字符流:OutputStreamWriter,InputStreamReader

由于用的是字符,有很多字符集,写入和读取的字符集要一致,不一致会乱码。

//写入数据
public static void main(String[] args) throws IOException {
        //使用指定字符集,把字节流转换为字符流
        OutputStreamWriter osw = new OutputStreamWriter(new 
                        FileOutputStream("e:\\b.txt"),"UTF-8");
        osw.write("汉字");
        //刷新一下,但流未关闭,还能写入数据
        osw.flush();
        //先刷新,在关闭此流
        osw.close();
    }
//从文件读出数据 
public static void main(String[] args) throws IOException {
        InputStreamReader isr = new InputStreamReader(new 
                        FileInputStream("e:\\b.txt"),"UTF-8");

        int len = 0;
        char[] by = new char[1024];
        while((len = isr.read(by)) != -1){
            System.out.print(new String(by,0,len));
        }
        isr.close();
    }

 flush和close的区别:在写入字符时,字符是在缓冲区的,文件里并没有,此时flush一下后,就会进入文件。flush能写入数据,但并没有把流关闭,随后还能写入数据。而close是刷新写入数据后把流关闭,随后就不能写入数据了。

3.2 OutputStreamWriter,InputStreamReader的封装类:FileWriter,FileReader

利用封装的类复制文件,代码:

public static void main(String[] args) throws IOException{
        FileWriter osw = new FileWriter("e:\\b.txt");
        FileReader isr = new FileReader("e:\\a.txt");

        int len = 0;
        char[] chars = new char[1024];
        while ((len = isr.read(chars)) != -1){
            osw.write(chars,0,len);
            //osw.flush();
        }
        osw.close();
        isr.close();
    }

3.3 缓冲区类(高效类):BufferedWriter,BufferedReader

//写入
public static void main(String[] args) throws IOException {
        BufferedWriter bw = new BufferedWriter(new FileWriter("e:\\b.txt"));

        bw.write("hello");
        bw.close();
    }
//读出
public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("e:\\b.txt"));

        int len = 0;
        char[] c = new char[1024];
        while((len = br.read(c)) != -1){
            System.out.println(c);
        }
        br.close();
    }

这两个类有特殊的方法:

public void newLine():系统决定换行符
public String readLine():一次读取一行数据,没有数据时返回null

方法的使用:

//复制文件练习 
public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("e:\\a.txt"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("e:\\b.txt"));

        String str = null;
        while((str = br.readLine()) != null){
            bw.write(str);
            bw.newLine();
        }
        bw.close();
        br.close();
    }

BufferReader的子类:LineNumberReader

其特有功能:

特殊方法: int getLineNumber() :获取当前行号
          void setLineNumber(int lineNumber):设置当前行号

代码:

public static void main(String[] args) throws IOException {
        LineNumberReader lnr = new LineNumberReader(new FileReader("e:\\b.txt"));
        lnr.setLineNumber(11);//从第12行开始
        String str = null;
        while((str = lnr.readLine()) != null){
            int line = lnr.getLineNumber();
            System.out.println(line +":"+str);
        }
    }

 运行结果:

12:hello
13:world
14:java

4.数据输入输出流 

DataOutputStream:FilterOutputStream的子类

数据输入输出流可以读写任意类型数据

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

    }

    private static void read() throws IOException {
        DataInputStream dis = new DataInputStream(new FileInputStream("e:\\b.txt"));

        int i = dis.readInt();
        char c = dis.readChar();
        float f = dis.readFloat();
        double d = dis.readDouble();

        dis.close();
        System.out.println(i);
        System.out.println(c);
        System.out.println(f);
        System.out.println(d);
    }

    private static void write() throws IOException{
        DataOutputStream dos = new DataOutputStream(new FileOutputStream("e:\\b.txt"));

        dos.writeInt(12);
        dos.writeChar('a');
        dos.writeFloat(12.32f);
        dos.writeDouble(14.36);

        dos.close();
    }

5.内存操作流

不需要文件,用于处理临时存储信息,程序结束,数据就从内存中消失,这个有读有写,对应的读的操作类:

字节数组:java.io.InputStream 继承者 java.io.ByteArrayInputStream

字符数组:java.io.Reader  继承者 java.io.CharArrayReader

字符串:java.io.Reader 继承者 java.io.StringReader

字节数组(三种类似)的写入读出操作:

 public static void main(String[] args) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        baos.write("hello".getBytes());
        baos.write("java".getBytes());
        //这个close()不起任何作用,内部源码是个空的,主要是为迎合父类操作
        //baos.close();
        byte[] by = baos.toByteArray();
        ByteArrayInputStream bios = new ByteArrayInputStream(by);
        int len = 0;
        while((len = bios.read()) != -1){
            System.out.print((char) len);
        }
        //这个close()也是
        bios.close();
    }

6.打印流

打印流读字面意思就可以知道这个只有向文件写数据,没有读数据:

字节打印流:java.io.FilterOutputStream 继承者 java.io.PrintStream

字符打印流:java.io.Writer  继承者 java.io.PrintWriter

特点:

1.只有写数据,没有读数据,只能操作目的地,不能操作数据源

2.可以操作任意类型数据:print(),println()

3.如果启用了自动刷新,能够自动刷新

PrintWriter pw = new PrintWriter(new FileWriter("e:\\b.txt"),true);
启用自动刷新,但必须使用println()(包含了写入,换行,刷新)

4.该流可以直接操作文件

那些可直接操作文件的流:FileOutputStream,FileInputStream,FileWriter,FileReader,PrintStream,PrintWriter

代码示例:

 public static void main(String[] args) throws IOException {
        PrintWriter pw = new PrintWriter(new FileWriter("e:\\b.txt"),true);

//        pw.print("hello");
//        pw.print(100);
//        pw.print("java");
        pw.println("hello");
        pw.println(100);
        pw.println("java");
//        pw.close();// 代码中close()也会刷新,测试自动刷新,可以把close()注释
    }

7.标准输入输出流

public static final InputStream in
public static final PrintStream out

标准输出流:System.out 显示器
标准输入流:System.in  键盘

与我们常用的输入输出一样,在输出流中用打印流的方法都能使用 :public static final PrintStream out

 public static void main(String[] args) {
        PrintStream p = System.out;
        p.println(11);//与下面意思一样
        System.out.println(12);
    }

8.随机访问流

此类不是一个流,是Object的子类
融合了InputStream和OutputStream
支持对文件随机访问读取和写入

 public static void main(String[] args) throws IOException {
        RandomAccessFile raf = new RandomAccessFile("E:\\b.txt","rw");//第二个参数是操作文件的模式,读写两种写法一样

//        raf.writeInt(100);
//        raf.writeChar('a');
//        int i = raf.readInt();
//        System.out.println(i);
//        System.out.println("当前文件指针位置"+raf.getFilePointer());
        raf.seek(4);//设置指针位置
        char c = raf.readChar();
        System.out.println(c);
        System.out.println("当前文件指针位置"+raf.getFilePointer());
        raf.close();
    }

9.合并流

字面意思,一次同时读取多个文件。只有读操作

构造方法:SequenceInputStream(InputStream,InputStream):合并两个文件

                  SequenceInputStream(Enumeration e):合并多个文件

 把a.txt和b.txt的文件内容传到c.txt,两种方式:

    public static void main(String[] args) throws IOException {
        //合并两个文件
//        InputStream is1 = new FileInputStream("e:\\a.txt");
//        InputStream is2 = new FileInputStream("e:\\b.txt");
//        SequenceInputStream sis = new SequenceInputStream(is1,is2);
        //合并多个文件
        Vector vi = new Vector();
        InputStream is1 = new FileInputStream("e:\\a.txt");
        InputStream is2 = new FileInputStream("e:\\b.txt");
        vi.add(is1);
        vi.add(is2);
        //利用构造方法:SequenceInputStream(Enumeration e)
        Enumeration ei = vi.elements();//返回此向量的组件的枚举。
        SequenceInputStream sis = new SequenceInputStream(ei);
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("e:\\c.txt"));
        int len = 0;
        byte[] by = new byte[1024];
        while ((len = sis.read(by)) != -1){
            bos.write(by,0,len);
        }
        bos.close();
        sis.close();
    }

10.序列化流反序列化流

序列化流(对像操作流):写 ObjectOutputStream,对象--》流
                把对象按照流一样的方式存入文本文件或者在网络中传输
反序列化流:读 ObjectInputStream,流--》对象
                把文本文件中的流对象或者网络中的流对象数据还原为对象

 public static void main(String[] args) throws IOException, ClassNotFoundException {
        write();
        read();
    }

    private static void read() throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("e:\\c.txt"));

        Object o = ois.readObject();
        System.out.println(o);
        ois.close();
    }

    private static void write() throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("e:\\c.txt"));
        Student s = new Student("张三",100,120,148);

        oos.writeObject(s);
        oos.close();
    }

 

/**
 * Serializable:序列化
 * 如果某个变量不想被序列化,可加入关键字transient
 */
public class Student implements Serializable {
    //姓名
    public String name;
    //语文成绩
    public int chinese;
    //数学成绩
    public int math;
    //英语成绩
    public int english;
    ......
}

11.Properties

属性集合类,是一个可以和IO流相结合使用的集合类。可以保存在流中或者从流中加载。属性列表中每一个键所对应的值都是字符串。

java.util.Hashtable

               继承者 java.util.Properties

特有功能 

bject setProperty(String key, String value):调用 Hashtable 的方法 put。

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

Set stringPropertyNames() : 返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键。

 文件与此类的结合:

方法: void load(Reader reader) 按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。

            void store(Writer writer, String comments) 以适合使用 load(Reader) 方法的格式,将此 Properties 表中的属性列表(键和元素对)写入输出字符。

使用代码:

 public static void main(String[] args) throws IOException {
        myLoad();
        myStore();
    }

    private static void myStore() throws IOException{
        Properties p = new Properties();
        Writer w = new FileWriter("e:\\c.txt");

        p.setProperty("张飞","丈八蛇矛");
        p.setProperty("吕布","方天画戟");
        p.setProperty("刘备","双股剑");

        p.store(w,"hero");
        w.close();
    }

    private static void myLoad() throws IOException{
        Properties p = new Properties();
        Reader r = new FileReader("e:\\c.txt");

        p.load(r);
        System.out.println(p);
        r.close();
    }

 

你可能感兴趣的:(java)