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

文件的初识

广义文件和狭义文件

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

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

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

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

文件路径

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

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

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

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

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

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

文件内容

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

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

操作文件

文件系统操作:

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

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

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

属性:

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

构造方法:

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

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

(parent是一个File对象)

File(String pathname)

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

File(String parent,String child)根据父目录+孩子文件路径,创建一个新的File实例,父目录用路径表示

方法:

修饰符及返回值类型方法签名说明
StringgetParent()返回File对象的父目录文件路径
StringgetName()返回File对象的纯文件名称
StringgetPath()返回File对象的文件路径
StringgetAbsolutePath()返回File对象的绝对路径
StringgetCanonicalPath()返回File对象的修饰过的绝对路径
booleanexists()判断File对象代表的文件是否存在
booleanisDirectory()判断File对象代表的文件是否是一个目录
booleanisFile()判断File对象代表的文件是否是一个普通文件
booleancreateNewFile()根据File对象的路径,创建一个空文件。成功返回true
booleandelete()根据File对象路径,删除该文件,成功删除后返回true
voiddeleteOnExit()根据File对象,标准文件将在JVM运行结束后删除(进程结束后删除)
String[]list()返回File对象代表的目录下的所有文件名(以字符串形式存储)
File[]listFiles()返回File对象代表的目录下的所有文件,以File对象表示
booleanmkdir()创建File对象代表的目录
booleanmkdirs()创建File对象代表的目录,会创建中间目录(如果是多级目录)
booleanrenameTo(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概述:

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

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概述:

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

将b这个字符数组中从

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

voidclose()关闭字节流
voidflush()背景:文件的读写操作是很慢的,因此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方法的小总结,如有错误还望诸位谅解,也期望大家指出在下的不足。

更多推荐