JAVA输入/输出流详细讲解

应用程序经常需要访问文件和目录,读取文件信息或写入信息到文件,即从外界输入数据或者向外界传输数据,这些数据可以保存在磁盘文件、内存或其他程序中。在Java中,对这些数据的操作是通过I/O技术来实现的。所谓I/O技术,就是数据的输入(Input)、输出(Output)技术。本章将对Java的 I/O系统进行讲解,包括I/O的体系结构、流的概念、字节流、处理字节流的基本类InputStream和OutputStream、字符流、处理字符流的基本类Reader和Writer、文件管理、序列化和反序列化等。

JAVA输入/输出流详细讲解_第1张图片

12.1 I/O流概述

Java将数据的输入/输出操作当作“流”来处理,“流”是一组从源头到目的地的有序的字节序列。在Java程序中,从某个数据源读取数据到程序的流称为输入流,通过程序使用数据流将数据写入到目的地的称为输出流。输入流和输出的读取和写入流程如图12.1所示。

JAVA输入/输出流详细讲解_第2张图片

 

(a)输入流 (b)输出流

图12.1 输入/输出流示意图

当程序需要从某个数据源读入数据的时候,就会开启一个输入流,数据源可以是文件、内存或网络等。相反,需要写出数据到某个数据源目的地的时候,也会开启一个输出流,这个数据源目的地也能够是文件、内存或网络等。I/O流有很多种,按操作数据单位不同可分为字节流和字符流,按数据流的方向不同分为输入流和输出流,如表12.1所示。

表12.1 流的分类

输入/输出

字节流

字符流

输入流

InputStream

Reader

输出流

OutputStream

Writer

    输入流和输出流的区别是以程序为中心来进行判断,从外部设备读取数据到程序是输入流,从程序写入数据到外部设备是输出流。字节流的单位是一个字节,即8bit;字符流的单位是两个字节,即16bit。表12.1是I/O流的简单分类,实际开发中需要使用的的I/O流共涉及40多个类,都是从这4个抽象基类派生的。接下来,我们先学习输入/输出流的体系结构。

Java.io包中的最重要的部分是由5个类和一个接口组成。5个类是指File、RandomAccessFile、InputStream、OutputStream、Writer、Reader,一个接口指的是Serializable。掌握了这些I/O的核心操作,那么对于Java中的I/O体系也就有了一个初步的认识了。总体上看,Java I/O主要包括如下3个部分:

• 流式部分:I/O的主体部分。

• 非流式部分:主要包含一些辅助流式部分的类,如File类、RandomAccessFile类和FileDescriptor类等。

• 其他类:主要是文件读取部分的与安全相关的类(如SerializablePermission类),以及与本地操作系统相关的文件系统的类,如(FileSystem类、Win32FileSystem类和WinNTFileSystem类)。

这里,将Java I/O中主要的类简单介绍如下:

• File类(文件特征与管理类):用于文件或者目录的描述信息等(An abstract representation of file and directory pathnames),如生成新目录、修改文件名、删除文件、判断文件所在路径等。

• InputStream类(二进制格式操作类):基于字节输入操作的抽象类,是所有输入流的父类,定义了所有输入流都具有的共同特征。

• OutputStream类(二进制格式操作类):基于字节输出操作的抽象类,是所有输出流的父类,定义了所有输出流都具有的共同特征。

• Reader类(文件格式操作类):抽象类,基于字符的输入操作。

• Writer类(文件格式操作类):抽象类,基于字符的输出操作。

• RandomAccessFile类(随机文件操作类):它的功能丰富,可以从文件的任意位置进行存取(输入输出)操作。

综上所述,Java中I/O流的体系结构如图12.2所示。

JAVA输入/输出流详细讲解_第3张图片

图12.2 I/O流体系结构图

12.2 File类

File类可以用于处理文件目录。在对一个文件进行输入/输出,必须先获取有关该文件的基本信息,如文件是否可以读取、能否被写入、路径是什么等。java.io.File类不属于Java流系统,但它是文件流进行文件操作的辅助类,提供了获取文件基本信息以及操作文件的一些方法,通过调用File类提供的相应方法,能够完成创建文件、删除文件以及对目录的一些操作。

12.2.1 File类的常用方法

File类的对象是一个“文件或目录”的抽象,它并不打开文件或目录,而是指定要操作的文件或目录。File类的对象一旦创建,就不能再修改。要创建一个新的File对象,需要使用它的构造方法,如表12.2所示。

表12.2 File类构造方法

构造方法

功能描述

public File(String filename)

创建File对象,filename表示文件或目录的路径

public File(String parent,String child)

创建File对象,parent表示上级目录,child表示指定的子目录或文件名

public File(File obj,String child)

设置File对象,obj表示File对象,child表示指定的子目录或文件名

使用表12.2所列的哪种构造方法要由其他被访问的文件来决定。例如,当在应用程序中只用到一个文件时,使用第1种构造方法最合适;如果使用了一个公共目录下的几个文件,那么使用第2种或第3种构造方法会更方便。

创建File类的对象后,就可以使用File的相关方法来获取文件信息。接下来,先了解一下File类的常用方法,如表12.3所示。

表12.3 File类常用方法

常用方法

功能描述

备注

String getName()

获取相关文件名

与文件名相关的方法

String getPath()

获取文件路径

String getAbsolutePath()

获取文件绝对路径

String getParent()

获取文件上级目录名称

boolean renameTo(File newName)

更改文件名,成功则返回true,否则返回false

boolean exists()

检测文件对象是否存在

文件测定相关方法

boolean canWrite()

检测文件对象是否可写

boolean canRead()

检测文件对象是否可读

boolean isFile()

检测文件对象是否是文件

boolean isDirectory()

检测文件对象是否是目录

boolean isAbsolute()

检测文件对象是否是绝对路径

long lastModified()

返回此File对象表示的文件或目录最后一次被修改的时间

常用文件信息和方法

long length()

返回此File对象表示的文件或目录的长度

boolean delete()

删除文件或目录。如果File对象为目录,则该目录为空,方可删除。删除成功,返回true,否则返回false

boolean mkdir()

创建File对象指定目录。如果创建成功,则返回true,否则返回false

目录相关类工具

boolean mkdirs()

创建File对象指定的目录,如果此目录的父级不存在,则还会创建父目录。如创建成功,则返回true,否则返回false

String []list()

返回此File对象表示的目录中的文件和目录的名称所组成字符串数组

    接下来,通过一个案例来演示File类常用方法的基本使用,先在当前目录创建一个1201.txt文件,在里面输入“AAA软件教育欢迎您!”,然后编写代码,如例12-1所示。

12-1 Demo1201.java

1 package com.aaa.p120201;

2 import java.io.*;

3 import java.util.*;

4 import java.text.SimpleDateFormat;

5

6 public class Demo1201 {

7     public static void main(String[] args) {

8 File file = new File("src/1201.txt");

9 System.out.println("文件是否存在-->" + file.exists());

10 System.out.println("文件是否可写-->" + file.canWrite());

11 System.out.println("文件是否可读-->" + file.canRead());

12 System.out.println("文件是否是文件-->" + file.isFile());

13 System.out.println("文件是否是目录-->" + file.isDirectory());

14 System.out.println("文件是否是绝对路径-->" + file.isAbsolute());

15 System.out.println("文件名是-->" + file.getName());

16 System.out.println("文件的路径是-->" + file.getPath());

17 System.out.println("文件的绝对路径是-->" + file.getAbsolutePath());

18 System.out.println("文件的上级路径是-->" + file.getParent());

19 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

20 System.out.print("最后修改时间-->");

21 System.out.println(sdf.format(new Date(file.lastModified())));

22 System.out.println("文件长度是-->" + file.length());

23     }

24 }

程序的运行结果如下:

文件是否存在-->true

文件是否可写-->true

文件是否可读-->true

文件是否是文件-->true

文件是否是目录-->false

文件是否是绝对路径-->false

文件名是-->1201.txt

文件的路径是-->src\1201.txt

文件的绝对路径是-->D:\work\AAA课程研发\教材编写\javaIO\src\1201.txt

文件的上级路径是-->src

最后修改时间-->2021-06-15

文件长度是-->25

例12-1在程序中构造了File类的对象,运用File类的各个方法得到文件的各种相关属性。在第19~21行代码中,通过格式化时间信息,获取文件最后修改时间,最后打印文件1201.txt相关属性的信息。

12.2.2 遍历目录下的文件

File类用来操作文件和获得文件的信息,但是不提供对文件读取的方法,这些方法由文件流提供。File类中提供了list()方法和listFiles()方法,用来遍历目录下所有文件。两者不同之处是list()方法只返回文件名,没有路径信息;而listFiles()方法不但返回文件名称,还包含有路径信息。

接下来,通过案例来演示list()方法与listFiles()方法的使用,如例12-2所示。

12-2 Demo1202.java

1 package com.aaa.p120202;

2 import java.io.*;

3

1 public class Demo1202 {

2 public static void main(String[] args) {

3 System.out.printf("***********list()方法***********");

4 File file = new File("D:\\javaCode");         // 创建File对象

5 if (file.isDirectory()) {         // 判断file目录是否存在

6 String[] list = file.list();

7 for (String fileName : list) {

8 System.out.println(fileName);         // 打印文件名

9 }

10 }

11 System.out.printf("***********listFiles()方法***********");

12 files(file);

13 }

14 public static void files(File file) {

15 File[] listFile = file.listFiles();         // 遍历目录下所有文件

16 for (File f : listFile) {

17 if (f.isDirectory()) {         // 判断是否是目录

18 files(f);             // 递归调用

19 }

20 System.out.println(f.getAbsolutePath());

21 }

22 }

23 }

程序的运行结果如下:

***********list()方法***********

chapter02

test.txt

***********listFiles()方法***********

D:\javaCode\chapter02\.idea\.gitignore

D:\javaCode\chapter02\.idea\misc.xml

D:\javaCode\chapter02\.idea\modules.xml

D:\javaCode\chapter02\.idea\uiDesigner.xml

D:\javaCode\chapter02\.idea\workspace.xml

D:\javaCode\chapter02\.idea

D:\javaCode\chapter02\chapter02.iml

D:\javaCode\chapter02\out\production\chapter02\Demo02.class

D:\javaCode\chapter02\out\production\chapter02\Demo0201.class

例12-2中,首先创建File对象,指定File对象的目录。第5~10行代码先判断file目录是否存在,若存在,则调用list()方法,第6行代码以String数组的形式得到所有文件名,最后循环遍历数组内容并打印。如果目录下仍然有子目录则不能遍历到,此时就需要用到File类的listFiles()方法,遍历目录下所有文件之后,循环判断遍历到的是否是目录,如果是目录,则再次递归调用file(file)方法本身。第14~22行代码是自定义的静态方法,直到遍历完到文件。通过程序运行结果可以看到,listFiles()方法输出的信息比list()方法输出的信息更加详细,而且listFiles()方法返回值是File类型,可以直接使用该文件。

注意:在Windows系统中,目录的分隔符是反斜杠(\)。但是,在Java语言中,使用反斜杠表示转义字符,所以如果需要在Windows系统的路径下包括反斜杠,则应该使用两条反斜线,如D:\\javaC

你可能感兴趣的:(java,java)