Java day20、21——File、字节流、字符流、对象流

File

File - 文件类, 可以表示文件或者目录
Input/读文件 Output/写文件
所属软件包: java.io

构造方法

new File(String 文件路径)

注意: new 出来的File对象, 只是在JVM内存中有一个对象而已,和本地磁盘有没有这个文件, 无关 !a.txt不一定存在

 @Test
    public void test01(){
        // 传入文件路径, 构造File对象
        // 注意: new 出来的File对象, 只是在JVM内存中有一个对象而已
        //      和本地磁盘有没有这个文件, 无关 !
        File file = new File("a.txt");
        System.out.println(file);
    }

new File(String 父路径, String 子路径)

 @Test
    public void test02() {
        // 传入文件父路径 和 子路径, 共同构造File对象
        File file = new File("b/c","d/a.txt");
        System.out.println(file); // b/c/d/a.txt
    }

API

getAbsolutePath()

获得文件/目录的绝对路径

 @Test
    public void test01Path() {
        File file = new File("a.txt");

        // 获得file的绝对路径
        String path = file.getAbsolutePath();
        // /Users/bonnie/IdeaWorks/corejava/API_day09/a.txt
        System.out.println(path);
    }

exists()

file对应的文件或者目录存不存在

@Test
    public void test02() {
        File file = new File("src");
        // file对应的文件或者目录存不存在
        boolean exists = file.exists();
        System.out.println("src 存不存在:" + exists);
    }

isFile()/isDirectory()

是文件/是目录

@Test
    public void test03() {
        File file = new File("src"); // 目录, 并且存在
        System.out.println("src是目录吗? " + file.isDirectory());
        System.out.println("src是文件吗? " + file.isFile());

createNewFile()

创建一个文件

 @Test
    public void test04() throws IOException {
        // 创建一个文件
        File file2 = new File("a.txt");
        // file2.exists() 返回true, 就表示存在, 就不能创建新文件
        // 如果文件不存在, 就创建这个文件
        // 如果文件存在, 就不创建, 也不会报错
        file2.createNewFile();
    }

mkdir()

创建目录

@Test
    public void test05() throws IOException {
        File file2 = new File("dir");
        // 创建目录
        file2.mkdir();
    }
    
    File file2 = new File("test/a/b");
        // 创建目录, 并且可以将不存在的父目录一起创建
        file2.mkdirs();

listFiles()/list()

listFiles():获得file对象中所有的文件

@Test
    public void test07(){
        // 创建一个file对象, .表示的是当前module目录 API_day09
        File file = new File(".");

        // 列出这个目录中所有的文件和目录 File对象
        File[] files = file.listFiles();
        for(File f : files) {
            System.out.println(f);
        }
        //.\a.txt
		//.\a_bak.txt
		//.\d.txt
		//.\day20.iml
        System.out.println("-----------");
        // 列出file目录下, 所有的文件和目录的名字 -- 了解
        String[] ss = file.list();
        for (String s : ss) {
            System.out.println(s);
        }
        //a.txt
    }

listFiles(FileFilter filter)

listFiles中的过滤器
返回一个抽象路径名数组,表示由此抽象路径名表示的满足指定过滤器的目录中的文件和目录。

@Test
    public void test08() {
        File file = new File(".");
        File[] files = file.listFiles(new FileFilter() {
            @Override
            public boolean accept(File f) {
                // 只想保留文件, 不想保留目录
                return f.isFile();
            }
        });
        System.out.println(Arrays.toString(files));

        File[] files1 = file.listFiles((File f) -> {
                // 只想保留 txt 文件
                String name = f.getName();
                return name.endsWith(".txt");
            });
        System.out.println(Arrays.toString(files1));
        // 所有文件都保留
        file.listFiles(f -> true);
    }
}

递归删除非空目录

public class Demo04Delete {
    // 删除目录, 要删除目录中所有的file对象
    public void deleteFile(File file) {
        // 结束递归的条件: 1.file对象本身就是文件. 2.file是一个空目录
        File[] files = file.listFiles();
        if (files != null) {
            for (File f : files) {
                deleteFile(f);
            }
        }
        file.delete();
    }
    @Test
    public void test01() {
        File file = new File("test");
        deleteFile(file);
    }

路径

绝对路径

绝对路径: window是 - 从盘符开始 C:\xx\xx…
Linux是 - /xx/xx (从根目录开始)
以/开头的都是绝对路径

相对路径

相对路径: 会有一个参照对象 a.txt
参考值 我们称之为 - 当前目录

参考值: /Users/bonnie/Desktop 相对路径是: a.txt
那么a.txt的真实路径: /Users/bonnie/Desktop/a.txt

现在a.txt的真实路径: /Users/bonnie/IdeaWorks/corejava/API_day09/a.txt
那么现在的参考值: /Users/bonnie/IdeaWorks/corejava/API_day09

参考值: C:\IdeaWorks\day09\src 相对路径: com/zzxx/demo01/a.txt
那么a.txt的真实路径: C:/IdeaWorks/day09/src/com/zzxx/demo01/a.txt

. : 当前目录 - 现在的参考值
…: 上一级目录 - 现在的参考值 往上一层

相对路径获取绝对路径

1.xx.class.getResource(“相对路径”) -> 得到一个绝对路径
2.xx.class.getClassLoader().getResource(“相对路径”) -> 得到一个绝对路径

@Test
    public void test02() {
        String path = Demo03Path.class.
                getResource("a.txt").getPath();
        // a.txt 路径的参考值: 当前类的编译目录 - 就是当前这个包
        // 直接理解为: a.txt 和 当前这个类 同一个包
        // /Users/bonnie/IdeaWorks/corejava/out/production/API_day09/com/zzxx/a_file/a.txt
        System.out.println(path);
    }
    @Test
    public void test03() {
        String path = Demo03Path.class.getClassLoader()
                .getResource("b.txt").getPath();
        // b.txt 路径的参考值: 当前这个模块编译后的根目录 classpath - 类路径
        // 直接理解为: b.txt 就是在src下的
        // /Users/bonnie/IdeaWorks/corejava/out/production/API_day09/b.txt
        System.out.println(path);
    }
}

注意

  • 类路径 classpath: 就是src编译后的目录, 也叫编译根目录
  • 以上 1 和 2 代码得到的绝对路径, 都是在编译后的目录中, 和src没有直接关系
  • 在开发中, 我们是先将文件放入src中的, 会自动编译到类路径中

字节流

用来做文件复制

  1. 以单位来分: 字节流 字符流
  2. 以层级来分: 底层流 包装流

字节流: InputStream/OutputStream
子类: FileInputStream/FileOutputStream

构造方法

@Test
    public void test01InputStream() throws FileNotFoundException {
        InputStream is = new FileInputStream(new File("a.txt"));
        InputStream is1 = new FileInputStream("a.txt");
    }
  @Test
    public void test01OutputStream() throws FileNotFoundException {
        OutputStream os = new FileOutputStream(new File("a.txt"));
        OutputStream os1 = new FileOutputStream("a.txt");//默认false替换
        // true在原有的文件末尾上追加内容
        OutputStream os2 = new FileOutputStream("a.txt", true);
        OutputStream os3 = new FileOutputStream(new File("a.txt"), true);
    }

注意:

  1. IO所有跟文件相关的流中, 构造方法中需要File作为参数的都可以使用文件路径直接取代
  2. 字节流写和读都是以字节为单位的, 单个字节能不能正常显示出来, 是不确定的

API

write(int)

写单个字节
void write(int) : 写入这个int值的低八位,比如写入-1,最后八位都是1,读出来就是255

 @Test
    public void test01Write() throws IOException {
        // a.txt 现在不存在
        /*
          如果文件不存在, 会创建新的文件, 然后再写入内容
          如果文件存在, 会清空原来的内容, 然后再写入
         */
        OutputStream os = new FileOutputStream("a.txt");
        // 以字节为单位写入, 只写入一个字节
        // 00000000 00000000 00000001 00000000
        os.write(229);
        os.write(147); // 'a' = 97
        os.write(136); // 'A' = 65
        os.write(48); // '0' = 48
        // 10000000 00000000 00000000 00000001
        // 反:11111111 11111111 11111111 11111110
        // 补:11111111 11111111 11111111 11111111
        os.write(-1); // 11111111
    }

read()

读文件中单个字节, 并且存入int的低八位, 其余空位补0
当返回 -1 的时候, 说明文件读到了末尾

 @Test
    public void test01Read() throws IOException {
        /*
           如果文件不存在, 就会抛出 FileNotFoundException
         */
        InputStream is = new FileInputStream("a.txt");
        // 读一个字节 8位 放入int的 32位 中的低八位, 其他空位都补0
        int i ;
        while((i = is.read()) != -1) {
            System.out.println("i:" + i);
        }
    }

write(byte[])

将这个字节数组中所有的字节一起写入,编码

@Test
    public void test02Write() throws IOException {
        OutputStream os = new FileOutputStream("a.txt");
        String str = "你好, 你吃了吗?";
        // 字符串 -> 字节数组 [编码]
        byte[] bs = str.getBytes("gbk");//编码
        os.write(bs);
        //[-60, -29, -70, -61, 44, 32, -60, -29, -77, -44, -63, -53, -62, -16, 63]
        System.out.println(Arrays.toString(bs));
    }

read(byte[] bs)

读出字节数组,返回的是长度,最多一次读出bs.length个字节
读到文件末尾,返回-1

@Test
    public void test02Read() throws IOException {
        InputStream is = new FileInputStream("a.txt");
        byte[] bs = new byte[20];
        int i = is.read(bs);//返回的是数组的长度
        System.out.println("i: " + i);
        System.out.println("bs: " + Arrays.toString(bs));
    }
//
i: 15
bs: [-60, -29, -70, -61, 44, 32, -60, -29, -77, -44, -63, -53, -62, -16, 63, 0, 0, 0, 0, 0]

 		InputStream is = new FileInputStream("a.txt");
        byte[] bs = new byte[6];
        int len ;
        while((len = is.read(bs)) != -1) {
            System.out.println("len: " + len);
            System.out.println("bs: " + Arrays.toString(bs));
        }
//
len: 6
bs: [-60, -29, -70, -61, 44, 32]
len: 6
bs: [-60, -29, -77, -44, -63, -53]
len: 3
bs: [-62, -16, 63, -44, -63, -53]//最后两位是没替换之前的

write(byte[],int offset,int length)

截取一部分字节数组写入

public void test03Write() throws IOException {
        OutputStream os = new FileOutputStream("a.txt");
        String str = "你好, 你吃了吗?";
        // 字符串 -> 字节数组 [编码]
        byte[] bs = str.getBytes("gbk");
        
        os.write(bs, 0, bs.length); // 等同于  os.write(bs);
        os.write(bs, 2, 3); // 好,
        System.out.println(Arrays.toString(bs));
         //[-60, -29, -70, -61, 44, 32, -60, -29, -77, -44, -63, -53, -62, -16, 63]
    }

Buffered缓冲区

包装 -> 高级流: BufferedInputStream/BufferedOutputStream
Buffered: 缓冲/缓存,提高效率

BufferedOutputStream需要手动刷新缓冲区flush()
关闭流的时候也会自动刷新缓冲区close
关闭流一般放在try/catch的finally中
在这里插入图片描述

案例:文件复制

方法一:单个字节读出然后写入

方法一:单个字节读出然后写入
@Test
    public void copy() throws IOException {
        InputStream is = new FileInputStream("a.txt");
        OutputStream os = new FileOutputStream("a_bak.txt");
        int i ;
        while((i = is.read()) != -1) {
            os.write(i);
        }
    }


方法二:读出字节数组然后写入,效率比上面高

//write(byte[])
@Test
    public void mc() throws IOException {
        InputStream is=new FileInputStream("a.txt");
        OutputStream os=new FileOutputStream("ab.txt");
        int len;
        byte[] bs=new byte[1024];
        while ((len=is.read(bs))!=-1){
            os.write(bs,0,len);
        }
    }

方法三:缓冲区,效率最高

//Buffered
@Test
    public void copy02Buffered() throws IOException {
        InputStream is = new FileInputStream("a.mp3");
        BufferedInputStream bis = new BufferedInputStream(is);
        OutputStream os = new FileOutputStream("a_bak.mp3");
        BufferedOutputStream bos = new BufferedOutputStream(os);
        int len ;
        byte[] bs = new byte[1024];
        long time1 = System.currentTimeMillis();
        while ((len = bis.read(bs)) != -1) {
            bos.write(bs, 0, len);
        }
        long time2 = System.currentTimeMillis();
        System.out.println(time2 - time1);
    }

案例:文件加密解密

文件加密 -> 原理, 将读出来的字节做了运算后写入到新文件中
解密 -> 将加密过的文件, 再读出, 做一个还原运算, 重新写入
运算 -> 为了避免byte取值范围溢出, 同时为了避免加密解密两套代码
一般使用 ^ 运算

只能单个字节异或加密

public void copy01Buffered() {
        InputStream is = null;
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            is = new FileInputStream("a_bak.txt");
            bis = new BufferedInputStream(is);
            OutputStream os = new FileOutputStream("a_bak_back.txt");
            bos = new BufferedOutputStream(os);
            int a;
            long time1 = System.currentTimeMillis();
            while ((a = bis.read()) != -1) {
                bos.write(a ^ 1);
            }
            // 手动将缓冲区的内容写出到文件
//        bos.flush();
            long time2 = System.currentTimeMillis();
            System.out.println(time2 - time1);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bos != null) {
                // 流在关闭的时候, 也会自动刷新缓冲区内容
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

try/catch处理异常(了解)

try(resource) {} 不管有没有异常, resource都会自动关闭, 不需要finally手动关闭

finally
        try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a_bak.txt"));
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("a_bak_back.txt"))) {

字符流

字符流: Reader/Writer

Writer

OutputStreamWriter(OutputStream out, String charsetName)- 指定字符集
OutputStreamWriter(OutputStream out)- 默认字符集

 public void write01() throws IOException {
        Writer w = new OutputStreamWriter(new FileOutputStream("a.txt"));
        // 写入单个字符
        // 11111111 11111111
        w.write(-1); // 65535
        w.write(97); // a
        w.write('你');
        
        w.close();
    }
public void write02() throws IOException {
        Writer w = new OutputStreamWriter(new FileOutputStream("a.txt"));
        //写字符数组
        char[] ch = {'h', 'e', 'l', 'l', 'o'};
        w.write(ch);
        w.write('\n');
        w.write("hello");

        w.close();
    }
 public void write03() throws IOException {
        Writer w = new OutputStreamWriter(new FileOutputStream("a.txt"));
        //写字符数组的一部分
        char[] ch = {'h', 'e', 'l', 'l', 'o'};
        w.write(ch, 2, 3); // llo
        w.write("\n");
        w.write("hello", 1, 4);

        w.close();

Reader

InputStreamReader(InputStream in, String charsetName) - 指定字符集
InputStreamReader(InputStream in) - 默认字符集
注:虽然读取了⼀个字符,但是会⾃动提升为int类型。

    public void read01() throws IOException {
        Reader r = new InputStreamReader(new FileInputStream("a.txt"));
        int c = r.read();
        System.out.println((char) c);//读出来还是int型,需要转换
    }
    
public void read02() throws IOException {
        Reader r = new InputStreamReader(new FileInputStream("a.txt"));
        char[] ch = new char[10];
        int len = r.read(ch);
        System.out.println(len);
        System.out.println(ch);
    }

缓冲(包装)字符流

通常用来读写文件内容,效率>>>>

BufferedReader(Reader)

readLine()
读一整行,读到末尾返回null

public void test01() throws IOException {
        BufferedReader br = new BufferedReader(
                new InputStreamReader(
                        new FileInputStream("a.txt"), "gbk"));
        String str;
        while ((str = br.readLine()) != null) {
            System.out.println(str);
        }
        br.close();
    }

PrintWriter

PrintWriter(String fileName, String csn)

只能清空原文件内容, 但是可以指定字符集

PrintWriter(OutputStream out, boolean autoFlush)

可以在原文件上追加内容, 但是不可以指定字符集, 可以自动刷新缓冲区

PrintWriter(Writer out, boolean autoFlush)

可以在原文件上追加内容, 可以指定字符集, 可以自动刷新缓冲区

 @Test
    public void test02() throws IOException {
        PrintWriter pw = new PrintWriter(
                new OutputStreamWriter(
                        new FileOutputStream("a.txt", true), "gbk"), true);
        pw.print("?");
        pw.println();
        pw.println("没有");

//        pw.flush();
    }
    @Test
    public void test03() throws IOException {
        PrintWriter pw = new PrintWriter(
                new OutputStreamWriter(
                        new FileOutputStream("a.txt", true), "gbk"), true);

        pw.print("你怎么还不找!");
        pw.print("都多大人了!");
        pw.flush();
    }
print和println

void print(Object): 写出内容, 不加换行
void println(): 写出内容, 并且换行
注意: 自动刷新的功能, 只有println方法具有
print方法 必须手动刷新

对象流

对象 -> 文件[字节] : 序列化
文件[字节] -> 对象 : 反序列化

API

 public void test01Init() throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));
    }

 public void test02Write() throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));

        Date date = new Date();
        oos.writeObject(date);

        String str = "hello";
        oos.writeObject(str);

        oos.writeObject(null);

        oos.close();
    }
public void test03Read() throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));

        Date d = (Date) ois.readObject();
        System.out.println(d);

        String s = (String) ois.readObject();
        System.out.println(s);
        // 没有对象了, 读出来的是 EOFException  End Of File
        Object o = ois.readObject();
        System.out.println(o);
    }

Serializable: 可序列化的

内部没有任何字段方法

serialVersionUID

给类添加固定的序列版本号

transient

修饰的变量, 在序列化的时候, 会被忽略掉

public class Student implements Serializable {
    // 序列化后的版本编号, 不指定的话,
    // 会自动生成一串, 会随着类内容的修改而改变
    public static final long serialVersionUID = 1234l;
    private String name;
    private int age;
    // 序列化的时候, sex对应的值会被忽略
    private transient char sex;

public void test01Write() throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("stu.obj"));

        Student s = new Student();
        s.setName("杨幂");
        s.setAge(38);
        s.setSex('女');
        // NotSerializableException
        oos.writeObject(s);

        oos.close();
    }

public void test02Read() throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("stu.obj"));

        // NotSerializableException
        Student s = (Student) ois.readObject();

        ois.close();
        System.out.println(s);
    }

流的选择

文件复制:
BufferedInputStream/BufferedOutputStream

文件内容读写:
BufferedReader/PrintWriter
FileReader/FileWriter

对象读写:
ObjectInputStream/ObjectOutputStream

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值