2021年6月7日。又是一年高考季。又一代人的青春迎来了高考,祝福每一位高考考生!
在炎热的夏日里,除了坐在考场上奋笔疾书的考生们。此时此刻,我坐在电脑前整理这篇Java IO流知识点总结。希望能对需要它的人有帮助。
1、前言
我们在日常开发中,有许多方面都会涉及到IO流,比如上传,下载,设计模式等等。而所有的一切都是基于IO流来进行的,所以今天这篇文章就来看看Java中IO流的相关知识点。
本文主要内容安排如下:
- 文件对象
- 流简介
- 字节流
- 字符流
2、文件对象
2.1 文件路径
Java标准库 java.io 提供了 File 对象用于操作文件和目录,也就是说我们的文件和目录都是可以通过 File 封装成对象的。构造 File 对象时,需要传入我们的文件或目录的路径名,常用的构造方法如下:
import java.io.File;
/**
* @version : 1.0
* @className : FileObject
* @date : 2021/4/20 9:20
* @description : 创建 File 对象的三个构造方法
*/
public class FileObject {
public static void main(String[] args) {
File file1 = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data/1.txt");
System.out.println(file1);
File file2 = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data", "1.txt");
System.out.println(file2);
File file3 = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data");
File file4 = new File(file3, "1.txt");
System.out.println(file4);
}
}
复制代码
对于我们传入文件的路径,既可以使用绝对路径,也可以使用相对路径。
- 相对路径:以当前文件所在位置为参考,然后建立出另一个文件所在位置路径。我们最常用的有 . 和 ..,前者表示当前目录,而后者则表示当前目录的上一级目录。假设我们当前目录为 /home/cunyu1943/data,则 . 仍然表示该目录,而 .. 则表示 /home/cunyu1943 目录。
- 绝对路径:又可以分为 本地绝对路径 和 网络绝对路径。本地绝对路径以根目录为参考,指文件在硬盘中真实存在的路径,比如在 Windows 系统,我们的一个绝对路径是D:\Softwares\Typora\Typora.exe,而在类 Unix 系统中则为 /home/cunyu1943/IO.md,此时需要注意平台间的分隔符是不一样的,但为了同一,推荐同一写成 /,这样程序在不同系统中迁移时也不会出现问题。而网络绝对位置则指带有网址的路径,比如 www.baidu.com。
import java.io.File;
import java.io.IOException;
/**
* @version : 1.0
* @className : FilePath
* @date : 2021/4/20 9:55
* @description : 文件路径
*/
public class FilePath {
public static void main(String[] args) throws IOException {
File file = new File("../data/1.txt");
System.out.println(file.getPath());
System.out.println(file.getAbsolutePath());
System.out.println(file.getCanonicalPath());
}
}
复制代码
2.2 文件和目录操作
2.2.1 创建与删除
既然拿到了 File 对象,接下来就是通过操作该对象来进行创建和删除文件或目录了,以下是一些 File 类常用的创建和删除方法。
import java.io.File;
import java.io.IOException;
/**
* @version : 1.0
* @className : CreateAndDelete
* @date : 2021/4/20 10:40
* @description : 创建&删除
*/
public class CreateAndDelete {
public static void main(String[] args) throws IOException {
File file1 = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data/2.txt");
if (file1.createNewFile()) {
System.out.println("创建文件成功");
} else {
System.out.println("创建文件失败");
}
if (file1.delete()) {
System.out.println("删除文件成功");
} else {
System.out.println("删除文件失败");
}
File file2 = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data/demo");
if (file2.mkdir()) {
System.out.println("创建文件夹成功");
} else {
System.out.println("创建文件夹失败");
}
File file3 = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data/JavaSE/demo");
if (file3.mkdirs()) {
System.out.println("创建多级目录成功");
} else {
System.out.println("创建多级目录失败");
}
}
}
复制代码
注意
- 创建文件时,调用的是 createNewFile() 方法,而创建目录时调用的是 mkdir() 或者 mkdirs() 方法。我们在调用时要注意区分,否则就算你的路径是文件,当调用了创建目录的方法后它也会创建成目录而非文件。对应的,就算你给定的路径是目录,当调用创建文件的方法后它也会创建成文件而非目录。
- 删除目录时,若目录中有内容(目录、文件),则 不能直接删除,而是应该先删除目录中的内容,然后才能删除目录;
2.2.2 相关属性
获取到 File 对象后,我们可以对其相关属性进行判断,常用方法如下:
import java.io.File;
/**
* @version : 1.0
* @className : Main
* @date : 2021/4/20 11:04
* @description : 相关属性
*/
public class Main {
public static void main(String[] args) {
File file = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data/new.txt");
if (file.canExecute()) {
System.out.println("该对象可执行");
} else {
System.out.println("该对象不可执行");
}
if (file.canRead()) {
System.out.println("该对象可读");
} else {
System.out.println("该对象不可读");
}
if (file.canWrite()) {
System.out.println("该对象可写");
} else {
System.out.println("该对象不可写");
}
System.out.println("文件大小:" + file.length() + " Byte");
}
}
复制代码
2.2.3 获取和判断
获取到 File 对象后,我们既可以用它来表示文件,也可以用来表示目录。而对于文件和目录的判断和获取功能,可以使用如下常用的方法:
import java.io.File;
/**
* @version : 1.0
* @className : Main
* @date : 2021/4/20 11:15
* @description : 判断和获取
*/
public class Main {
public static void main(String[] args) {
File file = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data");
System.out.println(file.isDirectory());
System.out.println(file.isFile());
System.out.println(file.exists());
System.out.println("-------------------------");
System.out.println(file.getPath());
System.out.println(file.getAbsolutePath());
System.out.println(file.getName());
System.out.println("-------------------------");
System.out.println("目录下的文件和目录列表:(文件或目录名)");
for (String path : file.list()) {
System.out.println(path);
}
System.out.println("-------------------------");
System.out.println("目录下的文件和目录列表:(完整绝对路径)");
for (File path : file.listFiles()) {
System.out.println(path);
}
}
}
复制代码
2.3 练习
假设我们要遍历 Windows 下 C 盘的 Windows 目录,并且列出其中文件名和文件大小,而不用列出目录名,我们可以利用如下代码来实现:
i
mport java.io.File;
/**
* @version : 1.0
* @className : Test
* @date : 2021/4/20 11:40
* @description : 遍历 C 盘 Windows 目录下的文件,并打印文件名和大小
*/
public class Test {
public static void main(String[] args) {
File file = new File("C:/windows");
for (File item : file.listFiles()) {
if (item.isFile()) {
System.out.println("文件名:" + item.getName() + "\t文件大小占:" + item.length() + " 字节");
}
}
}
}
复制代码
3、流
3.1 什么是流
所谓流,就是一系列数据的组合。当我们需要进行数据交互的时候,比如在服务器和客户端之间进行数据交互时,我们此时就可以使用 Java 中的流来实现。Java 中,数据的输入和输出都是以流的形式来进行的。根据数据流方向的不同,我们可以将其分为:输入流、输出流。而根据处理的数据单位不同,可分为:字节流、字符流。两者的关系可以描述为下表:
而对于字节流和字符流的选用原则,我们建议遵循如下规则:如果数据能够通过 Windows 自带笔记本软件打开并且能够读懂其中的内容,则选用字符流,否则选择字节流。而如果我们也不知道应该使用何种类型的流,则默认使用字节流。
下图描述了字节流和字符流的类层次图,注意:无论是字节流还是字符流,其子类名都是以其父类名作为子类名的后缀的。
3.2 InputStream
注意,InputStream 并非是并不是一个接口,而是所有字节输入流所有类的父类。下面我们主要以 FileInputStream 来举例,所谓 FileInputStream,就是从文件流中读取数据,然后将数据从文件中读取到内存,常用方法如下:
下面是一个从文件中读取数据到内存中的实例,文件内容如下:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* @version : 1.0
* @className : TestInputStream
* @date : 2021/4/20 15:29
* @description : InputStream 实例
*/
public class TestInputStream {
public static void main(String[] args) {
String result = null;
File file = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data/1.txt");
try (InputStream inputStream = new FileInputStream(file)) {
// 读取输入流中可以被读的 bytes 估计值
int size = inputStream.available();
// 根据 bytes 数创建数组
byte[] array = new byte[size];
// 数据读取到数组
inputStream.read(array);
// 数组转化为字符串
result = new String(array);
} catch (IOException e) {
e.printStackTrace();
}
// 打印字符串
System.out.println(result);
}
}
复制代码
3.3 OutputStream
OutputStream 并非是并不是一个接口,而是所有输出字节流的所有类的父类。下面我们主要以 FileOutputStream 来举例,所谓 FileOutputStream,就是从内存中读取数据,然后将数据从内存存放到文件中,常用方法如下:
import java.io.*;
/**
* @version : 1.0
* @className : TestOutputStream
* @date : 2021/4/20 15:58
* @description : OutputStream 实例
*/
public class TestOutputStream {
public static void main(String[] args) {
File file = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data/2.txt");
String content = "这是一个 OutputStream 实例!";
try (OutputStream outputStream = new FileOutputStream(file)) {
// 字符串转换为 byte 数组
byte[] array = content.getBytes();
// 写入数据
outputStream.write(array);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("写入成功");
}
}
复制代码
需要注意的点:
① 字节流写入数据时如何实现换行?
写入换行的转义字符的字节数组即可,但是需要注意,不同系统下换行的转义字符不同,Windows 下为 \r\n,macOS 下为 \r,而 Linux 下为 \m。
②字节流写入数据时如何实现追加?
调用 public FileOutputStream(String name, boolean append) 这个构造方法即可,当 append 为 true 时,表示追加,默认情况下是 false,表示不追加。
除了这篇文章整理的关于Java IO流的学习资料,我还整理了更多的Java学习资料,多家互联网大厂和多位大佬的面经资料,还有更多的面试技巧。有需要的朋友可以点击进入获取。暗号:掘金。一起好好学习,天天向上!
3.4 字符串中的编解码问题
3.4.1 编码
(1)byte[] getBytes():使用平台默认字符集将该字符串编码成一系列字节,然后将结果存储到新的字节数组中;
(2)byte[] getBytes(String charsetName):使用指定字符集将该字符串编码为一系列字节,然后将结果存储到新的字节数组中;
3.4.2 解码
(1)String(byte[] bytes):使用平台默认字符集解码指定的字节数来构造新的字符串;
(2)String(byte[] bytes, String charsetName):通过指定的字符集解码指定的字节数组来构造新的字符串;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
/**
* @version : 1.0
* @className : EncodeAndDecode
* @date : 2021/4/21 9:37
* @description : 编码和解码
*/
public class EncodeAndDecode {
public static void main(String[] args) throws UnsupportedEncodingException {
// 编码
String str = "村雨遥";
byte[] bytes1 = str.getBytes();
byte[] bytes2 = str.getBytes("UTF-8");
byte[] bytes3 = str.getBytes("GBK");
System.out.println(Arrays.toString(bytes1));
System.out.println(Arrays.toString(bytes2));
System.out.println(Arrays.toString(bytes3));
// 解码
String res1 = new String(bytes1);
String res2 = new String(bytes1, "UTF-8");
String res3 = new String(bytes1, "GBK");
System.out.println(res1);
System.out.println(res2);
System.out.println(res3);
}
}
复制代码
3.5 Writer
当我们要写入基于字符的数据到数据源中时,需要使用写入器 Writer. 以其中的 FileWriter 具体展开,其常用方法如下:
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
/**
* @version : 1.0
* @className : TestWriter
* @date : 2021/4/20 18:35
* @description : Writer 实例
*/
public class TestWriter {
public static void main(String[] args) {
File file = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data/2.txt");
try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file))) {
bufferedWriter.write("村雨遥");
bufferedWriter.newLine();
bufferedWriter.write("Blog:https://cunyu1943.site");
bufferedWriter.newLine();
bufferedWriter.flush();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("写入成功");
}
}
复制代码
3.6 Reader
当我们要从数据源读取基于字符的数据时,需要使用读取器 Reader. 我们以 FileReader 实践,其常用的方法有:
我们以从文件中读取内容为例:
import java.io.*;
/**
* @version : 1.0
* @className : TestReader
* @date : 2021/4/20 18:40
* @description : Reader 实例
*/
public class TestReader {
public static void main(String[] args) {
String content = null;
File file = new File("D:/PersonalFiles/github/githubCodes/IDEA/TheWay2Java/IOStream/data/2.txt");
System.out.println("内容如下:");
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) {
while ((content = bufferedReader.readLine()) != null) {
System.out.println(content);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
复制代码
4、总结
本文整理的相关知识点难免会有遗漏或者错误的知识点,如果此时此刻正在阅读这篇文章的你发现有错误,敬请指正,谢谢大家啦!
以上,就是本文整理的关于IO流的知识点,赶紧学起来吧!如果你觉得本文对你有帮助,别忘了点赞、收藏、分享、关注一波哟!加油加油,冲冲冲!