I/O,文件操作,File类

前言

小亭子正在努力的学习编程,接下来将开启javaEE的学习~~

分享的文章都是学习的笔记和感悟,如有不妥之处希望大佬们批评指正~~

同时如果本文对你有帮助的话,烦请点赞关注支持一波, 感激不尽~~

目录

前言

前驱知识

文件:

目录:

 文件路径(Path):

文件类型

Java 中操作文件

1.文件系统操作

File类的属性

File类的构造方法

File类的常用方法

​2.文件内容操作

字符流   和字节流

输入输出流:

 InputStream 概述

FileInputStream 概述

 InputStream的方法:

OutputStream 概述

 小案例:

遍历目录,查找包含某个关键词的文件


前驱知识

文件:

我们先来认识狭义上的文件(file)。针对硬盘这种持久化存储的I/O设备,当我们想要进行数据保存时,往往不是保存成一个整体,而是独立成一个个的单位进行保存,这个独立的单位就被抽象成文件的概念,就类似办公桌上的一份份真实的文件一般。

目录:

随着文件越来越多,对文件的系统管理也被提上了日程,如何进行文件的组织呢,一种合乎自然
的想法出现了,就是按照层级结构进行组织 —— 也就是我们数据结构中学习过的树形结构。这样,一种专门用来存放管理信息的特殊文件诞生了,也就是我们平时所谓文件夹(folder)或者目录(directory)的概念。

【一般在计算机中我们将文件夹叫做  目录】


 文件路径(Path):

 

 咱们电脑的文件存储的形式就像一颗树一样,从根节点出发,向下分叉衍生

  • 文件路径:就是从树根结点出发,沿着树杈,一路向下走,达到目标寄文件,这个过程中经过的文件就是路径。
  • 绝对路径:从盘符开始,一层一层往下找,这个过程得到的路径。
  • 相对路径:从给定的某个目录出发,一层一层往下找,,这个过程得到的路径。

【注意:区分的重点在于找准基准目录(工作目录)是哪个】

特殊标识符:

  • . 相对路径中,表示当前目录
  • .. 相对路径中,表示当前目录的上级目录
  • 路径中的每级目录之间用一个路径分隔符隔开,/ or \\ or \

【路径分隔符和系统有关:
●windows和DOS系统默认使用“\”来表示
●UNIX和URL使用“/”来表示】

【注意:

  • 在Windows 中,路径和文件是一一对应的,任何一个文件,对应的路径是惟一的。但是在Linux中不一定。
  • word,Excel,是二进制文件.csv 是文档文本】

文件类型

文件类型分为:

文本文件:存储的是文本,内容是由ASCII码构成的。
二进制文件:存储的是二进制数据。(内容不受限制)

【一个简单粗暴的区分方法:打开文件,你能看懂的就是文本文件,乱七八糟的你看不懂的就是二进制文件。注意,word写的docx,Excel的文件是二进制。】

Java 中操作文件

1.文件系统操作

创建文件,删除文件,重命名文件,创建目录

Java 中通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述。注意,有 File 对象,并不代表真实存在该文件

File 能新建、删除、重命名文件和目录,但 File 不能访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流,下面会说到
File对象可以作为参数传递给流的构造器

File类的属性

修饰符及类型属性说明
static StringpathSeparator依赖于系统的路径分隔符,String 类型的表示
static charpathSeparator依赖于系统的路径分隔符,char 类型的表示

File类的构造方法

签名说明
File(File parent, String
child)
根据父目录 + 孩子文件路径,创建一个新的 File 实例
File(String pathname)根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者
相对路径
File(String parent, String
child)
根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用
路径表示

File类的常用方法


2.文件内容操作

针对文件内容进行读和写

补充知识


流的分类:
操作数据单位:字节流(8 bit)、字符流(16 bit)
数据的流向:输入流、输出流
流的角色:字节流、处理流
体系结构:抽象基类、节点流、处理流
节点流:直接从数据源或目的地读写数据
处理流:不直接连接到数据源或目的地,而是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能
【本文我们主要讨论字节流,字符流,输入流和输出流】

字符流   和字节流

  • 针对  文本文件,提供了一组类,统称为 “字符流”,(典型代表:Reader(读),Writer(写)),读写基本单是:字符
  • 针对 二进制文件,提供了一组类,统称为“字节流”,(典型代表:InputStream(读),OutputStream(写))读写基本单位是:字节

输入输出流:

输入:Reader,InputStream
输出:Writer,OutputStream】

输入输出的方向注意要以cpu为基准去判断

 InputStream 概述

InputStream 只是一个抽象类,不仅可以读写文件,还可以读写背的,比如网卡。要使用还需要具体的实现类。关于 InputStream 的实现类有很多,基本
可以认为不同的输入设备都可以对应一个 InputStream 类,我们现在只关心从文件中读取,所以使用它的子类FileInputStream

FileInputStream 概述

构造方法

签名说明
FileInputStream(File file)利用 File 构造文件输入流
FileInputStream(String name)利用文件路径构造文件输入流

代码实现一下(注意:这种方式不建议用,因为return,异常之类的情况可能会导致close()执行不到,推荐写法在下面)

推荐写法:

 注意:

1.可能会因为权限问题和中文文件名报错,大家实现代码的时候注意一下
2.close()方法千万不能忘记写。因为在java中,文件这里的资源(主要是文件描述符表)需要手动释放。
文件描述符:
记载当前进程都打开了那些文件。
每次打开一个文件,就会在这个表里,这个表记载了当前进程打开了哪些文件,每次打开一个文件就会在这个表里申请空间。这个表的空间是有限的,不停地申请空间,又不释放,空间会满,一旦满了,继续打开文件就会打开失败,严重的还会文件资源泄露。

 InputStream的方法:

返回值类
方法签名说明
intread()读取一个字节的数据,返回 -1 代表已经完全读完了
intread(byte[] b)最多读取 b.length 字节的数据到 b 中,返回实际读到的数
量;-1 代表以及读完了
intread(byte[] b,
int off, int len)
最多读取 len - off 字节的数据到 b 中,放在从 off 开始,返
回实际读到的数量;-1 代表以及读完了
voidclose()关闭字节流

代码示例:

读操作,字节流

public class IODemo1 {
    public static void main(String[] args) throws IOException {
//        //文件打开                      //此处需要抛异常
//        InputStream inputStream = new FileInputStream("D:/yunna/Desktop/笔记草稿/IO测试文件");
//        inputStream.close();//关闭文档,千万不能忘了
//推荐使用下面这种写法, 因为InputStream实现了Closeable这一特定的接口,这样写try会自动帮忙调用.
       try( InputStream inputStream = new FileInputStream("D:\\code\\text.txt")){
       //读文件
           while(true){
               int b = inputStream.read();
               if (b==-1){
                   //读到末尾了,结束循环
                   break;
               }
               System.out.println(b);
           }


       }
    }
}

读操作,字符流

public class IODemo3 {
    public static void main(String[] args) {
        try(Reader reader = new FileReader("D:\\code\\text.txt")){
            while(true){
                int c = reader.read();
                if(c==-1){
                    break;
                }
                char ch = (char) c;
                System.out.println(ch);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

OutputStream 概述

OutputStream 同样只是一个抽象类,要使用还需要具体的实现类。我们现在还是只关心写入文件中,所以使用 FileOutputStream

方法

修饰
符及
返回
值类
方法签名说明
voidwrite(int b)写入要给字节的数据
voidwrite(byte[]
b)
将 b 这个字符数组中的数据全部写入 os 中
intwrite(byte[]
b, int off,
int len)
将 b 这个字符数组中从 off 开始的数据写入 os 中,一共写 len 个
voidclose()关闭字节流
voidflush()重要:我们知道 I/O 的速度是很慢的,所以,大多的 OutputStream 为
了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的
一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写
入设备中,这个区域一般称为缓冲区。但造成一个结果,就是我们写的
数据,很可能会遗留一部分在缓冲区中。需要在最后或者合适的位置,
调用 flush(刷新)操作,将数据刷到设备中。

代码示例:写操作,字节流

public class IODemo2 {
    //写操作
    public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("D:\\code\\text.txt")){
            outputStream.write(97);//注意这个写入的是ascii码值
            outputStream.write(98);
            outputStream.write(99);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 写操作,字符流

public class IODemo4 {
    public static void main(String[] args) {
        try(Writer writer  = new FileWriter("D:\\code\\text.txt")) {
            writer.write(65);
            writer.write(66);
            writer.write(67);
            writer.write(68);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 小案例:

遍历目录,查找包含某个关键词的文件

步骤:

//让用户先指定一个要搜索的根目录
//让用户输入一个要查询的词

//递归进行目录/文件的遍历(目录结构是一颗N叉树)
注意:这种方法不高效,但是小规模搜索还是可以的

import java.io.*;
import java.util.Scanner;

public class IODemo5 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        //先让用户指定一个要搜索的根目录
        System.out.println("请输入需要搜索的目录:");
        File rootDir = new File(scanner.next());
        if (!rootDir.isDirectory()){
            System.out.println("输入有误,您输入的目录不存在!");
            return;
        }
        //让用户输入一个要查询的词
        System.out.println("请输入要查询的词");
        String word = scanner.next();

        //递归的进行目录文件的遍历
        scanDir(rootDir,word);
    }
    private static void scanDir(File rootDir,String word){
        //列出当前的rootDir 中的内容,没有内容,直接递归结束
        File[] files = rootDir.listFiles();
        if (files == null){
            //当前rootDir 是一个空目录,直接结束不用递归
            return;
        }
        //目录里有东西,就遍历每个元素
        for (File f: files){
            System.out.println("当前搜索到:"+ f.getAbsoluteFile());
            if (f.isFile()){
                //是普通文件,就打开文件,比较看是否包含关键词
                String content = readFile(f);
                if (content.contains((word))){
                    System.out.println(f.getAbsoluteFile()+"包含要查找的关键字");
                }
            }else if(f.isDirectory()){
                //是目录,就进行递归操作
                scanDir(f,word);

            }else{
                //不是普通文件也不是目录文件,直接跳过
                continue;
            }
        }
    }

    private static String readFile(File f) {
        //读取文件的整个内容,返回出来,匹配的是字符串,所以用字符流
     StringBuilder stringBuilder = new StringBuilder();
     try (Reader reader = new FileReader(f)){
         //一次读取一个字符,把读到的结果拼装到StringBuilder中,统一转成String
         while (true){
             int c = reader.read();
             if(c== -1){
                 break;
             }
             stringBuilder.append((char)c);
         }

     } catch (FileNotFoundException e) {
         e.printStackTrace();
     } catch (IOException e) {
         e.printStackTrace();
     }
     return stringBuilder.toString();
    }
}


注意:

上述代码没有考虑文件特别大,内存存不下的情况,如果真遇到这种情况,可以考虑把文件分块读取

说明:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值