Java-文件IO

文件IO

狭义的文件: 硬盘上的文件和目录

广义上的文件: 泛指计算机中很多的软硬件资源.OS中,把很多硬件设备和软件资源抽象为文件.按照文件的方式统一管理.网卡也是一个文件.

  • 每个文件在硬盘上都有具体的路径.绝对路径和相对路径.

    • 绝对路径: 以根目录开头的路径

    • 相对路径: 以当前所在目录(工作目录)为基准,以. .. 开头找到指定的路径

文件分类大致可分为两类: 文本文件和二进制文件

  1. 针对文件系统的操作: 删除,创建,重命名
  2. 针对文件内容的操作: 读写

File类

文件系统操作设置
package IOCode;
import java.io.File;
import java.io.IOException;

public class IODemo1 {
    public static void main(String[] args) throws IOException {
        //相对路径
        File file=new File("./test1.txt");
        System.out.println(file.getName());
        System.out.println(file.getParent());
        System.out.println(file.getPath());
        System.out.println(file.getAbsolutePath());
        System.out.println(file.getCanonicalPath());
        //test1.txt
        //.
        //.\test1.txt
        //D:\java_projects\javaeeCode\.\test1.txt
        //D:\java_projects\javaeeCode\test1.txt

        //绝对路径
        File file2=new File("d:/test2.txt");
        System.out.println(file2.getName());
        System.out.println(file2.getParent());
        System.out.println(file2.getPath());
        System.out.println(file2.getAbsolutePath());
        System.out.println(file2.getCanonicalPath());
        //test2.txt
        //d:\
        //d:\test2.txt
        //d:\test2.txt
        //D:\test2.txt
    }
}

package IOCode;

import java.io.File;
import java.io.IOException;

public class IODemo2 {
    public static void main(String[] args) throws IOException {
        File file=new File("d:/test3.txt");
        System.out.println(file.exists());
        System.out.println(file.isFile());
        System.out.println(file.isDirectory());

        //false
        //false
        //false


        File file2 =new File("./test4.txt");
        System.out.println(file2.exists());
        System.out.println(file2.isFile());
        System.out.println(file2.isDirectory());

        file2.createNewFile();

        System.out.println(file2.exists());
        System.out.println(file2.isFile());
        System.out.println(file2.isDirectory());
        //false
        //false
        //false

        //true
        //true
        //false
    }
}

package IOCode;
import java.io.File;

public class IODemo3 {
    public static void main(String[] args) {
        File file =new File("./test4.txt");
        file.delete();
        file.deleteOnExit();
        //在程序退出时才会删除.系统结束时的"临时文件"使用这个删除.
        // word文件打开时默认生成一个~临时文件.保存了当前实时编辑的内容还未保存的东西.
        //下次再次word启动时,提醒提前导入这个临时文件.
    }
}

package IOCode;

import java.io.File;
public class IODemo4 {
    //目录创建
    public static void main(String[] args) {
        //创建一级目录
        File dir = new File("./testDir1");
        dir.mkdir();
        //创建多级目录
        File dir2 =new File("./testDir2/aaa/bbb");
        dir2.mkdirs();
    }
}
package IOCode;
 import java.io.File;
public class IODemo5 {
    public static void main(String[] args) {
        File dir1=new File("./testDir1");
        File dir2 =new File("./test7");
        dir1.renameTo(dir2);
    }
}

流对象

文件内容修改

针对文件内容,是采用流对象进行操作的.

"流" 本身就是OS的API接口提供的,所以其他编程语言也继承下来.

  • 字节流 以字节为单位读写数据

InputStream OutputStream 操作二进制数据

  • 字符流 以字符为单位读写数据

Reader Writer 操作文本数据

以上四种都是抽象类,不能直接new出对象,所以需要对它进行继承和重写.

抽象 vs 具象 差别就在于给定信息的多和少.抽象的提供的信息是非常少的,但是具象信息量就比较丰富,比较具体.

抽象类:大部分都是确定的,只有一些是不确定的.

接口: 大部分都是不确定的,方法都是抽象方法.(不考虑之后提供的default)

  • 大致过程都是如下:
  1. 打开文件,构造对象
  2. 读文件(read) =>针对InputStream
  3. 写文件(write)=> 针对OutputStream
  4. 关闭文件(close)
字节流操作文件
字节流输入read
  • read一次就会走一次IO.
  • 缓冲区的存在就是为了减少IO的次数,一次读取多个字节放到缓冲区当中.此时可以提升整体的效率.
package IOCode;

import java.io.*;

public class IODemo6 {
    //读取多个字节放到缓冲区当中
    public static void main(String[] args) throws IOException{
        InputStream inputStream =new FileInputStream("./src/IOCode/test1.txt");
        while(true){
            byte[] buffer =new byte[1024];
            int len=inputStream.read(buffer);
            //将buffer交给read进行填写,这里是输入输出型参数,使用参数来返回内容
            if(len==-1){
                //代表读取完成
                break;
            }
            for(int i=0;i<len;i++){
                System.out.printf("%x\n",buffer[i]);
            }
        }
        inputStream.close();
        //e4
        //bd
        //a0
        //e5
        //a5
        //bd
    }
    
    //每次只读取一个字节
    public static void main1(String[] args) throws IOException {
        // 读取文件以字节流的方式读取
        InputStream inputStream= new FileInputStream("./src/IOCode/test1.txt");

        while(true){
            int b = inputStream.read();//read返回值是读取到的一个字节byte,因为要表示读写完毕的情况,所以用int 接收
            //无参数默认读一个字节
            //一个参数: 将读取的内容放到指定字节数组当中.返回值是读取的字节数
            //三个参数: 往数组的一部分区间当中写入
            if(b==-1){//返回值是int 类型,-1代表读取完成
                break;
            }
//            System.out.println(" "+ (byte)b);
            System.out.printf("%x \n",(byte)b);
        }

        inputStream.close();
        //test1.txt: hello 读取出来的就是对应字符的ASCII码值
        // 104
        // 101
        // 108
        // 108
        // 111
        //16进制打印得到结果如下:
        //68
        //65
        //6c
        //6c
        //6f
        //d
        //a
        //e4
        //bd
        //a0
        //e5
        //a5
        //bd
    }
}
字节流输出write
package IOCode;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class IODemo7 {
    //保证close操作一定被执行的方式二(推荐)
    public static void main(String[] args)throws IOException {
        try(OutputStream outputStream=new FileOutputStream("./src/IOCode/test1.txt")){
            outputStream.write(99);
            outputStream.write(100);
            outputStream.write(101);
        }
        //虽然没有显示的调用close,但是在try语句块执行完毕之后,还是会执行close的.
        //这个语法Java中叫做try with resources
        //只有实现了Closeable接口的类,才能够放到try的()中自动关闭.
    }
    //保证close操作一定被执行的方式一
    public static void main2(String[] args) throws IOException{
        OutputStream outputStream=null;
        try{
            outputStream =new FileOutputStream("./src/IOCode/test1.txt");
            outputStream.write(99);
            outputStream.write(100);
            outputStream.write(101);
        }finally {
            outputStream.close();
        }
    }
    public static void main1 (String[] args) throws IOException {
        //默认打开文件的时候将原本的内容删除
        OutputStream outputStream = new FileOutputStream("./src/IOCode/test1.txt");
        outputStream.write(99);
        outputStream.write(100);
        outputStream.write(101);
        outputStream.close();
        //关闭文件,文件描述符表(数组)记录了进程打开了哪些文件,将表中元素释放掉
        //如果不释放,表中元素会一直存在,可能会一瞬间将表打满,如果满了后续就无法再申请打开文件
        //文件描述符表上限也就几百个到几千个
        //close并不是必须要执行的,因为进程结束时OS会回收为进程安排的空间,比如PCB以及文件描述符表
        //此时表数组被删除了,里面你未曾close的文件对象也会被释放.
        //
    }
}
字符流
字符流读取
package IOCode;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.*;
public class IODemo8 {
    //字符流读取
    public static void main(String[] args) throws IOException {
        try(Reader reader =new FileReader("./src/IOCode/test1.txt")){
            while(true){
                int ch= reader.read();//读取到的是一个字符,但是返回值设置为int 类型
                if(ch==-1){
                    break;
                }
                System.out.println(""+ (char)ch);
            }
        }catch(IOException e){
            e.printStackTrace();
        }
        //你
        //好
        //a
        //b
        //c
    }
}
字符流写入
package IOCode;

import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class IODemo9 {
    public static void main(String[] args) throws IOException {
        try(Writer writer =new FileWriter("./src/IOCode/test1.txt")){
            writer.write("a");
            writer.write("b");
            writer.write("abcd");
            
            writer.flush();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

  • 写文件内容并没有真的在文件中出现,很可能就是因为缓冲区的存在

write操作,其实是先写到缓冲区当中.OS内核也可能有缓冲区,标准库也有缓冲区.

写操作执行完成,内容可能就在缓冲区中,没有真正写入硬盘.

close操作,就会触发缓冲区的刷新(冲刷)flush.

  • 针对Scanner
package IOCode;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;

public class IODemo10 {
    public static void main(String[] args) {
        try(InputStream inputStream =new FileInputStream("./src/IOCode/test1.txt")){
            
            Scanner scanner=new Scanner(inputStream);//传给Scanner的就是文件字节输入流对象
            scanner.next();
            //此时的读取就是从 文件 中进行读取了
            
        }catch (IOException e){
            e.printStackTrace();
        }
    }
    public static void main1(String[] args) {
        Scanner scanner=new Scanner(System.in);
        //    public final static InputStream in = null;
        //说明这个in也是一个输入流,是一个字符输入流对象
    }
}

此时内部的inputStream对象已经被try()关闭了,里面的Scanner不关闭也没关系.

实例练习
文件操作实例1
  1. 扫描指定目录,并找到名称中包含指定字符的普通文件(不包含目录)
  2. 用户输入要查询的词,看看当前目录下是否存在
  3. 查找成功之后,由用户决定是否删除这个文件
package IOCode;

import java.sql.SQLOutput;
import java.util.Scanner;
import java.io.File;
public class IODemo11 {

    private static Scanner scanner=new Scanner(System.in);

    public static void main(String[] args) {
        //1. 让用户输入指定搜索的目录
//        Scanner scanner =new Scanner(System.in);
        System.out.println("请输入指定搜索的目录# ");
        String basePath= scanner.next();
        File root= new File(basePath);
        //2. 针对用户输入进行判定
        if(!root.isDirectory()){
            System.out.println("输入的目录名称有误~");
            return;
        }
        //3. 用户输入想要删除的文件名
        System.out.println("请输入想要删除的文件名# ");
        String nameToDelete=scanner.next();
        //针对指定目录进行扫描,递归操作
        //从根目录出发,查看是否包含需要删除的文件,是就删除,不是就下一个
        //如果遇到目录,再针对这个子目录进行查找删除操作
        scanDir(root,nameToDelete);
    }

    private static void scanDir(File root, String nameToDelete) {
        //1. 先列出当前目录下的文件
        File[] files=root.listFiles();//将目录下的文件放到数组中,相当于双击一个目录,显示结果
        if(files==null){
            return ;
        }
        //2. 遍历当前列出的结果
        for (int i = 0; i < files.length; i++) {
            if(files[i].isDirectory()){//当前是目录,递归走处理子目录
                scanDir(files[i],nameToDelete);
            }else{//当前是文件
                if(files[i].getName().contains(nameToDelete)){
                    System.out.println("要删除 "+files[i].getAbsolutePath()+"这个文件吗? Y or N");
                    String choice = scanner.next();
//                    if(choice == "Y"){//这种比较java只是比较引用
                    if(choice.equals("Y")) {//这才是String对象的比较方式
                        files[i].delete();
                        System.out.println("删除成功~");
                    }else {
                        System.out.println("删除取消~");
                    }
                }
            }

        }
    }
}
文件操作实例2

进行普通文件的复制.读取一个文件,将文件中内容写入到另一个文件当中.

  • 以字节流方式拷贝,不管是什么类型的文件都是字节构成的,拷贝之后肯定是一样的.
package IOCode;

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

public class IODemo12 {
    public static void main(String[] args) throws IOException {
        //输入源文件目录和目标文件目录
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入要拷贝哪个文件#");
        String srcPath = scanner.next();
        System.out.println("请输入要被复制到哪个目标去#");
        String destPath=scanner.next();
        File srcFile=new File(srcPath);
        if(!srcFile.isFile()){
            //源文件不存在/给定的是一个目录
            System.out.println("源文件输入有误~");
            return ;
        }
        File destFile= new File(destPath);
        if(destFile.isFile()){
            //如果复制目标文件已经存在,认为也不能拷贝
            System.out.println("目标路径有误~");
            return;
        }
        //支持包含多个流对象
        try(InputStream inputStream =new FileInputStream(srcFile);
            OutputStream outputStream =new FileOutputStream(destFile)){

            while(true){
                int b=inputStream.read();
                if(b==-1){
                    break;
                }
                outputStream.write(b);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}
  • OutputStream查找到没有文件,会创建一个新的文件
  • InputStream没有查找到指定文件名的文件,会报错,不会创建.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值