四时宝库

程序员的知识宝库

File类详解以及IO流(java.io的file类是什么类)

这几天写文件的读取和上传,虽然现在的工具类很多,都封装好了,但是依然要会使用原始方法进行读取和保存,今天记录一下。

File概述

我们平时说的文件是指的保存数据的地方,例如 word 文档、txt 文件、excel 文件等都属于文件,文件既可以保存我们平时的文字信息,也可以保存图片、视频以及声音等信息。

而在 Java 程序中,文件是以 “流” 的形式来进行操作的,如下图所示:

java中的输入:将磁盘的文件中的数据读取到 Java 程序中。

java中的输出:从 Java 程序中将数据写入到磁盘的文件中。

在计算机系统中,文件是一种非常重要的存储方式。Java 的标准库 java.io 提供了 File 类的实例对象来操作文件。在 Java 程序中,我们创建一个 File 对象时需要提供一个抽象文件路径名,之所以叫做抽象,是因为在创建该 File 对象时,提供的文件路径是在 Java 程序中声明的,而此时系统的磁盘中并不一定真实存在该文件路径。

  • 路径 vs 相对路径

绝对路径:是一个固定的文件路径,从盘符号开始声明,如:/Users/wangpeng/Downloads。

相对路径:是相对于某个位置开始声明的文件路径,在 Java 程序中:main()方法中的相对路径是相对于当前项目;单元测试方法中的相对路径是相对于当前模块;

  • 文件路径分隔符

文件路径中的每级目录之间都会用一个路径分隔符隔开。

默认的路径分隔符和操作系统有关:

1、windows 和 dos 系统默认使用 “\” 来分隔;

2、Linux、Unix 和 URL 使用 “/” 来分隔;

3、Java 程序支持跨平台运行,因此路径分隔符需要动态设置,File 类提供了一个静态常量,可以根据 Java 程序运行在不同的操作系统,动态地提供路径分隔符。如下:

public static final String separator

举例:

//举例:
File file1 = new File("Users" + File.separator + "aaa.txt");
//在windows中,会自动转为 “\\”
File file2 = new File("d:\\王朋.txt");
//在Linux中,会自动转为 “/”
File file3 = new File("/Users/wangpeng/Downloads/wangpeng.txt");

File 对象创建

创建一个 File 类对象可以使用 File 类提供的 3 种构造器方法,这 3 种构造器分别传入不同的抽象文件路径名,该路径名是以字符串形式表示的。用法如下:

方式一:public File(String pathname)

这里的pathname可以是绝对路径也可以是相对路径,如果是相对路径,则默认的当前路径在系统属性 user.dir 中存储:

//创建 File 对象
File file = new File("/Users/wangpeng/Downloads/wangpeng.txt");

方式二:public File(String parent, String child)

根据父目录文件(File 对象)和文件路径名创建一个 File 对象:

//先创建了一个 File 对象
File parentFile = new File("/Users/wangpeng/Downloads");
//这只是个文件路径名
String fileName = "wangpeng.txt";
File file = new File(parentFile, fileName);

方式三:public File(File parent, String child)

根据父目录路径名和文件路径名创建一个 File 对象:

String parentPath = "/Users/wangpeng/Downloads";
String fileName = "wangpeng.txt";
//上面的两个都是文件路径名
//真正创建 File 对象
File file = new File(parentPath, fileName);

特别注意:创建一个 File 对象时,即使提供的抽象文件路径名在磁盘中不存在,代码也不会出错,因为创建一个File 对象,并不会导致任何磁盘操作。只有当我们调用 File 对象的某些方法的时候,才会真正进行磁盘操作。

File 的常用方法

  • 磁盘操作的方法

在调用下面方法时,会真正在磁盘中产生操作,将 Java 内存中的 File 对象与磁盘中的文件产生联系。

如下表所示:

方法

功能

public boolean exists()

判断传入的抽象路径名(目录/文件)在磁盘中是否存在

public boolean isFile()

判断传入的抽象路径名是否是一个在磁盘中已存在的文件

public boolean isDirectory()

判断传入的抽象路径名是否是一个在磁盘中已存在的目录

public boolean createNewFile()

在磁盘中创建文件。若文件已存在,则不创建,返回 false

public boolean mkdir()

在磁盘中创建文件目录。如果此文件目录已存在,则不创建。如果此文件目录为未存在的多级文件目录,也不能创建

public boolean mkdirs()

在磁盘中一次性创建多级文件目录

public boolean delete()

从磁盘中删除指定文件路径下的文件或者文件目录


注意: 如果要删除一个文件目录,要保证该文件目录为空目录,即不能一次性删除多级目录。

  • 获取文件属性的方法

在调用下面方法时,不会真正地在磁盘中操作,只是操作 Java 内存中的 File 对象,获取 File 对象的一些属性。

如下表所示:

方法

功能

public String getAbsolutePath()

返回传入的抽象路径名的绝对路径名字符串

public String getPath()

将传入的抽象路径名转换为一个路径名字符串,并返回(传入什么就是什么)

public String getParent()

返回传入的抽象路径名的父路径名的路径名字符串(即最后一个分隔符前的路径)。如果此路径名没有指定父目录,则返回 null

public String getName()

返回传入的抽象路径名的最后一个子文件名(即最后一个分隔符后的路径)


注意: 如果声明的抽象文件路径名没有盘符路径,则该文件的绝对路径默认是在项目路径/模块路径下。

IO流

文件的读取和保存与IO流息息相关,我们先看下java的IO流相关知识。

  • 流的分类

按数据的流向不同分为:输入流输出流


输入流

输出流

字节流

InputStream

OutputStream

字符流

Reader

Writer

按操作数据单位的不同分为:字节流(8bit)和字符流(16bit)

根据IO流的角色不同分为:节点流(直接从数据源或目的地读写数据)和处理流(不直接连接到数据源或目的地,而是“连接”在已存在的流(节点流或处理流)上)

节点流FileInputStream、FileOutputStream、FileReader、FileWriter

处理流

缓冲流(增加缓冲功能,避免频繁读写硬盘,进而提升读写效率):BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter

转换流(实现字节流和字符流之间的转换):InputStreamReader、OutputStreamWriter

对象流(提供直接读写 Java 对象功能):ObjectInputStream、ObjectOutputStream

  • 字节流处理:InputStream 和 OutputStream

以字节为单位,处理文件信息

java.io.InputStream 抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。

方法

功能

public int read()

从输入流读取一个字节。返回读取的字节值。虽然读取了 一个字节,但是会自动提升为 int 类型。如果已经到达流末尾,没有数据可读,则返回-1。

public int read(byte[] b)

从输入流中读取一些字节数,并将它们存储到字节数组 b 中 。每次最多读取 b.length 个字节。返回实际读取的字节个数。如果已经到达流末尾,没有数据可读,则返回-1。

public int read(byte[] b,int off,int len)

从输入流中读取一些字节数,并将它们存储到字节数组 b 中,从 b[off]开始存储,每次最多读取 len 个字节。返回实际读取的字节个数。如果已经到达流末尾,没有数据可读,则返回-1。

public void close()

关闭此输入流并释放与此流相关联的任何系统资源。

java.io.OutputStream 抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。

方法

功能

public void write(int b)

将指定的字节输出流。虽然参数为 int 类型四个字 节,但是只会保留一个字节的信息写出。

public void write(byte[] b)

将 b.length 字节从指定的字节数组写入此输出流。

public void write(byte[] b, int off, int len)

从指定的字节数组写 入 len 字节,从偏移量 off 开始输出到此输出流。

public void flush()

刷新此输出流并强制任何缓冲的输出字节被写出

public void close()

关闭此输出流并释放与此流相关联的任何系统资源。

使用FileInputStream+FileOutputStream完成文件复制

public static void main(String[] args) {
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try {
			fis = new FileInputStream(new File("hello.txt"));
			fos = new FileOutputStream(new File("hello1.txt"));

			byte[] buffer = new byte[1024];
			int len = 0;
			while ((len = fis.read(buffer)) != -1) {
				fos.write(buffer, 0, len);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			try {
				if (fos != null)
					fos.close();
			} catch (IOException e) {
				throw new RuntimeException(e);
			}finally {
				try {
					if (fis != null)
						fis.close();
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
		}
	}
  • 字符流处理:Reader 与 Writer

以字符为单位读写数据,专门用于处理文本文件

常见的文本文件有如下格式:.txt 等

Reader抽象类的基本共性功能方法

方法

功能

public int read()

从输入流读取一个字符。 虽然读取了一个字符,但是会自动提升为 int 类型。返回该字符的 Unicode 编码值。如果已经到达流末尾了,则返回-1。

public int read(char[] cbuf)

从输入流中读取一些字符,并将它们存储到字符数组 cbuf 中 。每次最多读取 cbuf.length 个字符。返回实际读取的字符个数。 如果已经到达流末尾,没有数据可读,则返回-1。

public int read(char[] cbuf,int off,int len)

从输入流中读取一些字符,并将它们存储到字符数组 cbuf 中,从 cbuf[off]开始的位置存储。每次最多读取 len 个字符。返回实际读取的字符个数。如果已经到达流末尾,没有数据可读,则返 回-1。

public void close()

关闭此流并释放与此流相关联的任何系统资源。注意:当完成流的操作时,必须调用 close()方法,释放系统资源,否 则会造成内存泄漏

Writer抽象类的基本共性功能方法

方法

功能

public void write(int c)

写出单个字符。

public void write(char[] cbuf)

写出字符数组。

public void write(char[] cbuf, int off, int len)

写出字符数组的某一部分。off:数组的开始索引;len:写出的字符个数。

public void write(String str)

写出字符串。

public void write(String str, int off, int len)

写出字符串的某一部分。off:字符串的开始索引;len:写出的字符个数。

public void flush()

刷新该流的缓冲。因为内置缓冲区的原因,如果FileWriter不关闭输出流,无法写出字符到文件。如果希望不关闭流,又能写出数据,可以调用flush方法

public void close()

关闭此流。先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了

//使用FileReader完成文件读取
public static void main(String[] args) {
		FileReader reader = null;
		try {
			File file = new File("hello.txt");
			reader = new FileReader(file);
			int data = 0;
			while ((data = reader.read()) != -1) {
				System.out.print((char) data);
			}
      //上面的也可以换成下面的这种方式
      //char[] cbuf = new char[5];
			//while ((len = reader.read(cbuf)) != -1) {
				// 为什么不采用 String string = new String(cbuf);
				// 因为最后一次读取的时候,可能不足5个,这样就会出现乱码
			//	String string = new String(cbuf, 0, len);
			//	System.out.print(string);
			//}

		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
////使用FileWriter完成文件保存
public static void main(String[] args) {
		FileWriter fw=null;
		try {
			File file = new File("file.txt");
			fw = new FileWriter(file);
			fw.write("Hello World!");
			fw.flush();
			fw.close();
		} catch (IOException e) {
			try {
				fw.close();
			} catch (IOException ioException) {
				
			}
		}

	}
  • 缓冲流处理:BufferedInputStream、BufferedOutputStream、BufferedReader,BufferedWriter

缓冲流的基本原理:在创建流对象时,内部会创建一个缓冲区数组(默认/缺省使用 8192个字节(8Kb)的缓冲区),通过缓冲区读写,减少系统 IO 次数,从而提高读写的效率。

字符缓冲流特有方法

BufferedReader:public String readLine():读一行文字。

BufferedWriter:public void newLine():写入行分隔符,行分隔符由系统属性定义符号;在 Windows 上,它将写入 "\r\n",在 Unix/Linux/Mac 上,它将写入 "\n"。

StringBuilder content = new StringBuilder();
   try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
       String line;
       while ((line = reader.readLine()) != null) {
           content.append(line).append(System.lineSeparator());
       }
   }
 return content.toString();

Java NIO Files

Java标准库提供的一个工具类,用于操作文件和目录。它提供了一系列静态方法,可以用于创建、复制、删除、移动、重命名、读取、写入文件和目录等常见的文件系统操作。同时,它也提供了一些高级特性,如文件系统监控、文件属性操作等。在Java 7中引入,用于替代旧的java.io.File类。它是Java NIO中处理文件的核心组件之一,基于Java NIO的FileChannel和Path组件实现。

使用Files类读取文件的实现原理主要涉及到Path和FileChannel两个核心组件。当我们使用Files类读取文件时,首先需要使用Path对象创建一个文件路径,然后使用FileChannel打开一个文件通道,最后读取文件的内容到指定的数据结构中。

以下是使用Java NIO读取文件的步骤:

1、通过java.nio.file.Path类创建文件路径对象,例如:Path path = Paths.get("file.txt");

2、通过java.nio.file.Files类读取文件内容,例如:byte[] bytes = Files.readAllBytes(path);或List<String> lines = Files.readAllLines(path);

  • readAllBytes()方法可以一次性读取文件的所有字节,并返回一个byte[]数组。
  • readAllLines()方法可以逐行读取文本文件的内容,并返回一个List<String>对象,其中每个元素表示文件中的一行文本数据。

3、对于较大的文件,可以使用java.nio.file.Files类的newByteChannel()方法创建一个java.nio.channels.FileChannel对象,并使用ByteBuffer类缓存内容,以提高效率。

Path path = Paths.get("file.txt");
try (FileChannel channel = FileChannel.open(path)) {
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    while (channel.read(buffer) > 0) {
        buffer.flip();
        //读取buffer中的内容
        buffer.clear();
    }
} catch (IOException e) {
    e.printStackTrace();
}

注意在读取之前需要调用flip()方法将缓冲区从写模式切换到读模式,以便读取缓冲区中的内容。

JAVA读取和保存文件

上面已经介绍了文件读取和保存的基本操作,但是实际上我们并不用书写繁琐的代码,我们借助org.apache.commons.io.FileUtils工具类完成文件的读取与保存等操作

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接