文件操作和IO

在计算机中,大前提下,所有的文件都是二进制的,有些文本文件比较特殊,二进制数据刚好可以构成字符

Java标准库中提供了一系列类用来操作文件

File类

File用于操作系统文件,可以抽象表示为文件或者目录,但它根本上不是,只是代表文件或者目录的路径

File中的常用方法

public class Demo1 {
    public static void main(String[] args) throws IOException {
//        File file=new File("E:/编程的学习/Java EE初阶/newFile/newFile/test.txt");
        File file=new File("./test.txt");
        System.out.println(file.getParent());//返回file对象的父目录文件路径
        System.out.println(file.getName());//返回file对象的文件名称
        System.out.println(file.getPath());//返回file对象的文件路径
        System.out.println(file.getAbsolutePath());//返回file对象的绝对路径
        System.out.println(file.getCanonicalPath());//返回file对象的修饰过的绝对路径
        System.out.println(file.exists());//返回file对象描述的文件是否真实存在
    }
}

public class Demo2 {
    public static void main(String[] args) throws IOException {
        File file=new File("./test.txt");
        System.out.println(file.createNewFile());//如果该文件不存在,则可以直接创建
        System.out.println(file.getAbsolutePath());//得到文件的绝对路径
        System.out.println(file.getName());//得到文件的名称
        System.out.println(file.getPath());//得到文件的路径
    }
}

文件操作常常涉及到的异常

file.delete()立刻删除该文件

file.deleteOnExit()删除文件动作到jvm运行结束后才会进行

public class Demo3 {
    public static void main(String[] args) throws InterruptedException {
        File file=new File("./test.txt");
        file.delete();//立刻删除该文件
        file.deleteOnExit();//根据file对象,标注该文件将会被删除,删除动作到jvm运行结束后才会进行
        Thread.sleep(10000);
    }
}

file.list();获得该目录下的所有目录或者文件名

file.listFiles()获得该目录下的所有目录或者文件名的绝对路径

public class Demo4 {
    public static void main(String[] args) {
//        针对list的操作只能根据目录来完成,不能根据单个文件
        File file=new File("E:/");
        String[] s=file.list();  //返回File对象代表的目录下的文件名
        System.out.println(Arrays.toString(s));
        File[] files = file.listFiles();//返回File对象代表的目录下的文件,以File对象表示
        System.out.println(Arrays.toString(files));
    }
}

file.mkdir() 创建单级目录

file.mkdirs() 创建多级目录

public class Demo5 {
    public static void main(String[] args) {
        File file=new File("./test/aa/bb/cc");

        //mkdir只能创建单级目录
        boolean mkdir  = file.mkdir();

        //mkdirs可以创建多级目录
        boolean mkdirs = file.mkdirs();
        System.out.println(mkdirs);
    }
}

文件的重命名可以起到移动的作用

file.renameTo()

public class Demo6 {
    public static void main(String[] args) {

        //文件的重命名可以起到移动的作用
        File file=new File("./test.txt");
        File newFile=new File("./src/test.txt");
        System.out.println(file.renameTo(newFile));
        System.out.println(file.getPath());
    }
}

绝对路径:从根目录开始写的完整路径,定位唯一,不依赖当前所在的位置

相对路径:相对于当前的工作目录(当前的路径),来写的路径

文件IO

文件IO的输出输入方式通过数据流来实现

字节流

InputStream,读文件(输入)

OutputStream,写文件(输出)

字符流

Reader 读文件(输入)

Writer 写文件(输出)

字节流

InputStream

这里的创建对象,就相当于打开文件

但是又打开文件,就得有关闭文件

我们采用了try,finally,在结果加上关闭文件的操作

InputStream inputStream=null;
        try {
            inputStream=new FileInputStream("test.txt");
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }finally {
            inputStream.close();
        }

但是这样的代码十分的不美观

我们采用try-with-resources(自动资源管理)

只要出了try的代码块,就会自动的调用close

要求代码块中的类实现Closeable或者AutoCloseable

InputStream中的read方法,可以使用-1表示读取完毕,有一次读取一个的方法参数配置,也有多个的,和指定偏移量的参数配置


public class Demo7 {
    public static void main(String[] args) throws IOException {
//        InputStream inputStream=null;
//        try {
//            inputStream=new FileInputStream("test.txt");
//        } catch (FileNotFoundException e) {
//            throw new RuntimeException(e);
//        }finally {
//            inputStream.close();
//        }

        //InputStream实现了Closeable,会自动的帮助你结束字节流
        try (InputStream inputStream=new FileInputStream("test.txt")){
            while (true){
                //一次读一个字节
//                int read = inputStream.read();
//                if(read==-1){
//                    break;
//                }
//                System.out.printf("0x%x\n",read);

                //一次读多个字节
                byte[] data=new byte[3];//每次读三个字节

                int n=inputStream.read(data);
                if(n==-1){
                    break;
                }
                System.out.println("n="+n);
                for (int i = 0; i < n; i++) {
                    System.out.printf("0x%x\n",data[i]);
                }

            }
        }
    }
}

OutputStream

outputStream的write方法在文件中可以一次性只写一个,或者多个

public class Demo8 {
    public static void main(String[] args) {
//        这里面的true就是不会覆盖之前的内容,在后面追加
        try(OutputStream outputStream=new FileOutputStream("./test.txt",true)) {
            //一次写一个
//            outputStream.write(1);
//            outputStream.write(2);
//            outputStream.write(3);
//            outputStream.write(4);

            //一次写多个
            byte[] bytes=new byte[]{12,23,34};
            outputStream.write(bytes);
            InputStream inputStream=new FileInputStream("test.txt");
            while (true){
                int read = inputStream.read();
                if (read==-1){
                    break;
                }
                System.out.printf("0x%x\n",read);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

字符流

Reader

读文件(输入)

public class Demo9 {
    public static void main(String[] args) {
        try(Reader reader=new FileReader("./test.txt")) {
            while (true){
                char[] chars=new char[1024];
                int read = reader.read(chars);
                if (read==-1){
                    break;
                }
                for (int i = 0; i < read; i++) {
                    System.out.print(chars[i]);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

Writer

Writer 写文件(输出)

BufferedWriter就是给Writer添加一个缓冲区,提高效率,BufferedWriter会先把数据写入内存的缓存区,等缓存满了或者调用flush()/close()时再一次性写入磁盘中

public class Demo10 {
    public static void main(String[] args) {
        try(Writer writer=new FileWriter("./test.txt",true);
            BufferedWriter bufferedWriter=new BufferedWriter(writer)) {
            bufferedWriter.write("我是谁");
            Reader reader=new FileReader("./test.txt");
            while (true){
                char[] chars=new char[1024];
                int read = reader.read(chars);
                if (read==-1){
                    break;
                }
                for (int i = 0; i < read; i++) {
                    System.out.print(chars[i]);
                }
            }


        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

总结:

字节流和字符流两种代码都是对的,字节流读取到的时文件中原始的数据,字符流在读取的时候,会根据文件的内容编码格式,会自动进行解析(转码),转码会有性能的开销,所以字节流会比字符流快

转码的大概流程:

read一次,读到三个字节,返回的时候,针对3个字节进行转码,先拿3个字节查了一下utf8码表得到 ‘ 你 ’ read又把你这个汉字在unicode这个码表中再查一次,得到unicode的编码值,最终把unicode得到的编码值存储到char变量中(两字节)

专项练习1:扫描指定⽬录,并找到名称中包含指定字符的所有普通⽂件(不包含⽬录),并且后续询问⽤⼾是否 要删除该⽂件


/**
 * 扫描指定⽬录,并找到名称中包含指定字符的所有普通⽂件(不包含⽬录),并且后续询问⽤⼾是否 要删除该⽂件
 */
public class Demo11 {
    public static Scanner scanner=new Scanner(System.in);
    public static void main(String[] args) {
        System.out.println("请输入你要扫描的路径");
        String rootFile = scanner.nextLine();
        File files=new File(rootFile);
        if (!files.isDirectory()){
            System.out.println("你输入的不是目录");
        }
        System.out.print("请输入你要删除的关键词:");
        String key=scanner.next();
        scan(files,key);

    }

    private static void scan(File rootFile, String key) {
        File[] file=rootFile.listFiles();
        if (file==null){
            System.out.println("该目录不存在");
            return ;
        }
        for (File file1:file){
            if(file1.isFile()){
                delete(file1,key);
            }else {
                scan(file1,key);
            }
        }
    }

    private static void delete(File file1, String key) {
        if (file1.getName().contains(key)){
            System.out.println("请输入你是否要删除,这个文件,如果删除,请输入 y");
            String next = scanner.next();
            if(next.equalsIgnoreCase("y")){
                file1.delete();
                System.out.println("该文件已经删除");
            }
        }
    }

}

专项练习2:进⾏普通⽂件的复制


/**
 * 进⾏普通⽂件的复制
 */
public class Demo12 {
    public static void main(String[] args) {
        System.out.println("请输入你要复制文件的绝对路径/相对路径");
        Scanner scanner=new Scanner(System.in);
        String sourcePath=scanner.next();
        File sourceFile=new File(sourcePath);
        if (!sourceFile.exists()){
            System.out.println("该文件不存在");
            return;
        }
        if (!sourceFile.isFile()){
            System.out.println("你输入的路径不是文件");
            return;
        }
        System.out.println("请输入你要复制到的文件");
        String destPath=scanner.next();
        File destFile=new File(destPath);
        if (!destFile.exists()){
            System.out.println("该文件不存在");
            return;
        }
        if (!destFile.isFile()){
            System.out.println("你输入的路径不是文件");
            return;
        }
        try(InputStream inputStream=new FileInputStream(sourceFile);
            OutputStream outputStream=new FileOutputStream(destFile)) {

            while (true){
                byte[] bytes=new byte[1024];
                int read = inputStream.read(bytes);
                if (read==-1){
                    break;
                }
                outputStream.write(bytes,0,read);
                System.out.println("复制成功");
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
}

专项练习3:扫描指定⽬录,并找到名称或者内容中包含指定字符的所有普通⽂件(不包含⽬录)

/**
 * 扫描指定⽬录,并找到名称或者内容中包含指定字符的所有普通⽂件(不包含⽬录)
 */
public class Demo13 {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入你要扫描的目录");
        String next = scanner.nextLine();
        File file=new File(next);
        if(!file.isDirectory()){
            System.out.println("你输入的不是目录,请重新输入");
        }
        System.out.println("请输入你要查询的关键字");
        String key=scanner.next();
        scan(file,key);
    }

    private static void scan(File file, String key) {
        File[] files=file.listFiles();
        if(files==null){
            System.out.println("你输入的目录为空");
            return;
        }
        for (File file1:files){
            if (file1.isFile()){
                //是普通文件
                scanContent(file1,key);
            }else {
                //是目录
                scan(file1,key);
            }
        }
        
    }

    private static void scanContent(File file1, String key) {
        if (file1.getName().contains(key)){
            System.out.println("该文件名中有关键字"+file1.getAbsolutePath());
            return ;
        }else {
            StringBuffer stringBuffer=new StringBuffer();
            try(Reader reader=new FileReader(file1)) {
                while (true){
                    char[] chars=new char[1024];
                    int read = reader.read(chars);
                    if(read==-1){
                        break;
                    }
                    stringBuffer.append(chars,0,read);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            if(stringBuffer.indexOf(key)>=0){
                System.out.println("该文件内容中有关键字"+file1.getAbsolutePath());

            }
            return ;
        }

    }
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值