IO流详细笔记。FileInputStream,FileReader,BufferedReader,FileOutputStream,FileWriter,BufferedWriter,序列化和反序列

IO流

文件

文件可认为是相关记录或放在一起的数据的集合。

java API:java.io.File类

File类访问文件属性

​ 创建文件对象:

​ File file = new File(String pathname);

File类常用方法:
IO流详细笔记。FileInputStream,FileReader,BufferedReader,FileOutputStream,FileWriter,BufferedWriter,序列化和反序列

public class FileTest {
    public static void main(String[] args) {
        File file = new File("E:\\笔记\\test.txt");
        File file1 = new File("E:\\笔记\\testshengshi.sql");
        try {
            file.createNewFile();   // 此方法创建一个空文件不能创建文件夹
            System.out.println("文件或目录是否存在"+file.exists());
            System.out.println("是否为文件:"+file.isFile());
            System.out.println("是否为目录:"+file.isDirectory());
            System.out.println("相对路径:"+file.getPath());
            System.out.println("绝对路径:"+file.getAbsolutePath());
            System.out.println("文件或目录名称:"+file.getName());
            System.out.println("文件的大小"+file1.length()+"字节");
            //System.out.println("是否删除文件:"+file.delete());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
结果
文件或目录是否存在true
是否为文件:true
是否为目录:false
相对路径:E:\笔记\test.txt
绝对路径:E:\笔记\test.txt
文件或目录名称:test.txt
文件的大小260579字节

流是指一连串流动的字符,是以先进先出的方式发送信息的通道。

java流的分类

IO流详细笔记。FileInputStream,FileReader,BufferedReader,FileOutputStream,FileWriter,BufferedWriter,序列化和反序列

输入输出流是相对于计算机内存来说的。
IO流详细笔记。FileInputStream,FileReader,BufferedReader,FileOutputStream,FileWriter,BufferedWriter,序列化和反序列

字节流是8位通用字节流,字符流是16位Unicode字符流。

文本文件的读写

InputStream类是一个抽象类,FileInputStream是其子类

FileInputStream

思路:引入相关的类–>构造文件输入流FileInputStream对象–>读取文本文件的数据–>关闭文件流对象

“E:\笔记\test.txt”事先已经存在,并且写入了内容

hello world!!!
hello world!!!

public class FileTest1 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("E:\\笔记\\test.txt");
            System.out.println("可以读取到的字节数:"+fis.available());
            // 方法一:使用输入流read()方法
            int data;
            while ((data = fis.read()) != -1){
                System.out.print((char)data);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            fis.close();
        }
    }
}
结果
可以读取到的字节数:50
hello world!!!
hello world!!!
public class FileTest2 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("E:\\笔记\\test.txt");
            System.out.println("可以读取到的字节数:"+fis.available());
            // 方法二:使用输入流read(byte[] b)方法,次方法效率更高
            byte[] b = new byte[fis.available()];
            int data1;
            while ((data1 = fis.read(b)) != -1){
                for (int i = 0; i < data1; i++) {
                    System.out.print((char)b[i]);
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            fis.close();
        }
    }
}
结果
可以读取到的字节数:50
hello world!!!
hello world!!!

结论:

  • InputStream是字节输入流,读取文件返回的是int类型的字节数长度,如果到了输入流末尾,则返回-1。
  • read()和read(byte[] b)不能同时使用,除非重新构造一个输入流FileInputStream对象,就好比一个管道里的水第一次抽光了,第二次肯定就没有了。

FileReader

思路:引入相关的类–>构造FileReader对象–>调用read()方法读取数据–>关闭文件流对象

public class FileTest3 {
    public static void main(String[] args) throws IOException {
        FileReader fr = null;
        try {
            fr = new FileReader("E:\\笔记\\test.txt");
            StringBuffer s = new StringBuffer();
            char[] a = new char[100];
            int b = -1;
            while ((b = fr.read(a)) != -1){
                s.append(a);
            }
            System.out.println(s);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            fr.close();
        }
    }
}
结果
hello world!!!
hello world!!!

BufferedReader

思路:引入相关的类–>构造BufferedReader对象和FileReader对象–>调用readLine()方法读取数据–>关闭文件流对象

public class FileTest4 {
    public static void main(String[] args) throws IOException {
        FileReader fr = null;
        BufferedReader br = null;
        try {
            fr = new FileReader("E:\\笔记\\test.txt");
            br = new BufferedReader(fr);
            String line = null; // bufferedReader是一行一行读,每一行就是字符串,用String接收
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            br.close();
            fr.close();
        }
    }
}
结果
hello world!!!
hello world!!!

FileOutputStream

思路:引入相关的类–>构造文件输出流FileOutputStream对象–>把数据写入文本文件–>关闭文件流对象

public class FileTest5 {
    public static void main(String[] args) throws IOException {
        String pathName = "E:\\笔记\\test1.txt";
        File file = new File(pathName);
        FileOutputStream fos = null;
        try {
            file.createNewFile();  // 首先创建文件
            System.out.println("写入之前文件的长度为:"+file.length()+"字节");
            fos = new FileOutputStream(pathName);
            String s = "好好学习,天天向上";
            byte[] b = s.getBytes();  // 将字符串打散为一个字节数组
            fos.write(b);
            System.out.println("写入之后文件的长度为:"+file.length()+"字节");  // 证明写入成功
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            fos.close();
        }
    }
}
结果
写入之前文件的长度为:0字节
写入之后文件的长度为:27字节

FileWriter

思路:引入相关的类–>构造FileWriter对象–>调用writer()方法写入相关的数据–>关闭文件流对象

public class FileTest6 {
    public static void main(String[] args) throws IOException {
        String pathName = "E:\\笔记\\test2.txt";
        File file = new File(pathName);
        FileWriter fr = null;
        try {
            file.createNewFile();
            System.out.println("写入之前文件的长度为:"+file.length()+"字节");
            fr = new FileWriter(pathName,true);  // 加true的意思是在原文件内容基础上进行追加
            String str = "今天是个好日子";
            fr.write(str);
            fr.flush();  // 清空缓存区
            System.out.println("写入之后文件的长度为:"+file.length()+"字节");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            fr.close();
        }
    }
}
结果
写入之前文件的长度为:0字节
写入之后文件的长度为:21字节

注意:

  1. 如果在原文件内容的基础上添加内容,需要加参数true
  2. 文件写入一般都需要清空缓存区,防止文件写不出来

BufferedWriter

思路:引入相关的类–>构造BufferedWriter对象和FileWriter对象–>调用write()方法写入相关数据–>关闭文件流对象

public class FileTest7 {
    public static void main(String[] args) throws IOException {
        String pathName = "E:\\笔记\\test3.txt";
        File file = new File(pathName);
        FileWriter fw = null;
        BufferedWriter bw = null;
        try {
            file.createNewFile();
            System.out.println("写入之前文件的长度为:"+file.length()+"字节");
            fw = new FileWriter(pathName,true); // 加true的意思是在原文件内容基础上进行追加
            bw = new BufferedWriter(fw);
            String str = "今天是元旦假期";
            String str1= "是的!";
            bw.write(str);
            bw.newLine();   // 写文本时创建新的一行
            bw.write(str1);
            bw.flush();  // 清空缓冲区,防止文件写不出来
            System.out.println("写入之后文件的长度为:"+file.length()+"字节");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            bw.close();
            fw.close();
        }
    }
}
结果
写入之前文件的长度为:0字节
写入之后文件的长度为:32字节

综合练习

public class FileTest8 {
    public static void main(String[] args) throws IOException {
        // 新创建一个文件"E:\\笔记\\test4.txt",往文件中写入"元旦假期我在学习""学习使我快乐",然后读取文件内容,并把它重新写到"E:\\笔记\\test5.txt"
        String pathName = "E:\\笔记\\test4.txt";
        String pathName1 = "E:\\笔记\\test5.txt";
        File file = new File(pathName);
        File file1 = new File(pathName1);
        FileWriter fw = null;
        BufferedWriter bw = null;
        FileWriter fw1 = null;
        BufferedWriter bw1 = null;
        FileReader fr = null;
        BufferedReader br = null;
        try {
            // 创建文件
            file.createNewFile();
            file1.createNewFile();
            // 写入内容
            fw = new FileWriter(pathName);
            bw = new BufferedWriter(fw);
            fw1 = new FileWriter(pathName1);
            bw1 = new BufferedWriter(fw1);
            String str1 = "元旦假期我在学习";
            String str2 = "学习使我快乐";
            bw.write(str1);
            bw.newLine();
            bw.write(str2);
            bw.flush();
            // 读取内容
            fr = new FileReader(pathName);
            br = new BufferedReader(fr);
            String line = null;
            while ((line=br.readLine())!=null){
                System.out.println(line);
                // 重新写入新文件
                bw1.write(line);
                bw1.newLine();
                bw1.flush();
            }
            System.out.println("test4.txt的长度为:"+file.length()+"字节");
            System.out.println("test5.txt的长度为:"+file1.length()+"字节");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            bw1.close();
            br.close();
            fr.close();
            fw1.close();
            bw.close();
            fw.close();
        }
    }
}
结果
元旦假期我在学习
学习使我快乐
test4.txt的长度为:44字节
test5.txt的长度为:46字节

读取文件中的内容,将部分内容进行替换

public class FileTest10 {
    public static void main(String[] args) throws IOException {
        // 读取"E:\\笔记\\test6.txt"内容,将里面部分内容进行替换,写入到test7.txt中
        String pathName1 = "E:\\笔记\\test6.txt";
        String pathName2 = "E:\\笔记\\test7.txt";
        FileReader fr = null;
        FileWriter fw = null;
        BufferedReader br = null;
        BufferedWriter bw = null;
        File file = new File(pathName2);
        try {
            file.createNewFile();
            fr = new FileReader(pathName1);
            br = new BufferedReader(fr);
            StringBuffer sbf = new StringBuffer();  // 使用StringBuffer进行接收
            String line = null;
            while ((line = br.readLine()) != null){
                sbf.append(line);
            }
            System.out.println("替换前的内容为:"+sbf);
            String newStr = sbf.toString()
                    .replace("{name1}","欧欧")
                    .replace("{type}","狗狗")
                    .replace("{name2}","花花");
            System.out.println("替换后的内容为:"+newStr);
            // 写入到新的文件
            fw = new FileWriter(pathName2);
            bw = new BufferedWriter(fw);
            bw.write(newStr);
            bw.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            bw.close();
            fw.close();
            br.close();
            fr.close();
        }
    }
}
结果
替换前的内容为:我养了一条叫{name1}的{type},我想把它改名为{name2}。
替换后的内容为:我养了一条叫欧欧的狗狗,我想把它改名为花花。

IO流详细笔记。FileInputStream,FileReader,BufferedReader,FileOutputStream,FileWriter,BufferedWriter,序列化和反序列

读写二进制文件

使用字节流(图片,视频,音频等非文字文件)

DataInputStream

使用DataInputStream读二进制文件

思路:引入相关的类–>构造数据输入流对象–>调用read()方法读取二进制数据–>关闭数据输入流

DataOutputStream

使用DataOutputStream写二进制文件

思路:引入相关的类–>构造数据输出流对象–>调用write()方法写二进制文件的数据–>关闭数据输出流

public class FileTest9 {
    public static void main(String[] args) throws IOException {
        // 将"E:\picture.png" 赋复制到"E:\\笔记"文件夹下
        String pathName1 = "E:\\picture.png";
        String pathName2 = "E:\\笔记\\picture.png";
        File file = new File(pathName2);
        boolean file1 = file.isFile();
        System.out.println("\"E:\\笔记\"下复制之前是否存在picture.png==>"+file1);
        // 执行复制操作
        FileTest9 copy = new FileTest9();
        copy.copyFile(pathName1,pathName2);
        boolean file2 = file.isFile();
        System.out.println("\"E:\\笔记\"下复制之后是否存在picture.png==>"+file2);
    }
    public void copyFile(String file1, String file2) throws IOException {
        FileInputStream fis = null;
        DataInputStream dis = null;
        FileOutputStream fos = null;
        DataOutputStream dos = null;
        try {
            fis = new FileInputStream(file1);
            dis = new DataInputStream(fis);
            byte[] b = new byte[fis.available()];
            while (fis.read(b)!=-1){
                fos = new FileOutputStream(file2);
                dos = new DataOutputStream(fos);
                dos.write(b);
                dos.flush();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            dos.close();
            fos.close();
            dis.close();
            fis.close();
        }
    }
}
结果
"E:\笔记"下复制之前是否存在picture.png==>false
"E:\笔记"下复制之后是否存在picture.png==>true

备注:面向对象的好处是增强代码复用性,可以将读和写的做成法,以后直接调用。

序列化和反序列化

ObjectOutputStream

序列化:

思路:实现Serializable接口–>创建FileOutputStream和ObjectOutputStream对象输出流–>调用writeObject()方法–>关闭对象输出流

ObjectInputStream

反序列化:

思路:实现Serializable接口–>创建FileInputStream和ObjectInputStream对象输入流–>调用readObject()方法–>关闭对象输出流

public class Student implements Serializable {  // 实现Serializable接口
    private String name;
    private String sex;
    private int age;
    private transient String pwd;// 某些信息不想被序列化,可以加transient,输出为null

    public Student() {}

    public Student(String name, String sex, int age, String pwd) {
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.pwd = pwd;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getPwd() {
        return pwd;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
}

public class Application {
    public static void main(String[] args) throws IOException {
        String pathName = "E:\\笔记\\student.txt";
        Student student = new Student("李明", "男", 18, "123456");
        // 序列化
        FileOutputStream fos = null;
        ObjectOutputStream oos = null;
        // 反序列化
        FileInputStream fis = null;
        ObjectInputStream ois = null;
        try {
            // 序列化
            fos = new FileOutputStream(pathName);
            oos = new ObjectOutputStream(fos);
            oos.writeObject(student);
            System.out.println("序列化成功...");
            // 反序列化
            fis = new FileInputStream(pathName);
            ois = new ObjectInputStream(fis);
            Student o = (Student) ois.readObject();
            System.out.println("反序列化成功...");
            System.out.println("反序列化后为,姓名:"+o.getName()+"\t性别:"+o.getSex()+"\t年龄:"+o.getAge()+"\t密码:"+o.getPwd());
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            ois.close();
            fis.close();
            oos.close();
            fos.close();
        }
    }
}
结果
序列化成功...
反序列化成功...
反序列化后为,姓名:李明	性别:男	年龄:18	密码:null

结论:对象要序列化,必须先实现Serializable接口,某些信息不想被序列化,可以加transient,输出为null。反序列化返回的是Object类型,需要进行类型转换。

上一篇:js 操作文件


下一篇:用FileReader对象 上传图片