文章目录
一、文件和文件流
1. 什么是文件
文件是保存数据的地方,比如word文档,txt文件,excel文件。文件既可以保存图片,也可以保存视频,声音等等。
2. 文件流
文件在程序中是以流的形式来操作的。
流:数据在数据源(文件)和程序(内存)之间经历的路径
3.常用的文件操作
此处已经介绍了一些常用的文件操作,可先观看此处,点此链接
二、IO流原理及流的分类
1. IO流基本知识
- Java I/O(Input/Output)是指输入/输出操作。
- Java 中的流都位于 java.io 包下
- 输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
- 输出output:将程序(内存)中的数据输出到磁盘、光盘等存储设备中。
2. Java IO流原理
流是用于处理输入和输出的抽象机制,它提供了一种与底层系统通信的方法。Java I/O流是基于字节
和字符
的操作,它将数据存储在内存中,以便在需要时读取或写入数据。
Java I/O 流的工作原理是通过输入和输出流进行数据传输。输入流从源中读取数据,并将其存储在内存中,然后输出流从内存中读取数据,并将其写入到目标位置中。Java I/O 流的实现是基于装饰器模式的,它允许用户使用不同的装饰器来增强流的功能。
IO 流体系中大量使用了装饰器模式,让流具有更强的功能、更强的灵活性。比如:
FileInputStream fis = new FileInputStream(src);
BufferedInputStream bis = new BufferedInputStream(fis);
显然BufferedInputStream装饰了原有的InputStream,让普通的InputStream也具备了缓存功能,提高了效率。
3. 流的分类
- 按照流向分: 输入流 输出流
- 按照单位分: 字节流 字符流
- 按照角色分: 节点流 处理流
4.IO流的四个顶级父类
(抽象基类) | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream0 | Writer |
Java中IO流涉及到的类,都是由以上四个抽象基类派生的。如下图所示:
三、常用类的使用
1.FileInputStream
实现一:现在要使用FileInputStream读取本地D盘中的hello.txt文件
实现代码:
@Test
public void readFile01 () {
String filePath = "D:\\hello.txt";
int readData = 0;
FileInputStream fileInputStream = null;
try {
//创建 FileInputStream 对象,用于读取文件
fileInputStream = new FileInputStream(filePath);
//从此输入流中读取一个数据字节。如果没有输入可用,则此方法将阻塞。
//如果返回 -1,表示去读取完毕。
while ((readData = fileInputStream.read()) != -1) {
System.out.print((char)readData);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
//关闭文件流,释放资源
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果:
实现二:使用read(byte [ ])方法提高读取效率
代码如下:
/**
* read(byte []) 方法:
* 1、从此输入流中一次性将最多 b.length 个字节的数据读入一个 byte 数组中。
* 2、如果返回 -1,表示已经读取完毕。
* 3、如果读取正常,返回实际读取的字节数
*/
@Test
public void readFile02 () {
String filePath = "D:\\hello.txt";
int readData = 0;
//字节数组
byte [] buf = new byte[8]; //一次读取8个字节
int readLen = 0;
FileInputStream fileInputStream = null;
try {
//创建 FileInputStream 对象,用于读取文件
fileInputStream = new FileInputStream(filePath);
//从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。在某些输入可用之前,此方法将阻塞。
//如果返回 -1,表示去读取完毕。
//如果读取正常,返回实际读取的字节数
while ((readLen = readData = fileInputStream.read(buf)) != -1) {
System.out.print(new String(buf,0,readLen) + " ");//字符串显示
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
//关闭文件流,释放资源
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果:为了方便看出区别,我在每次输出后面加了一个空格,每次输出8个字节,此处可以看到第一次输出是以 o 结尾
2.FileOutputStream
实现一:使用FileOutputStream在 hello2.txt 文件中写入“Hello,World”
实现代码:
/**
* 演示使用FileOutputStream 将数据写到文件中
* 如果文件不存在,则创建文件
* 说明:
* 如果使用 :new FileOutputStream(filePath) 创建方式,当写入内容时,会覆盖原先的内容
* 如果使用: new FileOutputStream(filePath,true) 创建方式,当写入内容时,`会追加到原先的内容之后,并不是覆盖`
*/
实现内容追加使用的是FileOutputStream的另一个构造方法,如下所示:
@Test
public void writeFile() {
//创建 FileOutputStream 对象
String filePath = "D:\\hello2.txt";
FileOutputStream fileOutputStream = null;
try {
//得到 FileOutputStream 对象
fileOutputStream = new FileOutputStream(filePath);
//写入一个字节
//fileOutputStream.write('a');
String str = "hello.world";
//str.getBytes() 可以吧 字符串 -> 字节数组
//write(byte[] b, int off, int len) 将len字节从位于偏移量 off的指定字节数组写入此文件流输出
fileOutputStream.write(str.getBytes(),0,str.length());
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.组合使用,实现文件拷贝
实现:将D:\Demo下的 开发14截图.png 拷贝到D:\
public class FileCopy {
public static void main(String[] args) {
//实现文件拷贝 将D:\\Demo下的 开发14截图.png 拷贝到D:\\
/**
* 思路分析
* 1.创建文件的输入流,将文件读入到程序
* 2.创建文件的输出流,将读取到的文件数据,写入到指定的文件
*/
String path1 = "D:\\Demo\\hello.png"; //要拷贝的文件路径
String path2 = "D:\\hello.png"; //要拷贝到地方的路径
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
byte [] bytes = new byte[1024]; //创建一个byte数组
int readLen = 0; //每次读取的长度
try {
fileInputStream = new FileInputStream(path1);
fileOutputStream = new FileOutputStream(path2);
while ((readLen = fileInputStream.read(bytes)) != -1) {
fileOutputStream.write(bytes,0,readLen);
}
System.out.println("拷贝成功!");
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
//关流
fileOutputStream.close();
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4.FileReader
实现一:使用FileReader读取本地D盘中的 story.txt 文件
/**
* FileReader 常用方法
* new FileReader(File/String) 构造方法
* read():每次读取单个字符,返回该字符,如果文件到末尾则返回-1
* read(char[]):批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1
* 相关API:
* new String(char[]): 将char[]转换成String
* new String(char[],off,len): 将char[]的指定部分转换成String
*/
public class FileReader01 {
public static void main(String[] args) {
String filePath = "D:\\story.txt";
FileReader fileReader = null;
int data = 0;
//1.创建FileReader 对象
try {
fileReader = new FileReader(filePath);
//循环读取 使用 read,读取单个字符
while ((data = fileReader.read()) != -1) {
System.out.print((char)data);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
结果:
实现二:使用char[] 数组,提高读取效率
实现代码:
/**
* 使用字符数组读取文件
*/
@Test
public void readFile02() {
String filePath = "D:\\story.txt";
FileReader fileReader = null;
int readLen = 0;
char[] buf = new char[8]; //创建char[] 数组
try {
//创建FileReader 对象
fileReader = new FileReader(filePath);
//循环读取 使用 read(buf),返回的是实际读取到的字符数
//如果返回-1,说明已经到文件结尾了
while ((readLen = fileReader.read(buf)) != -1) {
System.out.print(new String(buf,0,readLen));
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fileReader.close(); //关流
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果:
5.FileWriter
实现一:使用FileWrite将 “笃志前行,虽远必达” 写入到 D:\note.txt 文件中。
/**
* FileWriter常用方法:
* 1、new FileWriter(File/String):覆盖模式,相当于流的指针在首段
* 2、new FileWriter(File/String,true):追加模式,相当于流的指针在尾端
* 3、write(int):写入单个字符
* 4、write(char[]):写入指定数组
* 5、write(char[],off,len):写入指定数组的指定部分
* 6、write(string):写入整个字符串
* 7、write(string,off,len):写入字符串的指定部分
*
* 注意:对应FileWriter,一定要关闭流,或者刷新(flush)才能真正的把数据写入到文件
* 关闭:刷新(flush) + 关闭
*/
public class FileWrite_ {
public static void main(String[] args) {
String path = "D:\\note.txt";
//创建FileWrite对象
FileWriter fileWriter = null;
try {
// fileWriter = new FileWriter(path);//内容覆盖,第二次执行结果:笃志前行,虽远必达
fileWriter = new FileWriter(path,true);//内容追加,第二次执行结果:笃志前行,虽远必达笃志前行,虽远必达
fileWriter.write("笃志前行,虽远必达");
// fileWriter.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (fileWriter != null){
fileWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
四、节点流和处理流
节点流
节点流是直接将源或目标连接到数据源或目标的流,是一个真正的Java IO流对象,代表着一个底层的物理流(如文件、Socket、管道等)。如:FileReader、FileWriter
处理流
处理流则是在节点流上的一个包装,本身不提供数据传输能力,但加入了许多有用的功能,例如缓冲、转换、过滤等,是对节点流的一种功能增强,使得读写数据更加方便、快捷、高效。如:BufferedReader、BufferedWriter.
处理流本身不能单独存在,必须要连接在一个节点流上,通过多个处理流的组合,可以构建出复杂而高效的IO数据处理链条。
一些处理流:
-
BufferedInputStream、BufferedOutputStream(缓冲流)
字节输入输出流的处理流,可以在读写数据时提高效率,通过缓冲区存储读入的数据,减少与物理介质的交互次数,提高IO性能。 -
BufferedReader、BufferedWriter(缓冲流)
是字符输入输出流的处理流,与BufferedInputStream、BufferedOutputStream不同的是,它们是基于字符数据的缓存机制,可以读写文本数据以及以行为单位读写数据,可以提高读写数据的效率。 -
DataInputStream、DataOutputStream(基本数据类型流)
是字节输入输出流的处理流,支持读写Java基本数据类型,如int、double、boolean等。 -
ObjectInputStream、ObjectOutputStream(对象流)
是字节输入输出流的处理流,支持读写Java对象,可以将Java对象序列化到文件中或从文件中反序列化出来,常常用于Java对象的数据持久化。 -
InputStreamReader、OutputStreamWriter(转换流)
是字节输入输出流与字符输入输出流之间的桥梁,能够把字节流转换为字符流和字符流转换为字节流,支持字符集编码转换。 -
PrintStream、PrintWriter(打印流)
是字节输出流和字符输出流的处理流,支持将格式化的数据写到流中,支持输出Java基本类型数据和对象类型数据。
实现一:使用BufferedReader读取文件
public class BufferedReader_ {
public static void main(String[] args) throws Exception {
String filePath = "D:\\story.txt";
//创建FileReader 对象
FileReader fileReader = new FileReader(filePath);
//创建BufferedReader 对象
BufferedReader bufferedReader = new BufferedReader(fileReader);
//读取
String line; //按行读取,效率高
// bufferedReader.readLine() 是按行读取文件 返回null,表示文件读取完毕
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
//关闭流, 这里只需要关闭 bufferedReader ,因为底层会自动关闭 节点流
bufferedReader.close();
}
}
实现二:使用BufferedWriter写入文件
public class BufferedWriter_ {
public static void main(String[] args) throws IOException {
String filePath = "D:\\hello.txt";
//创建FileWriter对象
FileWriter fileWriter = new FileWriter(filePath);
//创建BufferedWriter对象
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.write("笃志前行,虽远必达");
//插入一个和系统相关的换行
bufferedWriter.newLine();
//此处会在下一行显示
bufferedWriter.write("笃志前行,虽远必达");
//关闭流 关闭包装流即可,fileWriter 会在底层自动关闭
bufferedWriter.close();
}
}
实现三:拷贝文件
/**
* BufferedReader 和 BufferedWriter 是安装字符操作
* 不要去操作二进制文件,可能会造成文件损坏
*/
public class BufferedCopy {
public static void main(String[] args) {
String filePath1 = "D:\\Java\\story.txt";
String filePath2 = "D:\\story.txt";
BufferedReader br = null;
BufferedWriter bw = null;
String line = null;
try {
br = new BufferedReader(new FileReader(filePath1));
bw = new BufferedWriter(new FileWriter(filePath2));
//readLine() 读取一行内容,但是没有换行
while ((line = br.readLine()) != null) {
//每读取一行就写入
bw.write(line);
//插入一个换行
bw.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (br != null) {
br.close();
}
if (bw != null) {
bw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
五、Properties类
介绍
Java中的Properties类是一个键值对集合,通常用来存储和读取配置参数。它继承了Hashtable类,因此提供了Hashtable的所有方法,并增加了一些方便使用的特性,如支持从文件加载和保存属性、默认属性值等。下面是Properties类的详细介绍:
- 创建对象:
Properties prop = new Properties();
- 存取键值:
// 存储键值对
prop.setProperty("key", "value");
// 根据键获取值
String value = prop.getProperty("key");
- 加载属性:
// 从输入流读取属性
InputStream in = new FileInputStream("config.properties");
prop.load(in);
// 从文件读取属性
FileInputStream fis = new FileInputStream("config.properties");
prop.load(fis);
在以上示例中,我们可以通过使用setProperty()
方法将键值对添加到Properties对象中。然后,我们可以使用getProperty()方法通过键名称获取相应的值。接着,我们可以使用load()方法从(输入)流中加载属性。
- 保存属性:
// 将属性写入到文件中
OutputStream out = new FileOutputStream("config.properties");
prop.store(out, "Configurations");
在以上示例中,我们打开output Stream并指定目标文件,通过调用store()方法将Properties对象中的所有键值对存储到输出流中。此外,第二个参数是可选的注释字符串。
- 默认属性值:
Properties defaultProps = new Properties();
// 设置默认属性值
defaultProps.setProperty("key1", "value1");
// 创建属性对象,并将默认值作为参数
Properties props = new Properties(defaultProps);
// 获取属性值
String value = props.getProperty("key1");
通过在初始化Properties对象时传递一个默认属性值对象,我们可以将某些键值对的默认值提前设置。如果在之后存储或获取某个键的值时没有指定具体的值,则相应的缺省值将被使用。
实现:使用Properties 类来读取 jdbc.properties 文件
public class Properties01 {
public static void main(String[] args) throws IOException {
//1.创建Properties对象
Properties properties = new Properties();
//2.加载指定配置文件
properties.load(new FileReader("gao3\\src\\jdbc.properties"));
//3.把k-v显示在控制台
properties.list(System.out);
System.out.println("===================");
//4.根据key 获取相对应的值
String user = properties.getProperty("user");
String password = properties.getProperty("password");
System.out.println("用户名:" + user);
System.out.println("密码:" + password);
}
}
结果:
作者期望
如果能从本篇文章获取到一点知识的话,请为作者点个赞加个油
如果有什么不正确的地方,欢迎指正,评论区交流。