【Java文件操作】手把手教你拿捏IO 流

哈喽,大家好~我是保护小周ღ,本期为大家带来的是 Java 文件操作,理解文件的概念以及,常用的操作文件的类和方法, FileInputStream 类 FileOutputStream  , PrintWriter  and Scnner,  Reader and Wirter 确定不来看看嘛~
更多精彩敬请期待:保护小周ღ *★,°*:.☆( ̄▽ ̄)/$:*.°★* ‘


一、文件的基本概念

1.1 为什么使用文件

在我们程序中输入的数据一般会随着 main() (主线程)—— 进程的结束而清空,这是因为此时的数据是存放在内存中的,程序结束,内存回收,等我们下次再次运行程序的时候又需要重新输入数据,如果我们想要将数据持续化存储,就必须依托于第三方介质,依托于硬盘,依托于数据库等等Windows中对硬盘中信息的管理和使用是以文件为单位的,Windows系统中推行万物皆文件的模式,这样对整体数据的存储、管理就有了一个统一的规范,降低了管理的复杂度。


1.2 什么是文件

文件可以认为是操作系统使用、管理数据的基本单位,是硬盘存储和管理数据的基本单位,我们想要某些相关联的数据作为一个独立的整体的进行保存,这个独立的整体就可以认为是一个文件。

百度百科:

文件后缀名也叫文件的扩展名,是用来表示某种文件所采用的机制。文件扩展名是加在主文件名后面的,用“.”分隔。不同的软件要求不同的文件格式,后缀名可以帮助用户了解文件是应该使用哪种软件打开文件。

在程序设计中从文件功能的角度分析有两种文件:程序文件,数据文件。

程序文件:包括我们编写的目标源文件(. java, . C), 目标文件 (windows环境后缀为 .obj), 可执行文件(windows环境后缀为 . exe)。我们的 . java 文件经过编译后得到一个 .class 文件,由Java JVM 解析文件。

数据文件:文件的内容不一定是程序,还可以是程序运行中读写的数据,例如程序运行时需要从内存(CPU 只能直接对内存的数据进行处理,所以要处理的数据会先从第三方介质:硬盘等读取到内存)中读取数据进行处理,将处理后的数据又写回第三方介质,那么这个过程中读取和写入数据的源头就可以称之为数据文件。

根据数据的类型可以将文件划分为 文本文件 和 二进制文件

文本文件:是指以ASCII字符集方式(也称文本方式)存储的文件,依托于某种字符集来识别,C语言中使用的是ASCll 编码,所以一个 char 类型只占 一个字节, 例如: 大写字符 A  的ASCll 编码 0110 0001  (65),Java 中使用的是 Unicode 字符集 一个char 类型两个字节,可以用来描述更多的字符,也包括中文,Unicode 字符集兼容 Utf -8 字符集,utf- 8 兼容 ASCll 字符集  但是 utf- 8 使用三个字节描述中文。

二进制文件(binary):二进制文件是按机器(即电脑)能够阅读的格式(只有0和1)进行存储的文件,所有文件都是以二进制的形式存储,文本文件不同是,它可以使用字符集来解析二进制,二进制文件反正操作系统能解析,正常人都是看不懂的,如果使用某种字符集解析(utf-8)大概率也是无法成功的,编码的规则不同,自然就无法显示,即使显示了字符,也是偶然适配了字符,是没有意义的。

以下是一个二进制文件使用 utf-8 字符集解析的信息,没有意义,但是系统可是识别出信息。

【Java文件操作】手把手教你拿捏IO 流_第1张图片

 小正方块就是无法被字符集识别统一显示的信息。


1.3 文件的组织

伴随着文件越来越多,就需要一种管理文件的机制,在 Windows 系统中采用树型结构来组织管理文件夹。文件除了有数据内容之外,还有文件本身的一个信息,例如:文件名、文件类型、文件大小,文件路径、文件源地址,我们把这一块这信息称之文件的 “元信息”。

【Java文件操作】手把手教你拿捏IO 流_第2张图片

每一个文件夹对应硬盘上一块存储空间,它提供了指向对应空间的地址——子文件,可以把文件夹看作是一颗树的 Node 节点,节点中可以保存另一个节点或者是文本文件,二进制文件等等(实际上存储的是文件的元信息)。

文件夹是计算机术语也称之为 “目录” 是用来组织和管理磁盘文件的一种数据结构。

1.4 文件路径(Path)

熟悉电脑的朋友应该,Windows 不允许在同一文件下有相同类型并同名的文件。

文件命名规则:

(1)文件名最长可以使用255个字符。

(2)可以使用扩展名,扩展名用来表示文件类型,也可以使用多间隔符的扩展名。如 txt.jpg.exe是一个合法的文件名,但其文件类型由最后一个扩展名决定。

(3)文件名中允许使用空格,但不允许使用下列字符(英文输入法状态):< > / \ | : " * ?

(4)windows系统对文件名中字母的大小写在显示时有不同,但在使用时不区分大小写。

如何在文件管理系统中定位我们的唯一的文件?Windows 中不同文件夹中允许已使用的文件名,如果我们需要对文件精确定位,就需要使用文件路径了。

所谓文件路径就是从树形结构的角度来看,从根节点开始,逐渐向子节点延申,直到找到目标文件,那么找到该文件的所经过的节点,就称之为文件路径,从根节点开始扫描这种描述方式也被称之为文件的 “绝对路径”。

举个例子:D:\JAVA\JDK\bin\jave.exe 这是一个绝对路径

【Java文件操作】手把手教你拿捏IO 流_第3张图片


除了使用绝对路径定位文件,还有一种相对路径的方式,相对表示根据当前文件为根节点直至目标文件的路径,相对路径的表示方式也是我们常用的,缺点是文件路径不过精确,有时候会识别不到文件。

" . " 符号在相对路径中是一个特殊符号,表示当前目录

" .. " 符号也是特殊符号,表示当前目录中的上级目录

在相对路径的情况下要描述当前目录的上上级目录,或者级别更高的目录时,可以使用 “..\ ..\ ..\ ” 的形式,每一个 " ../ " 表示上一个目录。

在绝对路径中可以理解为以 “此电脑” 为根目录。

这一切的大前提都是建立在 Windows 操作系统的情况下,在其他操作系统的环境中可能会有所差异。


二、Java 中的文件操作

Java 中通过 java. io 包中的 File 类来对一个文件(包括目录)进行抽象的描述,File 对象是硬盘上的一个文件的“抽象”表示,为什么这么说呢,文件是存储来硬盘上的(第三方介质)的,直接通过代码操作硬盘,怕是不太友好,于是就在内存中创建一个文件对应的对象,然后我们通过操作内存中的对象,就可以间接的操作硬盘中的文件了。


2.1 File 类解析

我们从 File 类中常见的属性、构造方法和方法及其使用这几个方面来讲述。

2.1.1 构造方法

【Java文件操作】手把手教你拿捏IO 流_第4张图片


  2.1.2 方法

【Java文件操作】手把手教你拿捏IO 流_第5张图片


2.2 常用方法演示

2.2.1 文件属性 

// 文件的属性
    public static void main(String[] args) throws IOException {
        File file = new File("hello_world.txt"); // 使用相对路径
        //file.createNewFile();
        System.out.println(file.exists()); // 判断文件是否存在
        System.out.println(file.isDirectory()); // 判断file 对象是否是一个目录
        System.out.println(file.isFile()); // 判断对象是否是一个普通文件
        System.out.println(file.createNewFile()); // 根据file 对象自动创建一个空文件,成功创建后返回 true
        System.out.println(file.exists()); // 判断文件是否存在

        System.out.println(file.isDirectory());
        System.out.println(file.isFile());
        System.out.println(file.createNewFile()); // 文件如果存在返回 false
    }

【Java文件操作】手把手教你拿捏IO 流_第6张图片


 2.2.2 文件路径显示

public static void main(String[] args) throws IOException {
        File file = new File("..\\hello-world.txt"); // 代码中要使用 \ 要使用转意字符
        System.out.println(file.getParent()); // 返回对象的父目录文件路径
        System.out.println(file.getName()); //返回对象的纯文本名称
        System.out.println(file.getPath()); // 返回对象的文件路径
        System.out.println(file.getAbsolutePath()); // 返回对象的绝对路径
        System.out.println(file.getCanonicalFile()); // 返回对象的修饰过的绝对路径
    }

【Java文件操作】手把手教你拿捏IO 流_第7张图片


2.2.3  文件的删除

public static void main(String[] args) throws IOException {
        File file = new File("some-file.txt");
        System.out.println(file.exists()); // 判断文件是否存在
        System.out.println(file.createNewFile()); // 根据file 对象自动创建一个空文件,成功创建后返回 true
        System.out.println(file.exists()); // 判断文件是否存在
        System.out.println(file.delete()); // 删除这个文件,删除成功返回 true
        System.out.println(file.exists());
        file.deleteOnExit();// 标注这个文件将被删除,删除动作会到 JVM 运行结束时才会进行
    }

【Java文件操作】手把手教你拿捏IO 流_第8张图片


2.2.4  创建目录 

public static void main(String[] args) {
        File dir = new File("some-dir");
        System.out.println(dir.isDirectory()); // 判断对象是否是一个目录
        System.out.println(dir.isFile());// 判断对象是一个普通的文件
        System.out.println(dir.mkdir());// 创建file 对象的目录
        System.out.println(dir.isDirectory());
        System.out.println(dir.isFile());
        dir.mkdirs();// 可以创建中间目录, mkdir 只能创建单极目录
    }

【Java文件操作】手把手教你拿捏IO 流_第9张图片


 2.2.5  文件的重命名

【Java文件操作】手把手教你拿捏IO 流_第10张图片

运行结果博主已经验证,helloWorld,被创建博主手动向文件中添加了数据,最后再运行一次,renameTo() 方法,helloWorld 就替换掉成 helloWorld2 其中的数据没有丢失,重命名成功!!


 三、Java 操作文件内容

第三个模块涉及的是文件内容的读写操作,学习向指定文件中写入数据,从指定文件中读取数据。

Java 标准库提供了一组类专门用于对文件进行读写操作。

针对文本文件,提供了一组类,面向 “字符流” 操作,经典代表: Reader, Writer ,读写的基本单位是字符。

针对二进制文件,提供了一组类,面向 “字节流” 操作,经典代表: InputStream, OutputStream . 读写的基本单位是字节。

 3.1 文件缓冲区

先给大家补充一下 文件怎样写入信息或读出信息,当给文件写入数据时,最先应该在输出缓冲区,等缓冲区满了再输出到磁盘保存,当从文件里读取信息时,数据应先到达输入缓冲区,然后再给到程序对应的数据类型变量等。


 3.2 InputStream 抽象类

InputStream 提供的抽象方法

【Java文件操作】手把手教你拿捏IO 流_第11张图片

InputStream 只是一个抽象类,关于 InputStream 的实现类有很多,基本上可以认为不同的输入设备都对应有一个 InputStream类的实现类,这里我们从文件中读取数据,可以使用 FileInputStream 类。

FileInputStream 构造方法

【Java文件操作】手把手教你拿捏IO 流_第12张图片


使用:先准备一个 hello.txt 文件,向文件内部填充一些内容:

// InputStream 字节文件读取
    public static void main(String[] args) throws IOException {
       try(InputStream file = new FileInputStream("hello.txt")) {
           byte[] buf = new byte[1024]; // 数组长度自定义,不可扩容
           while (true) {
               int data = file.read(buf);
               if(data == -1) { // 表示文件已经全部读完
                   break;
               }
               //1. 每次读取 3 字节进行 utf-8 解码,得到中文字符,utf-8 字符集一个汉字三个字节
               //2. 利用 String 的构造方法完成
               //3. data统计的是字节数
               for (int i = 0; i < data; i += 3) {
                   String str = new String(buf, i, 3, "utf-8");
                   System.out.printf("%s", str);// java 保留了C语言的打印机制
               }
           }
       }
    }

【Java文件操作】手把手教你拿捏IO 流_第13张图片

字节流读取数据,我们想读到汉字的话巧妙的利用了 String 类的构造方法,将指定区间内(3个字节)的数据按照 utf- 8 编码集转换成字符。


3.3 Scanner 进行字符读取

上文 InputStream 针对字符进行字节流读取很不方便,还要转换,所以我们可以使用 Scanner 类将字节流读取,包装成 “字符流”,自动的转换~~

【Java文件操作】手把手教你拿捏IO 流_第14张图片

 使用:先准备一个 hello.txt 文件,向文件内部填充一些内容:

// 利用 Scanner 进行字符读取
    public static void main(String[] args) throws IOException{
        try(InputStream data = new FileInputStream("hello.txt")) {
            try(Scanner in = new Scanner(data, "utf-8") ) {
                while (in.hasNext()) {
                    String str = in.next();
                    System.out.println(str);
                }

            }
        }
    }

 因为 str = in.next 遇到空格会换行,所以 world! 再第二行打印。


3.4 OutputStream 抽象类

InputStream 提供的抽象方法

【Java文件操作】手把手教你拿捏IO 流_第15张图片

OutputStream 也只是一个抽象类,关于 OutputStream 的实现类有很多,这里我们往文件中写入数据,可以使用 FileOutputStream 类,面向字节流。

【Java文件操作】手把手教你拿捏IO 流_第16张图片


 使用 write() 方法向文件中写入数据

【Java文件操作】手把手教你拿捏IO 流_第17张图片

 注意:博主的文件流资源会随着进程(main)的结束而结束,所以并没有手动的调用 close() 。


3.5 PrintWirter  进行字符写入

使用字节流 向文件中 “写” 数据总归是不方便的,所以可以使用 PrintWirter 将字节流数据包装成指定字符集的数据来完成输出。

PrintWriter 类中提供了我们熟悉的 print(),  println(), printf ()方法。

PrintWriter 类是基于 Reader 类实现的,关于 Reader 类稍后再讲。

 // PrintWriter 字符写数据
    public static void main(String[] args) throws IOException {
        try(OutputStream data = new FileOutputStream("output.txt")) {
            try(OutputStreamWriter os = new OutputStreamWriter(data, "utf-8")) {
                // 如果想要使得每次写入的数据不被覆盖可以向构造方法中添加 true
                try(PrintWriter writer = new PrintWriter(os,true)) {
                    writer.println("我是第一行");
                    writer.printf("%d:我是第二行 \n", 1 + 2);
                    writer.print("我是第三行");
                }
            }
        }
    }

【Java文件操作】手把手教你拿捏IO 流_第18张图片

 避免二次写入文件被覆盖:

PrintWriter writer = new PrintWriter(os,true)

这一组文件操作类,InputStream 和 OutputStream 面向字节流操作文件, read() 和 write() 也可以一次读写多个字节,使用 byte[] 数组来表示,read() 方法会尽可能的 byte[] 数组填满,如果读到文件末尾,返回 -1 , writer() 方法会把 byte[] 数组中所有的数据都写入文件。 


3.6  Reader 类字符读取

 // Reader 类 read 方法 以字符的形式读取
    public static void main(String[] args) {
        try(Reader reader = new FileReader("hello.txt")) {
            while (true) {
                int c = reader.read();
                if(c == -1) {
                    break;
                }
                char ch = (char)c;
                System.out.print(ch);
            }
            reader.close(); //释放资源
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

【Java文件操作】手把手教你拿捏IO 流_第19张图片

 3.7 Writer 类字符写入

 // Writer 类 writer 方法 以字符的形式写入
    public static void main(String[] args) {
        try(Writer writer = new FileWriter("output3.txt",true) ){ // true文件不覆盖写
            String str = "我的老哥";
            writer.write(str);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


以上一组 Reader 和 Writer 类,构造方法打开文件,写入时文件不存在会自动的创建一个文件。

read() 方法来读,一次读取一个 char 或者 char[]

write() 方法来写,一次写入一个 char 或者 char[] 或者 String

close()关闭资源


到这里,Java的文件操作 IO 流博主已经分享完了,希望对大家有所帮助,如有不妥之处欢迎批评指正。

本期收录于博主的专栏——JavaEE,适用于编程初学者,感兴趣的朋友们可以订阅,查看其它“JavaEE基础知识”。

感谢每一个观看本篇文章的朋友,更多精彩敬请期待:保护小周ღ *★,°*:.☆( ̄▽ ̄)/$:*.°★* 

遇见你,所有的星星都落在我的头上……

你可能感兴趣的:(JavaEE,java,文件操作,IO流)