-->

Java-IO流总结

2020-11-29 09:23发布

IO流:

 

IO流分为两大类:字节流和字符流

 

IO的作用就是为了读写操作的。

 

   每种流都分为输入流(Input)、输出流(Output);站在java程序的角度来说,java程序进行读取操作时,就是输入流;如果java程序向其他地方(硬盘,其他的设备)写入操作时,就是输出流。

 

IO流只能操作文件,不能操作文件夹,否则会报错。

 

字节流:

字节输入流:InputStream

字节输出流:OutputStream

OutputStream

 

可以向文件中写入字节,进行写入常用的是OutputStream的子类:FileOutputStream,常用的写入方法是write(byte[]),传入byte数组。

 

下面将是演示利用FileOutputStream来进行写入文件:

 

package com.xiaoshitou_io;

import java.io.FileOutputStream;
import java.io.IOException;

public class Test {

    /**
     * 使用FileOutputStream来写入文件
     * @throws IOException 
     * 
     */
    public static void main(String[] args) throws IOException {
        // 创建FileOutputStream对象
        // write.txt 文件在项目的根目录下面
        FileOutputStream fos = new FileOutputStream("write.txt");
        // 准备byte数组
        byte[] b = "Hello every body!".getBytes();
        
        // 写入整个数组
        fos.write(b);
        // 写入换行符,System.lineSeparator()方法返回一个字符串,表示跨平台的换行符
        fos.write(System.lineSeparator().getBytes());
        // 写入数组的一部分
        fos.write(b, 0, 5);// 应该写入的是Hello
        
        // 关闭输出流
        fos.close();
        // 文件的内容为:
        /*
        Hello every body!
        Hello
        */
        
        
    }

}

 

   如果写入的文件存在,会被覆盖掉;要想在文件的末尾进行追加内容(保留以前的内容),就需要在创建FileOutputStream对象是,向构造器传入一个true;下面演示向文件中追加内容:

 

package com.xiaoshitou_io;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {

    /**
     * 使用FileOutputStream来写入文件
     * 直接在Write.txt文件追加内容
     * @throws IOException 
     * 
     */
    public static void main(String[] args) throws IOException {
        // 创建FileOutputStream对象
        // write.txt 文件在项目的根目录下面
        
        File writeFile = new File("write.txt");
        // 在创建对象传入一个true
        FileOutputStream fos = new FileOutputStream(writeFile, true);
        // 准备byte数组
        byte[] b = (System.lineSeparator()+"我是追加的内容,哈哈").getBytes();
        // 写入文件
        fos.write(b);
        
        // 关闭输出流
        fos.close();
        // 文件的内容为:
        /*
        Hello every body!
        Hello
        我是追加的内容,哈哈
        */
        
        
    }

}

 

InputStream:

  进行文件的读取经常使用的是InputStream的子类,FileInputStream可以读取任何文件,经常用的方法就是直接读入一个byte数组,这样是为了提高读取效率,不是用一个一个字节的读取。

  下面演示一个文件的复制,文件的复制,就是利用字节输入流读取文件,然后利用输出流写入文件。下面是复制一个视频文件(同时用了输入流和输出流)

 

package com.xiaoshitou_io;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {

    /**
     * 将C:\Users\Beck\Desktop\temp目录下all.avi文件复制到
     * 当前文件中,名字为copy.avi
     */
    public static void main(String[] args){
        // 创建输入输出流
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try{
            File file = new File("C:/Users/Beck/Desktop/temp");
            fis = new FileInputStream(new File(file, "all.avi"));
            fos = new FileOutputStream(new File(file, "copy.avi"));
            // 进行读写操作
            int len = -1;
            // 每次读入1M
            byte[] b = new byte[1024*1024];
            while ((len=fis.read(b)) != -1){
                // 写入
                fos.write(b, 0, len);
            }
            
        }catch (IOException e){
            e.printStackTrace();
            throw new RuntimeException("文件复制失败!");
        }finally{
            // 关闭流对象
            try{
                if (fos != null){
                    fos.close();
                }
            }catch (IOException e){
                e.printStackTrace();
                throw new RuntimeException("释放资源失败!");
            }finally{
                try{
                    if (fis != null){
                        fis.close();
                    }
                }catch (IOException e){
                    e.printStackTrace();
                    throw new RuntimeException("释放资源失败!");
                }
            }
        }
        System.out.println("复制文件完毕!");
        // 输出结果:
        /*复制文件完毕!*/
    }

}

 

BufferedInputStream&BufferedOutputStream:

  字符缓冲输入流和字符缓冲输出流,这两个流的作用的是提高输入输出的效率。BufferedInputStream&BufferedOutputStream,接收的参数分别是InputStreamOutputStream,底层还是利用字节的输入输出流,只是对输入输出流进行了封装。

  下面利用BufferedInputStream&BufferedOutputStream进行文件的复制:

 

package com.xiaoshitou_io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {

    /**
     * 将C:\Users\Beck\Desktop\temp目录下all.avi文件复制到
     * 当前文件中,名字为copy.avi
     * 这次使用的是BufferedInputStream 和 BufferedOutputStream来完成
     */
    public static void main(String[] args){
        // 创建缓冲输入输出流
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try{
            File file = new File("C:/Users/Beck/Desktop/temp");
            bis = new BufferedInputStream(new FileInputStream(new File(file, "all.avi")));
            bos = new BufferedOutputStream(new FileOutputStream(new File(file, "copy.avi")));
            // 进行读写操作
            int len = -1;
            // 每次读入1M
            byte[] b = new byte[1024*1024];
            while ((len=bis.read(b)) != -1){
                // 写入
                bos.write(b, 0, len);
            }
            
        }catch (IOException e){
            e.printStackTrace();
            throw new RuntimeException("文件复制失败!");
        }finally{
            // 关闭流对象
            try{
                if (bos != null){
                    bos.close();
                }
            }catch (IOException e){
                e.printStackTrace();
                throw new RuntimeException("释放资源失败!");
            }finally{
                try{
                    if (bis != null){
                        bis.close();
                    }
                }catch (IOException e){
                    e.printStackTrace();
                    throw new RuntimeException("释放资源失败!");
                }
            }
        }
        System.out.println("复制文件完毕!");
        // 输出结果:
        /*复制文件完毕!*/
    }

}

 

练习:把一个视频文件按照5M的大小切割成多个。

 

package com.xiaoshitou_io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {

    /**
     * 将C:\Users\Beck\Desktop\temp目录下all.avi文件复制到
     * 这次是把all.avi视频文件切割成多个文件。按照每个文件5M的大小切割
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException{
        // 这次我把IOException直接抛出去了没有捕获
        BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream("C:/Users/Beck/Desktop/temp/all.avi"));
        // 读取视频文件
        int len = -1;
        // 每次读入5M
        byte[] bytes = new byte[1024*1024*5];
        int flag = 0;
        while ((len=bis.read(bytes)) != -1 ){
            flag++;
            // 把读入的文件写入到一个文件中
            writeToFile(bytes, len, flag);
        }
        // 关闭输入流
        bis.close();
        System.out.println("切割完成!");
        
        
    }

    // 将一个byte数组的内容写入到一个文件中
    private static void writeToFile(byte[] bytes, int len, int flag) throws IOException {
        BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream("C:/Users/Beck/Desktop/temp/copy_"+flag+".avi"));
        bos.write(bytes, 0, len);
        bos.close();
    }
}

 

  切割结果:

字符流:

输出流:Writer

输入流:Reader

字符流的底层是字节流+编码表

字符流只能操作文本文件,进行文本文件的读写,如果是为了复制文件的话,最好选择字节流进行复制。

Writer

 

Writer下面有两个常用的字符输出流:OutputStreamWriterFileWriter

 

OutputStreamWriter:接收的参数是一个OutputStream参数,也可以传一个charset编码字符串,这样就可以按照你设置的编码写入文本文件中。

 

utf-8编码形式向文本文件中写入内容:

 

package com.xiaoshitou_io;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

public class Test {
    /*
     * 以utf8的格式向文件中写入字符串
     */
    public static void main(String[] args) throws IOException{
        // 创建 OutputStreamWriter对象
        OutputStreamWriter osw = new OutputStreamWriter(
                new FileOutputStream("wirter.txt"),"utf-8");
        
        osw.write("我是OutputStreamWriter写入的,");
        osw.write("我的编码是UTF-8格式的。");
        // 字符流需要自己刷新
        osw.flush();
        // 关闭流
        osw.close();
        //输出结果,两句话在一行,因为没有写入换行符
        /*
        我是OutputStreamWriter写入的,我的编码是UTF-8格式的。
        */
        
    }        

}

 

FileWriter:可以接收的参数可以是File对象或者是String类型的;它的编码是系统默认的编码,我们的一般编码是使用的是GBK编码。

使用FileWriter向文本文件中写入字符串:

 

package com.xiaoshitou_io;

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

public class Test {
    /*
     * 用FileWriter向文件中写入内容
     */
    public static void main(String[] args) throws IOException{
        // 创建 FileWriter对象
        FileWriter fw = new FileWriter("writer_gbk.txt");
        
        fw.write("我是用FileWriter写的");
        // 写入换行符
        fw.write(System.lineSeparator());
        fw.write("我的编码是用的是默认的,GBK");
        fw.flush();
        
        // 关闭流
        fw.close();
        // 输出结果
        /*
        我是用FileWriter写的
        我的编码是用的是默认的,GBK
        */
                
    }
        

}

 

Reader:

Reader下面有两个常用的字符流:InputStreamReaderFileReader

InputStreamReader:可以按照指定的编码去读取文本文件,接收的参数是InputStream和一个编码字符串。

utf-8的编码去读取一个文本文件:

 

package com.xiaoshitou_io;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class Test {
    /*
     * 以UTF-8去读取writer.txt
     * 这个文件是刚才用utf-8的格式写入的,
     * 也只能以utf8的格式去读取,否则会出现乱码
     */
    public static void main(String[] args) throws IOException{
        // 创建InputStreamReader对象
        InputStreamReader isr = new InputStreamReader(new FileInputStream("wirter.txt"), "utf-8");
        
        int len = -1;
        // 一次可以读取1024个字符,2*1024个字节,2KB
        char[] ch = new char[1024];
        while ((len=isr.read(ch)) != -1){
            System.out.print(new String(ch, 0, len));
        }
        // 关闭流
        isr.close();
        // 输出结果:
        /*
        我是OutputStreamWriter写入的,我的编码是UTF-8格式的。
        */
    }
        

}

 

FileReader:以系统默认的编码去读取一个文本文件。接收的参数可以是一个File或者String

FileReader去读取GBK的文件,系统默认的编码是GBK

 

package com.xiaoshitou_io;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class Test {
    /*
     * 用FileReader来读取文件writer_gbk.txt
     * FileReader默认是用的是系统的默认编码
     * 本机的默认编码是GBK
     */
    public static void main(String[] args) throws IOException{
        // 创建FileReader对象
        FileReader fr = new FileReader(new File("writer_gbk.txt"));
        
        int len = -1;
        char[] ch = new char[1024];
        while ((len=fr.read(ch)) != -1){
            System.out.println(new String(ch,0,len));
        }
        
        // 关闭流
        fr.close();
        // 输出结果
        /*
        我是用FileWriter写的
        我的编码是用的是默认的,GBK
        */
        
    }
        

}

 

乱码:

乱码产生的原因:用一个A编码表将字符转成字节, 又用B编码表将字节转回字符. 两个编码表对应的关系不同,因此查到的结果就不同.

保证不乱码的方式 : 编码与解码保持相同.

 

字符流复制文件原理:

BufferedReader&BufferedWriter:

BufferedReader&BufferedWriter:字符缓冲输入输出流,接收的参数分别是:ReaderWriter;作用是提高读写的速度,读写时字符的编码是系统默认的编码:

BufferedReader特有的一个方式读取一行readLine(),不会读取换行符

BufferedWrter特有的一个方法时,newLine()写入一个换行符

在写入的数据之后,需要手动flush

利用BufferedReader&BufferedWriter进行文本文件的读写:

 

package com.xiaoshitou_io;

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

public class Test {
    /*
     * 利用BufferedReader&BufferedWriter进行文本文件的读写:
     * 复制文件:test.properties
     */
    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new FileReader("test.properties"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("test_copy.properties"));
        
        // 进行读写,缓冲流特有的方法就是可以按照行来读取,如果读取结束返回null
        String line = null;
        while ((line=br.readLine()) != null){
            bw.write(line);
            // 写入换行
            bw.newLine();
            // 刷新
            bw.flush();
        }
        
        // 关闭流
        bw.close();
        br.close();
        
    }
        
}

 

字节流和字符流的总结:

  IO流只能操作文件”文件”,不能操作文件夹(目录),否则会出现异常。

 

打印流:

  PrintStream,PrintWriter:字节打印流,字符打印流;打印流只有输出流,没有输入流;输出的目的可以是文件,也可以是其他流。PrintStream自带刷新功能,PrintWriter需要手动开启。

  PrintStream:打印出来的字符的编码使用的是系统默认编码。

 

package com.xiaoshitou_io;

import java.io.IOException;
import java.io.PrintStream;

public class Test {
    /*
     * 使用打印流:PrintStream
     */
    public static void main(String[] args) throws IOException{
        
        PrintStream ps = new PrintStream("print.txt");
        ps.println("旺旺");
        ps.println("欢欢");
        ps.println("乐乐");
        ps.close();
        // 结果:
        /*
        旺旺
        欢欢
        乐乐
        */
    }
        

}

 

  PrintWriter:

package com.xiaoshitou_io;

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

public class Test {
    /*
     * 使用打印流:PrintWriter
     */
    public static void main(String[] args) throws IOException{
        // 创建PrintWriter对象时,开启自动刷新功能
        PrintWriter pw = new PrintWriter(new FileWriter("print.txt"), true);
        
        pw.println("我是PrintWriter");
        pw.println("出来的");
        
        pw.close();
        // 结果:
        /*
        我是PrintWriter
        出来的
        */
    }
        

}

序列化&反序列化:

序列化:就是将对象写入文件的过程

反序列化:从文件读入对象的过程

ObjectOutputStream&ObjectInputStream:需要序列化的对象必须去实现Serializable接口,否则在序列化的时候会出错。

序列化的注意点:

1、static修饰的成员不能被序列化

2、要想成员变量不被序列化,可以用transient关键字修饰

3、为了不发生序列号冲突,设置:serialVersionUID

下面就进行序列化和反序列化:

 

 

 

package com.xiaoshitou_io;

import java.io.Serializable;

public class Student implements Serializable{
    private static final long serialVersionUID = -5214244848175027425L;
    private String name;
    private String id;
    private transient String phone;
    
    
    public Student(String name, String id, String phone) {
        super();
        this.name = name;
        this.id = id;
        this.phone = phone;
    }
    public Student() {
        super();
        
    }
    
    @Override
    public String toString() {
        return "Student [name=" + name + ", id=" + id + ", phone=" + phone
                + "]";
    }
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
    
}

package com.xiaoshitou_io;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Test {
    /*
     * 进行序列化和反序列化
     * 对Student对象序列化
     */
    public static void main(String[] args) throws IOException, ClassNotFoundException{
        // 创建ObjectOutputStream对象,绑定目的地
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("tmp.txt"));
        // 创建Student对象
        Student stu = new Student("张三", "T001", "15522223333");
        // 写入对象
        oos.writeObject(stu);
        // 关闭流
        oos.close();
        System.out.println("序列化成功!");
        System.out.println("==============分割==============");
        
        // 进行反序列化
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("tmp.txt"));
        // 读取对象
        Object obj = ois.readObject();
        if (obj instanceof Student){
            Student s = (Student)obj;
            System.out.println(s);
        }
        // 关闭流
        ois.close();
        System.out.println("反序列化成功!");
        // 结果:phone是transient关键字修饰的,所以没有被序列化
        /*
        序列化成功!
        ==============分割==============
        Student [name=张三, id=T001, phone=null]
        反序列化成功!
        */
        
        
    }
        

}

Properties

Properties类是HashTable的一个子类,实现了Map接口,所以里面保存的是键值对,元素的存取是无序的,这个类经常被用来处理配置文件。

利用Properties来读写文件:

 

package com.xiaoshitou_io;

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

                
标签: