在开始本文内容的介绍之前,相信大家都知道,一般情况我们电脑上的数据(长期保存的那种)都是存储在硬件设施--硬盘上的。硬盘上存储的数据又被抽象地叫做“文件”。这里的文件与我们后文操作修改的可以近似等价

文件的初识

广义文件和狭义文件

可能有人会问,“文件不应该是在文件夹里的吗?怎么又在硬盘里面去了”,这就会涉及到“狭义的文件”和“广义的文件”。

  • 狭义的文件:我们文件夹中保存的,一个个独立的存储数据的容器,叫做“狭义的文件”(文件名称,文件类型各不相同)
  • 广义的文件:存储在硬盘上的数据,抽象成文件

其中广义的文件又包含两大类:

  • 文件夹:别称“目录”,用于存放许多普通文件(类似于“多叉树”的数据结构,文件夹就相当于是一个“根”,对于不同树,就有不同文件夹和“根结点”
  • 普通文件:就是存储数据的“容器”,可以存储不同类型的数据,也有不同的格式

文件路径

那么电脑中那么多文件(普通文件和文件夹),我们该如何才能找到需要的那个文件呢?正常找,猴年马月都找不完,于是我们使用--文件路径来作为寻找文件的线索

在我们先前说到的,操作系统管理文件,是采取“多叉树目录”的结构,因此,我们做有如下规定:

1.文件的管理是一棵树,树中结点可以是“普通文件”和“文件夹”

2.我们通常将“文件夹”视为某棵树的“根结点”

那么在如此规定下,从最头部的根节点连接到“文件”(硬盘上的概念)的路径,就是“文件路径”。

文件路径又分为:“绝对路径”和“相对路径”。

文件内容

文件也可以通过文件中存储的内容的类型作为分类的标准:

  • 二进制文件:像点开乱七八糟的,就是二进制文件。这是交由机器来读取的内容
  • 文本文件:像这种里面存储的是文本信息,我们人眼能看懂的正常内容,就是文本文件

操作文件

文件系统操作:

接下来在这部分,我们要介绍的方法都是对文件的创建,移动,复制等直接操作文件的操作,不会涉及到文件内容的读写操作。

File类的构造方法与常见方法:

我们使用创建File类对象(用一个文件路径),来抽象表示一个普通文件/目录,但需要注意的是“file对象存在,不代表对应的文件也存在”。我们就来介绍一下这个能把文件抽象化的类,到底怎么使用。

属性:

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

构造方法:

签名 说明
File(File parent,String child)

根据父目录+孩子文件路径,创建一个新的File实例

(parent是一个File对象)

File(String pathname)

根据文件路径创建一个新的File实例,路径可以是绝对路径或者相对路径

File(String parent,String child) 根据父目录+孩子文件路径,创建一个新的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对象路径,删除该文件,成功删除后返回true
void deleteOnExit() 根据File对象,标准文件将在JVM运行结束后删除(进程结束后删除)
String[] list() 返回File对象代表的目录下的所有文件名(以字符串形式存储)
File[] listFiles() 返回File对象代表的目录下的所有文件,以File对象表示
boolean mkdir() 创建File对象代表的目录
boolean mkdirs() 创建File对象代表的目录,会创建中间目录(如果是多级目录)
boolean renameTo(File dest) 进行文件改名,也可以视作剪切,粘贴操作

方法的使用示例:

关于文件路径相关的方法:

public class demo1 {
    public static void main(String[] args) throws IOException {
        //这部分内容,主要是对文件路径进行操作
        //操作管理文件,不涉及改写文件的内容
        //创建文件File对象
        //根据一个绝对路径/相对路径创建一个File实例,可以真正创建一个文件
        File file=new File("d:/Java.IO/thetest.txt");
        //对文件的路径的操作
        System.out.println("file对象的文件的父目录路径是"+file.getParent());
        System.out.println("file对象的文件的纯文件名称是"+file.getName());
        System.out.println("file对象的文件的文件路径是"+file.getPath());
        System.out.println("file对象的文件的文件绝对路径是"+file.getAbsolutePath());
        System.out.println("file对象的文件的修饰过的绝对路径是"+file.getCanonicalPath());

    }
}

关于判断文件类型和存在的方法:

public class demo2 {
    public static void main(String[] args) {
        //判断file对象对应的文件的属性(存在/类型)
        File file=new File("d:/Java.IO/test.txt");
        System.out.println("file对象对应的文件是否存在:"+file.exists());
        System.out.println("file对象代表的文件是否是一个目录(文件夹)"+file.isDirectory());
        System.out.println("file对象代表的文件是否是一个普通文件"+file.isFile());

    }
}

关于创建指定位置的文件/目录的方法:

public class demo3 {
    public static void main(String[] args) throws IOException {
        File file=new File("d:/Java.IO/one.txt");
        //根据file对象(传入的绝对路径)自动创建一个空文件
        System.out.println("指定文本文件是否创建成功:"+file.createNewFile());
        //根据file对象(传入的绝对路径)删除该文件
        //System.out.println("指定文本文件是否删除成功:"+file.delete());
        //根据file对象(传入的绝对路径)在该进程结束后删除这个文件
        //file.deleteOnExit();
    }
}

关于取出指定目录下的所有文件相关的方法:

public class demo4 {
    public static void main(String[] args) {
        File file=new File("d:/Java.IO");
        //返回file对象目录下所有文件名,注意返回的是String类型的文件名字
//        String[] s=file.list();
//        if(s==null){
//            System.out.println("该目录是空的");
//        }
//        //通过for each的遍历打印方式(前:打印的数据类型,后:数组的名字)
//        for (String a:s){
//            System.out.println(s);
//        }
        //同样返回目录下所有文件名字,但是接受数组是File[]
        File[] s= file.listFiles();
        if(s==null){
            System.out.println("该目录是空的");
        }
        for (File a:s){
            System.out.println(a.getName());
        }
    }
}

关于创建目录以及重命名文件(移动文件)的方法:

public class demo5 {
    public static void main(String[] args) {
        File file=new File("d:/Java.IO/aaa");
        //创建file对象代表的目录
        System.out.println("指定的单层目录是否创建成功:"+file.mkdir());
        //创建多个目录(可能给定的路径中的目录不是都存在,就需要我们一起都创建了)
        File file1=new File("d:/Java.IO/bbb/ccc");
        System.out.println("指定的多层目录是否创建成功:"+file1.mkdirs());
        //对文件进行改名(本质就是移动文件)->变成目标名字(对你的路径中名字进行修改,其实也可以更改路径实现粘贴(移动文件)到其他目录中)
        File file2=new File("d:/Java.IO/test.txt");
        //test文本文件要更改成的目标名字
        File file2des=new File("d:/Java.IO/the test.txt");
        System.out.println("指定的文件是否成功重命名成功:"+file2.renameTo(file2des));
        File file3=new File("d:/Java.IO/one.txt");
        //one文件要移动去的新地址
        File file3des=new File("d:/Java.IO/aaa/one.txt");
        System.out.println("指定的文件是否成功移动到了指定的目录下:"+file3.renameTo(file3des));
    }
}

因为我们先前已经实验操作过了,因此,这里显示的结果是false

注:这里的移动文件是因为本方法的本质是:“改写文件路径名”,从而可以实现移动

文件内容操作:

文件内容操作:对文件内容进行读和写操作

对文件内容的操作,我们都是使用“流对象”,Java标准库中给我们提供了一系列“流”的类

其中根据不同的读和写的单位,分为“字节流”和“字符流”

1.字节流:在读写过程中,以字节为单位,针对“二进制文件”

  • InputStream:输入,在读取文件内容时使用
  • OutputStream:输出,在写入文件内容时使用

2.字符流:在读写过程中,以字符为单位,针对“文本文件”

  • Read:输入,从文件读取内容
  • Write:输出,对文件写入内容

字节流:

对于InputStream和OutputStream,它们两个是抽象类,我们想要具体实现操作要使用它们的继承类--FileInputStream和FileOutputStream才能真正进行文件内容操作。

InputStream概述:

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

FileInputStream概述

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

利用文件路径构造文件输入流

注意!!!因为我们FileInputStream是继承的子类,因此可以直接使用父类的方法

代码示例:

public class demo6 {
    //从现在开始进入对文件内容读写(对文件内容修改)的部分
    public static void main(String[] args) throws IOException {
        File file=new File("d:/Java.IO/the test.txt");
        //此处是字节流的读写操作(操作的单位是一个字节)
        //读操作
        //InputStream inputStream=new FileInputStream(file);
        //读取一个字节的数据,返回-1即读完
        //本质是:每次都会返回一个数字(一般是按照ASCLL码对应的数字(每个对应一个符号),当读完时,则返回-1)
//        while (true){
//            int n=inputStream.read();
//            if(n==-1){
//                break;
//            }
//            System.out.printf("此时读到的时"+"%x\n",n);
//        }
        //输出型函数的读取,本质是传入一个数组,然后把读取结果全部放在这个数组里面返回,函数的返回值只是“结束”的标志
        byte[] a=new byte[100];
//        while (true) {
//            int n = inputStream.read(a);
//            if(n==-1){
//                //第二次读,会发现文件已经读完,会返回-1
//                break;
//            }
//            //由于第一次读完会直接返回读到的数量,因此n此时是读取到的有效的个数
//            for (int i=0;i<n;i++){
//                System.out.printf("%x\n",a[i]);
//            }
//        }
        //如果遇到文本文件中是中文字符的情况,使用scanner来读取获得最好
//            int n=inputStream.read(a);
//            if(n==-1){
//                break;
//            }
            try(InputStream inputStream=new FileInputStream(file)) {
                try (Scanner scanner = new Scanner(inputStream, "UTF-8")) {
                    while (scanner.hasNext()) {
                        String s = scanner.next();
                        System.out.print(s);
                    }
                } finally {
                    if (inputStream != null) {
                        inputStream.close();
                    }
                }
        }
    }
}

注:如果我们遇到了文件中是中文的情况,可以使用Scanner来处理更方便!!!

OutputStream概述:

修饰符及返回值类型 方法签名 说明
void write(int b) 写入要给字节的数据
void write(byte[] b) 将b这个字符数组中数据全部写入os中
int write(byte[] b,int off,int len)

将b这个字符数组中从

off开始的数据写入os中,一共写len个

void close() 关闭字节流
void flush() 背景:文件的读写操作是很慢的,因此OutputStream为了减少设备操作的次数,写入数据会写入缓存区,等到缓存区满了之后才会真正写入设备中。但可能会造成我们上一部分的数据遗留到下一部分,这就需要我们手动刷新发送过去

FileOutputStream概述:

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

代码示例:

public static void main(String[] args) throws IOException {
        //每次写都是把文件里的内容清空重写
        File file=new File("d:/Java.IO/aaa/one.txt");
//        try (OutputStream outputStream=new FileOutputStream(file);) {
//            //写入一个字节一次
//            for (int i = 65; i < 70; i++) {
//                outputStream.write(i);
//            }
//        }
        //使用写入整个字节数组中的数据
//        byte[] a={97,98,99,100,101};
//        try(OutputStream outputStream=new FileOutputStream(file)) {
//            outputStream.write(a);
//            outputStream.flush();
//        }
        //写入一个字符串
//        String s="hello world";
//        byte[] a=s.getBytes();
//        try (OutputStream outputStream=new FileOutputStream(file)){
//            outputStream.write(a);
//            outputStream.flush();
//        }
        //写入一个中文字符串
        String s="你好,牢大";
        byte[] a=s.getBytes("UTF-8");
        try (OutputStream outputStream=new FileOutputStream(file)){
            outputStream.write(a);
            outputStream.flush();
        }
        //可以指定,我们的内容是追加写入,不会清空文件内容
        s="see you again";
        a=s.getBytes();
        try (OutputStream outputStream=new FileOutputStream(file,true)){
            outputStream.write(a);
            outputStream.flush();
        }
    }

注:1.每次写入文件内容,记得调用flush方法刷新文件写入的数据缓存区,否则会造成写入的信息不完全

2.如果要写入中文字串,需要我们把写入的“中文字符串”转成字节数组,并且规定“UTF-8”的字符集

3.可以在创建OutputStream对象中规定true(规定内容是追加写入的,不会情况文件内容)

写入的优化操作:

对于写入文件,我们还可以使用另一个类(使用输出流来创建对象)来写入--PrintStream。这个类来进行写入其实更加方便。优势是:可以连贯写入内容(不会清空文件),还能指定单行写入(换行)

代码示例:

File file=new File("d:/Java.IO/the.txt");
        file.createNewFile();
        //按照字节进行写操作
        try (OutputStream outputStream=new FileOutputStream(file,true);
             PrintStream printStream=new PrintStream(outputStream
             )){
            printStream.print("再见了,所有的man");
            printStream.print("see you again");
            printStream.flush();
        }catch (IOException e){
            e.printStackTrace();
        }

字符流:

同样对于Reader和Writer类也是抽象类,我们要使用的话也是使用继承它的子类FileReader和FileWriter。字符流一般适用于文本文件的书写。

Reader概述:

同样,我们重点关注读取内容的方法,至于这些方法使用时的注意事项与InputStream类似,这里就不再赘述。

Writer概述:

写入的优化操作:

类似于OutStream,我们Writer也有一个更好的优化操作:PrintWriter

File file=new File("d:/Java.IO/ret.txt");
        file.createNewFile();
        //按字符进行写操作
        try (OutputStream outputStream=new FileOutputStream(file,true)){
            PrintWriter printWriter=new PrintWriter(outputStream);
            printWriter.print("Man,What can I say?");
            printWriter.print("manba out!!");
            printWriter.print("牢大想你了!!!");
            printWriter.flush();
        }catch (IOException E){
            E.printStackTrace();
        }

代码示例:

public class demo13 {
    //字符流的书写
    public static void main(String[] args) throws IOException {
        File file=new File("d:/Java.IO/main.txt");
        try(Reader reader = new FileReader(file);
            Writer writer = new FileWriter(file,true)) {
            while(true){
                //往文件写数据
                writer.write("你好呀!");
                char[] ch = new char[]{'哦','哦'};
                writer.write(ch);

                //读数据,一次最多读取4096个字符
                char[] chars=new char[4096];
                int a =  reader.read(chars);
                if(a==-1){
                    break;
                }
                for(int b=0;b<a;b++){
                    System.out.println(chars[b]);
                }
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
}

总结的书写模板

按照字节进行读写:

代码案例:

public class demo15 {
    public static void main(String[] args) throws IOException {
        //按照字节读取的模板
        File file=new File("d:/Java.IO/the.txt");
        file.createNewFile();
        //按照字节进行写操作
        try (OutputStream outputStream=new FileOutputStream(file,true);
             PrintStream printStream=new PrintStream(outputStream
             )){
            printStream.print("再见了,所有的man");
            printStream.print("see you again");
            printStream.flush();
        }catch (IOException e){
            e.printStackTrace();
        }
        //按照字节进行读操作
        try (InputStream inputStream=new FileInputStream(file)){
            byte[] a=new byte[1024];
            while (true){
                int n=inputStream.read(a);
                if(n==-1){
                    break;
                }
                for (int i=0;i<n;i++){
                    System.out.printf("%x\n",a[i]);
                }
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

按照字符进行读写:

代码示例:

public class demo14 {
    public static void main(String[] args) throws IOException {
        //这里是关于按照字符读写操作的规范模板
        File file=new File("d:/Java.IO/ret.txt");
        file.createNewFile();
        //按字符进行写操作
        try (OutputStream outputStream=new FileOutputStream(file,true)){
            PrintWriter printWriter=new PrintWriter(outputStream);
            printWriter.print("Man,What can I say?");
            printWriter.print("manba out!!");
            printWriter.print("牢大想你了!!!");
            printWriter.flush();
        }catch (IOException E){
            E.printStackTrace();
        }
        //按字符进行读操作,可以处理中文的情况
        try (InputStream inputStream=new FileInputStream(file);
             Scanner scanner=new Scanner(inputStream,"UTF-8")){
            while (scanner.hasNext()){
                String s=scanner.next();
                System.out.println(s);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

本篇算是一个IO方法的小总结,如有错误还望诸位谅解,也期望大家指出在下的不足。

更多推荐