Java笔记——文件操作I/O 02

目录

File类常见方法总结​编辑

相对路径

​编辑

关于 内容 的读写

1.关于读

处理文本数据(字符数据)

​编辑

查表法

小知识:终止 scanner.hasNext() 永久停止

写OutputStream 输出

​编辑

总结

​编辑 


本质介绍File方法的网页

文件 (Java Platform SE 8 ) (oracle.com)

使用Java操作文件(File),主要操作结构

 getAbsolutePath() 方法 保留一模一样的输入路径

 getCanonicalPath() 方法 保留有意义,最简洁的路径

 

 如果想得到标准的父目录方法: 

 为什么这里尾部用File的方法而不是之前的Path 一个返回类型是 File 一个是 String

原因:

 

 如果目录为空则打印就为空,如果不是目录,则打印null

 注释:如果为null就不用用foreach打印了,用toString

 

深度优先遍历 

    // 1. 深度优先的遍历
    private static void traversalDepthFirst(File dir) throws Exception {
        // 1. 找到这个目录下的所有孩子
        File[] files = dir.listFiles();
        if (files == null) {
            return;
        }

        // 2. 针对每个孩子,判断是目录还是文件
        for (File file : files) {
            if (file.isDirectory()) {
                // 如果确定是个目录,则继续递归去遍历处理
                System.out.println("[D] " + file.getCanonicalPath());
                traversalDepthFirst(file);
            } else {
                System.out.println("[F] " + file.getCanonicalPath());
            }
        }
    }

 层序遍历

    // 2. 广度优先的遍历
    private static void traversalBroadFirst(File dir) throws Exception {
        // 使用队列进行层序优先的遍历
        Queue<File> queue = new LinkedList<>();
        queue.offer(dir);

        while (!queue.isEmpty()) {
            File poll = queue.poll();
            if (poll.isDirectory()) {
                System.out.println("[D] " + poll.getCanonicalPath());
            } else {
                System.out.println("[F] " + poll.getCanonicalPath());
            }

            if (poll.isDirectory()) {
                File[] files = poll.listFiles();//取出当前目录下的所有孩子添加到队列中
                if (files == null) {
                    continue;
                }

                for (File file : files) {
                    queue.offer(file);
                }
            }
        }
    }

 重点方法

 跟之前弄的创建文件区别

 

 注释:如果目录不存在,可以用mkdirs()

src后面的目录都是程序创建的,而且是只会创建目录,就算你输入的是hello.txt 也只是目录名称叫这个而已 

 注释:修改后的路径是别的地方也可以,renameTo 相当于 剪切效果

File类常见方法总结

 JDK只提供针对节点的操作,其他都是在此基础上衍生的。

相对路径

不是一个时间段,甚至不是一个进程里面 

如果输入的是相对路径,让flie打印绝对路径会出现什么?

因为前面的这部分是这个项目的路径,默认就是这个。

如果我们手动改变的话,输出的路径也就会被改变。

在什么路径下运行,相对路径前面就打印什么路径

 第三个是工作目录 

注释:只有相对路径才考虑启动位置,绝对路径是不用考虑。

---------至此File 就讲完了

关于 内容 的读写

1.关于读

1).直接读取 (以二进制数据的方式读取,表现在代码中byte为单位)

2)文本读取
 

举例:

数着是26字符,显示却是28是因为  换行也算

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Arrays;

public class Domo3 {
    public static void main(String[] args)throws Exception {
        InputStream is = new FileInputStream("hello.txt");
        // FileInputStream 可以赋值给 InputStream,是因为 有继承关系 && FileInputStream 是 InputStream 的下级类
        // 准备好一个水桶
        byte[] buf = new byte[1024];        // 1024 代表能接 1024 滴(字节)水,我们准备好桶的容量

        // 拿着准备好的桶去水龙头接水
        int n = is.read(buf);
        // 这里的 n 代表这次真正接到了多少滴(字节)水
        // n 一定小于等于 1024 && n >= 0
//        System.out.println(n);  // 28
        // 真正的数据放在 buf 从 [0, 28)
        byte[] bytes = Arrays.copyOf(buf, n);
        for (byte b : bytes) {
            System.out.printf("%02x\n", b);
        }
        System.out.println("-----------");
        System.out.println(n);
        is.close();

    }
}

一共28个数据  以2进制打印 采用的是ASCLL码值

 

 

 接水代码

import java.io.FileInputStream;
import java.io.InputStream;

public class Domo4 {
    public static void main(String[] args)throws Exception {
        InputStream is = new FileInputStream("hello.txt");

        while(true){
            int data = is.read();//一滴一滴劫
            if(data == -1){
                // 所有数据都被读完了
                break;
            }
            byte b = (byte) data;
            System.out.printf("%02x --- %c\n",b ,b);
        }

        is.close();//资源回收
    }
}

一次一桶一桶的接水 

import java.io.FileInputStream;
import java.io.InputStream;

public class Domo5 {
    public static void main(String[] args)throws Exception {
        InputStream is = new FileInputStream("hello.txt");
        byte[] buf = new byte[5];
        while (true){
            int n = is.read(buf);//n返回值是这次读取到的有效数据个数
            // n == 0 只是本次没数据,以后还有
            // n == -1 本次没数据,以后也没数据了
            if(n == -1){
                //代表所有数据读完
                break;
            }

            for (int i = 0; i < n; i++) {
                byte b = buf[i];
                System.out.printf("%02x ---- %c\n",b,b);
            }
            
        }
        is.close();
    }
}

      try-with-resources 语法

 try的语法糖 - 为了我们方便书写整洁

我们之前写的JDBC也可以简便的写

 上面讲的要点:

 

处理文本数据(字符数据)

 

查表法

每个数字都对应一个字符

 

ASCLL 和 Unicode 

 

 ASCLL 一个字节:  实际使用中就直接使用即可

 Unicode 4个字节 :如果真的每个字都用4个字节,就有很多空间浪费,所以就产生了不同的编码规则

 我们现在用的大部分是采样 UTF-8 这样的编码规则,一个字符占用的空间大小看输入的字符是什么类型再做决定

乱码的问题

解读过程:当我们存入一个字符 '我' 时,对应的unicode 是 25105(都是假设的),然后以16进制进行保存,当我们读取时。假设我们事先并不知道这个数据是以什么方式保存的,然后我们采用了UTF - 8 编码格式进行解读,得出 19371然后去unicode里找对应的值,这样就会造成大量的错误信息。一般来说乱码是很难查的。

举例:

import java.io.FileInputStream;
import java.io.InputStream;

public class Domo7 {
    public static void main(String[] args) throws Exception {
        try (InputStream is = new FileInputStream("./hello.txt")) {
            byte[] buf = new byte[1024];
            int n = is.read(buf);
//            System.out.println(n);
//            for (int i = 0; i < n; i++) {
//                System.out.printf("%02x ", buf[i]);
//            }
            String s = new String(buf, 0, n, "UTF-8");//正常读写
            String s1 = new String(buf, 0, n, "GBK");//错误读写
            System.out.println(s);
            System.out.println("--------------");
            System.out.println(s1);
        }
    }
}

 

 不一样的读写格式,就会造成乱码

小知识:

我们平常写的 Scanner sc = new Scanner(System.in);

 

而下面这个Scanner 方法就可以让我们自己选择读取的字符集是哪种 

    public static void main(String[] args) throws Exception {
        try (InputStream is = new FileInputStream("./hello.txt")) {
            try (Scanner scanner = new Scanner(is, "UTF-8")) {
                while (scanner.hasNextLine()) {
                    String line = scanner.nextLine();   // 默认去掉了换行符
                    System.out.println("|" + line + "|");
                }
            }
        }
    }

 

源头是:InputStream

所以以后Scanner里面其实可以写 InputStream 类型

 

小知识:终止 scanner.hasNext() 永久停止

输入 ctrl + d 

 

 

写OutputStream 输出

 

 类比到计算机内容,想读取内存里面的内容并不是一个一个字符读取的,而是先在内存中分配到了一块空间(缓冲区),把你想要的内容先存到缓冲区中,到时候一次去读,这样可以减少读写的次数,增加效率

 注释:读取内存数据到外面称 刷盘

进行刷盘的时刻:

注释:一般关闭之前,统一做一次手动刷盘
         确保缓冲区(buffer)里面没有残留的数据

举例:进行刷盘操作

// OutputStream -> FileOutputStream

// 所以很少用 file.createNewFile()

// 如果文件之前不存在,则会进行创建(创建可能失败: 1. 权限、2. 路径上的目录还不存在)

// 如果文件之前存在,会清空之前的文件内容,重新写入

   创建了个world.txt的文件 

import java.io.FileOutputStream;
import java.io.OutputStream;

public class Domo9 {
    public static void main(String[] args) throws Exception {
        // OutputStream -> FileOutputStream
        // 所以很少用  file.createNewFile()
        // 如果文件之前不存在,则会进行创建(创建可能失败: 1. 权限、2. 路径上的目录还不存在)
        // 如果文件之前存在,会清空之前的文件内容,重新写入
        try (OutputStream os = new FileOutputStream("./world.txt")) {

            os.write(0x20);
            os.write(0x0d);     // '\r'
            os.write(0x0a);     // '\n'
            // 空格// 0xe6 0x88 0x91 是 "我" 的 UTF-8 编码的字节序列
//            os.write(0xe6);
//            os.write(0x88);
//            os.write(0x91);
            os.write(0x65);
            os.write(0x65);
            os.write(0x65);

            os.flush();     // 确保把缓冲区内可能遗留的数据全部写入 Output 设备中
        }
    }
}

注释:上面的字符都是一个一个进行写入

一次性写入多个方法---用数组  或者也可以只写入数组里面的部分内容

public class Domo10 {
    public static void main(String[] args) throws Exception {
        try (OutputStream os = new FileOutputStream("./world.txt")) {
            byte[] buf = { 0x65, 0x65, 0x20, 0x65, 0x0d, 0x0a, (byte)0xe6, (byte)0x88, (byte)0x91 };
//            os.write(buf);  // 整个 buf 的数据全部写入
            os.write(buf, 2, 4);  // 整个 buf 的数据全部写入
            os.flush();
        }
    }
}

上面发现用字符来输入太麻烦了,其实可以用String类

Writer抽象类 和 它的 实现类 OutputStreamWriter 

实现: write里面就可以写入字符串了

 PrintWriter实现类就更加方便了,里面有方法println 和 printf ...等等我们比较熟悉

总结

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值