【JavaEE】文件io

目录

文件类型

File概述

属性

构造方法

常用方法

Reader

Writer

InputStream

OutputStream

字节流转字符流

通过Scanner读取InputStream

通过PrintWriter转换outputstream

示例


文件类型

从编程的角度看,文件类型主要就是两大类

  • 文本(文件中保存的数据,都是字符串,保存的内容都是合法的字符)
  • 二进制(文件中保存的数据,仅仅是二进制数据,不要求保存的内容是合法的字符)

File概述

属性

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

D:\

如上所示,"\"就是一个路径分隔符

构造方法

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

常用方法

修饰符及返回类型 方法签名 说明
String getParent() 返回File对象的父目录文件路径
String getName() 返回File对象的纯文本名称
String getPath() 返回File对象的文件路径
String getAbsolutePath() 返回File对象的绝对路径
String getCanonicalPath() 返回File对象修饰过的绝对路径
boolean exists() 判断File对象描述的文件是否真实存在
boolean isDirectory() 判断File对象代表的文件是否是一个目录
boolean isFile() 判断File对象代表的文件是否是一个普通文件
boolean createNewFile() 根据File对象,自动创建一个空文件,成功创建返回true
boolean delete() 根据File对象,删除该文件
void deleteOnExit() 根据File对象,标注文件将被删除,删除动作会到JVM运行结束时才删除
String[] list() 返回File对象代表的目录下所有文件名
File[] listFiles() 返回File对象代表的目录下的所有文件,以File对象表示
boolean mkdir() 创建File对象代表的目录
boolean mkdirs() 创建File对象代表的目录,如果必要,会创建中间目录
boolean renameTo(File dest) 进行文件改名,也可以视为平时的剪切、粘贴操作
boolean canRead() 判断用户是否对文件有可读权限
boolean canWrite() 判断用户是否对文件有可写权限

在标准库中,提供的读写文件的流对象,有很多个类,可以归结为两个大的类别中:

1、字节流(对应着二进制文件),每次读/写的最小单位,都是"字节"

  • InputStream
  • OutputStream

2、字符流(对应着文本文件) ,每次读/写的最小单位,是"字符",一个字符可能对应多个字节,跟当前字符集编码方式有关,本质上,是针对字节流进行了又一层封装

  • Reader
  • Writer

上述四种是抽象类,不能直接new实例

  1. 无参数read:一次读取一个字符
  2. 一个参数read:一次读取若干个字符,会把参数指定的buf数组给填充满
  3. 三个参数read:一次读取若干个字符,会把参数执行的cbuf数组中,从off这个位置开始,到len这么长的范围尽量填满

使用示例:

Reader

一次read一个字符

try(Reader reader = new FileReader("D:/data.txt");){

while (true) {

int c = reader.read();

if (c == -1) {

//读取完毕

break;

}

char ch = (char) c;

System.out.println(ch);

}

} catch (IOException e) {

throw new RuntimeException(e);

}

read方法一次读取一个字符,返回数字,当返回值为-1时,代表读取到文件末尾

一次read多个字符

Reader reader=new FileReader("D:/data.txt");

try{

while(true){

char[] ch=new char[1024];

int n= reader.read(ch);

if(n==-1)

{

//读取完毕

break;

}

System.out.println("读取长度:"+n);

System.out.println(Arrays.toString(ch));

}

} catch (IOException e) {

throw new RuntimeException(e);

} finally {

try {

reader.close();

} catch (IOException e) {

throw new RuntimeException(e);

}

}

这样写虽然能够解决中途抛异常,导致reader不能正常释放,但是不够优雅,我们可以采取try with resources方法 ,Reader reader=new FileReader("D:/data.txt")在出了作用域后,会自动调用close方法

try(Reader reader=new FileReader("D:/data.txt")){

while(true){

char[] ch=new char[1024];

int n= reader.read(ch);

if(n==-1)

{

//读取完毕

break;

}

System.out.println("读取长度:"+n);

System.out.println(Arrays.toString(ch));

}

} catch (IOException e) {

throw new RuntimeException(e);

}

Writer

try(Writer writer=new FileWriter("D:/data.txt"))

{

writer.write("你好你好");

} catch (IOException e) {

throw new RuntimeException(e);

}

Writer写入文件,默认情况下,会将原来的数据清空掉,如果不想清空,需要在构造函数中再传入一个参数 ,这样就能实现追加写

Writer writer=new FileWriter("D:/data.txt",true)

utf8编码,一个中文字符是3个字节,在Java标准库内部:

  • 如果是只使用char,此时使用的字符集,固定就是unicode;
  • 如果是使用String,此时就会自动的把每个字符的unicode转换utf8

InputStream

字节流与字符流不同的是,传入的数组是byte类型的,read返回值是int,其实是byte,0-255之间的值,-1表示到达文件末尾

try(InputStream inputStream=new FileInputStream("D:/data.txt"))

{

byte[] buffer=new byte[1024];

int n=inputStream.read(buffer);

System.out.println("n = "+n);

for(int i=0;i<n;i++)

{

System.out.printf("%x\n",buffer[i]);

}

} catch (IOException e) {

throw new RuntimeException(e);

}

OutputStream

OutputStream和Writer类似,打开一个文件,默认就会清空文件的原有内容

try(OutputStream outputStream=new FileOutputStream("d:/data.txt"))

{

String str="你好";

outputStream.write(str.getBytes());

} catch (IOException e) {

throw new RuntimeException(e);

}

若要使用追加的方式写入,可以在构造方法的第二个参数中传入true

OutputStream outputStream=new FileOutputStream("d:/data.txt",true)

字节流转字符流

当提供的是字节流对象,但实际数据内容是文本数据,我们可以将字节流转换成字符流

通过Scanner读取InputStream

try(InputStream inputStream=new FileInputStream("d:/data.txt"))

{

Scanner scanner=new Scanner(inputStream);

String str=scanner.next();

System.out.println(str);

} catch (IOException e) {

throw new RuntimeException(e);

}

通过PrintWriter转换outputstream

try(OutputStream outputStream=new FileOutputStream("d:/data.txt"))

{

PrintWriter writer=new PrintWriter(outputStream);

writer.println("hello");

} catch (IOException e) {

throw new RuntimeException(e);

}

PrintWriter这样的类,在进行写入的时候,不一定是直接写硬盘,而是先把数据写入到一个内存构成的缓冲区中,当我们写入缓冲区之后,如果还没来得及把缓冲区的数据写入硬盘中,进程就结束了,此时数据就丢失了,为了能够确保数据确实被写入硬盘,就应该在合适的时机,使用flush方法手动刷新缓冲区,因此上述的代码需要修改一下:

try(OutputStream outputStream=new FileOutputStream("d:/data.txt"))

{

PrintWriter writer=new PrintWriter(outputStream);

writer.println("hello");

writer.flush();

} catch (IOException e) {

throw new RuntimeException(e);

}

示例

扫描指定目录,并找到名称中包含指定字符的所有普通文件(不包括目录),并且后续询问用户是否要删除该文件

java 复制代码
    public static void main(String[] args) throws FileNotFoundException {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入搜索路径:");

        String direcory = scanner.next();
        File sourceFile = new File(direcory);
        if (!sourceFile.isDirectory()) {
            System.out.println("搜索路径有误!");
            return;
        }

        System.out.println("请输入要删除文件的关键词:");
        String word=scanner.next();
        scanDir(sourceFile,word);
    }

    public static void scanDir(File rootPath, String word)
    {
        File[] files = rootPath.listFiles();

        if(files==null)
            return;

        for (File file : files) {
            System.out.println("当前扫描的文件: " + file.getAbsolutePath());
            if (file.isFile()) {
                checkDelete(file,word);
            } else {
                scanDir(file,word);
            }
        }
    }
    public static void checkDelete(File rootPath, String word)
    {
        if(!rootPath.getName().contains(word))
        {
            //不必删除,直接方法结束
            return ;
        }
        //需要删除
        Scanner scanner = new Scanner(System.in);
        System.out.println("是否需要删除(Y/N):");
        String choice=scanner.next();
        if(choice.equals("Y")||choice.equals("N"))
        {
            rootPath.delete();
            System.out.println("删除完毕!");
        }
    }
相关推荐
南宫生8 分钟前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石16 分钟前
12/21java基础
java
高山我梦口香糖24 分钟前
[react]searchParams转普通对象
开发语言·前端·javascript
李小白6624 分钟前
Spring MVC(上)
java·spring·mvc
GoodStudyAndDayDayUp37 分钟前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea
信号处理学渣1 小时前
matlab画图,选择性显示legend标签
开发语言·matlab
红龙创客1 小时前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
jasmine s1 小时前
Pandas
开发语言·python
装不满的克莱因瓶1 小时前
【Redis经典面试题六】Redis的持久化机制是怎样的?
java·数据库·redis·持久化·aof·rdb
n北斗1 小时前
常用类晨考day15
java