Java-IO流知识整理
一、文件
1.1 概念
- 保存数据的地方;
1.2 文件流
-
文件在程序中是以流的形式来操作的;
-
流:数据在 数据源(文件) 和 程序(内存) 之间经历的路径;
- 输入流: 数据源(文件) ==> 程序(内存)
- 输出流: 数据源(文件) <== 程序(内存)
1.3 常用的文件操作
-
(1)文件创建
- 三种方式
static void createFile_1(){//1.根据文件路径创建 String filePath = "D:\\JavaCode\\projects\\JavaDemo\\hsp_ch19\\testfile\\news01.txt"; File file = new File(filePath);//在内存中,创建了File文件对象; try { file.createNewFile();//此时才会在磁盘对应位置创建文件并写入; System.out.println("文件" + file.getName() + "已创建"); } catch (IOException e) { throw new RuntimeException(e); } } static void createFile_2(){//2.根据父目录文件 + 文件名创建 File parent = new File("D:\\JavaCode\\projects\\JavaDemo\\hsp_ch19\\testfile"); String fileName = "news02.txt"; File file = new File(parent, fileName); try { file.createNewFile(); System.out.println("文件" + file.getName() + "已创建"); } catch (IOException e) { throw new RuntimeException(e); } } static void createFile_3(){//3.根据父目录文件路径 + 文件名创建 String parentPath = "D:\\JavaCode\\projects\\JavaDemo\\hsp_ch19\\testfile"; String fileName = "news03.txt"; File file = new File(parentPath, fileName); try { file.createNewFile(); System.out.println("文件" + file.getName() + "已创建"); } catch (IOException e) { throw new RuntimeException(e); } }
-
(2)获取文件信息
- 常用的几个:
static void getInfo(){ File file = new File("D:\\JavaCode\\projects\\JavaDemo\\hsp_ch19\\testfile\\news01.txt"); System.out.println(" 文件名 ===== " + file.getName()); System.out.println(" 绝对路径 ===== " + file.getAbsolutePath()); System.out.println(" 父级目录 ===== " + file.getParent()); System.out.println(" 文件大小(byte) ===== " + file.length()); System.out.println(" 文件是否存在 ===== " + file.exists()); System.out.println(" 是不是一个文件 ===== " + file.isFile()); System.out.println(" 文件是不是一个目录 ===== " + file.isDirectory()); }
-
(3)目录操作和文件删除
- 删除文件
@Test public void m1() { //1.判断 指定路径的文件是否存在,存在则删除; String filePath = "D:\\JavaCode\\projects\\JavaDemo\\hsp_ch19\\testfile\\news01.txt"; File file = new File(filePath); if (file.exists()) { if (file.delete()) { System.out.println("文件删除成功!"); } else { System.out.println("文件删除失败!"); } } else { System.out.println("文件不存在!"); } }
- 删除(目录)文件
@Test public void m2() { //2.判断 指定目录 是否存在,存在则删除; // 目录也是一种文件!! String filePath = "D:\\JavaCode\\projects\\JavaDemo\\hsp_ch19\\testfile02"; File file = new File(filePath); if (file.exists()) { if (file.delete()) { System.out.println("目录删除成功!"); } else { System.out.println("目录删除失败!"); } } else { System.out.println("该目录不存在!"); } }
- 创建目录
@Test public void m3() { //3.判断 指定目录 是否存在,存在则提示存在,否则创建该目录; String filePath = "D:\\JavaCode\\projects\\JavaDemo\\hsp_ch19\\testfile\\a"; File file = new File(filePath); if (file.exists()) { System.out.println("该目录已存在!"); } else { if(file.mkdirs()){//创建多级目录mkdirs(),即在当前已存在的目录下,创建多级目录文件(...\\a\\b\\c\\d) // if(file.mkdir()){//创建一级目录mkdir(),即在当前已存在的目录下,创建一级目录文件(...\\a) System.out.println("该目录创建成功!"); } else { System.out.println("该目录创建失败!"); } } }
二、IO流原理及流的分类
2.1 I/O原理
- I/O技术:用于处理数据传输,如文件读/写,网络通讯等;
- Java程序中,对于数据输入/输出操作以“流(stream)”的方式进行;
- 输入流(input):读取外部数据(可以是磁盘、光盘、另一个程序等等)到程序(内存)中;
- 输出流(output):将程序(内存)数据输出到外部存储设备或另一个程序
- java.io包中提供了各种“流”类和接口,用以获取不同种类的数据,并通过方法进行数据的输入或输出;
2.2 流的分类
- 按操作数据单位不同:
- 字节流(8 bit)
- InputStream 和 OutputStream
- 如:操作二进制文件(如视频,音频)时,使用字节流操作不会产生损失;
- 字符流(字符,大小与文件编码有关)
- Reader 和 Writer
- 如:操作文本文件(文本文件里面都是字符)时,使用字符流操作比较好;
- 字节流(8 bit)
- 按数据流的流向不同:
- 输入流
- 输出流
- 按流的角色不同
- 节点流
- 处理流/包装流
(抽象基类) | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
上述四个类都是抽象类,可以通过实现子类来创建相应的对象,I/O流的子类都是以抽象父类作为后缀的
2.3 输入流
2.3.1 InputStream
- 抽象类 ==> 输入流 ==> 字节流
- 以字节为单位进行I/O操作
FileInputStream
-
文件输入流(字节流)
-
new FileInputStream(File/String)
- 一个字节一个字节读取
@Test public void read_FileInputStream_byte() throws IOException { String filePath = "D:\\JavaCode\\projects\\JavaDemo\\hsp_ch19\\testfile\\hello1.txt"; int read_index = 0; FileInputStream fi = null; try { fi = new FileInputStream(filePath); read_index = fi.read(); while(read_index != -1){//read_index == -1时,文件到达末尾,读取结束! System.out.print((char)read_index); read_index = fi.read(); } System.out.println(); } catch (IOException e) { throw new RuntimeException(e); } finally { //这里不能直接访问trycatch子句中定义的流对象 if(fi != null) fi.close(); } }
- 通过byte数组,指定每次最多读取的字节数
@Test public void read_FileInputStream_byteArray() throws IOException { String filePath = "D:\\JavaCode\\projects\\JavaDemo\\hsp_ch19\\testfile\\hello1.txt"; int read_len = 0; byte[] buf = new byte[8];//让字节流一次最多读取8个字节 FileInputStream fi = null; try { fi = new FileInputStream(filePath); while ((read_len = fi.read(buf)) != -1){//read(byte[])返回读取到的字节数 System.out.print(new String(buf, 0, read_len)); } } catch (IOException e) { throw new RuntimeException(e); } finally { //这里不能直接访问trycatch子句中定义的流对象 if(fi != null) fi.close(); } }
BufferedInputStream
-
继承关系:BufferedInputStream 继承 FliterInputStream 继承 InputStream
-
带缓冲字节输入流(包装流,可以包装任意InputStream字节输入流及其实现子类)
ObjectInputStream
- 对象字节输入流(节点-处理-输入流)
- new ObjectInputStream(InpuSteam)
2.3.2 Reader
- 抽象类 ==> 输入流 ==> 字符流
- 以字符为单位进行I/O操作
FileReader
-
继承关系:FileReader 继承 InputStreamReader 继承 Reader
-
文件输入流(字符流)
-
new FileReader(File/String)
- 一个字符一个字符读取
@Test public void read_FileReader_char() throws IOException { String filePath = "D:\\JavaCode\\projects\\JavaDemo\\hsp_ch19\\testfile\\news04.txt"; int read_index = 0; FileReader fr = null; try { fr = new FileReader(filePath); while((read_index = fr.read()) != -1){ System.out.print((char)read_index); } System.out.println(); } catch (IOException e) { throw new RuntimeException(e); } finally {//记得关闭流!! if(fr != null) fr.close(); } }
- 通过char数组读取
@Test public void read_FileReader_charArr() throws IOException { String filePath = "D:\\JavaCode\\projects\\JavaDemo\\hsp_ch19\\testfile\\news04.txt"; int read_len = 0; char[] buf = new char[8]; FileReader fr = null; try { fr = new FileReader(filePath); while((read_len = fr.read(buf)) != -1){ // System.out.print(new String(buf)); System.out.print(new String(buf, 0, read_len)); } System.out.println(); } catch (IOException e) { throw new RuntimeException(e); } finally {//记得关闭流!! if(fr != null) fr.close(); } }
BufferedReader
-
带缓冲字符输入流(包装流,可以包装不同的节点流)
-
new BufferedReader(new xxxReader)
- 读取文件
import java.io.*; /** * @author: sea-365 * @date: 2023/4/21 15:06 */ public class FileIO_BufferedReader01 { public static void main(String[] args) throws IOException { String filePath = "./hsp_ch19/FileIO_create/FileIO_create01.java"; //创建BufferedReader BufferedReader bufferedReader = new BufferedReader(new FileReader(new File(filePath))); //读取文件 String line = bufferedReader.readLine(); while(line != null){ System.out.println(line); line = bufferedReader.readLine(); } //关闭流 bufferedReader.close(); } }
InputStreamReader
- 转换流
2.4 输出流
2.4.1 OutputStream
- 抽象类 ==> 输出流 ==> 字节流
- 以字节为单位进行I/O操作
FileOutputStream
-
文件输出流(字节流)
- 若指定的文件不存在但所在目录存在,则会先创建该文件然后写入数据;
@Test public void write_FileOutputStream() throws IOException { String filePath = "D:\\JavaCode\\projects\\JavaDemo\\hsp_ch19\\testfile\\hello2.txt"; FileOutputStream fo = null; try { fo = new FileOutputStream(filePath, true);//true表示追加模式,默认为false覆盖模式; fo.write('a');//写入单个字节; fo.write("\nhello,北京\n".getBytes());//通过字节数组写入 fo.write("\n1234567890\n".getBytes(), 3, 9);//写入字节数组指定范围内的数据 } catch (IOException e) { throw new RuntimeException(e); } finally { if(fo != null) fo.close(); } }
BufferedOutputStream
- 继承关系:BufferedOutputStream 继承 FliterOutputStream 继承 OutputStream
- 带缓冲字节输出流(包装流,可以包装任意OutputStream字节输入流及其实现子类)
ObjectOutputStream
- 对象字节输出流(节点-处理-输出流)
- new ObjectOutputStream(OutputStream)
2.4.2 Writer
-
抽象类 ==> 输入流 ==> 字符流
-
以字符为单位进行I/O操作
FileWriter
-
继承关系:FileWriter 继承 OutputStreamWriter 继承 Writer
-
文件输出流(字符流)
-
FileWriter在使用结束后,必须使用close()关闭方法或flush()刷新方法,否则写入不到指定文件(还在内存中!!!)
-
顺序:先flush(),后close()!
-
两个方法的实现中都会将流里面的内容写入文件;
-
-
new FileWriter(File/String, true);//true表示追加内容,默认是false,覆盖模式;
- 一个字符一个字符写入
@Test public void writer_FileWriter_char() throws IOException { String filePath = "D:\\JavaCode\\projects\\JavaDemo\\hsp_ch19\\testfile\\news05.txt"; FileWriter fw = null; try { //fw = new FileWriter(filePath);//覆盖模式 fw = new FileWriter(filePath, true);//追加模式 fw.write('a'); } catch (IOException e) { throw new RuntimeException(e); } finally {//记得关闭或刷新流!! if(fw != null) fw.close(); } }
- 指定char数组写入
@Test public void writer_FileWriter_charArr() throws IOException { String filePath = "D:\\JavaCode\\projects\\JavaDemo\\hsp_ch19\\testfile\\news05.txt"; FileWriter fw = null; try { //fw = new FileWriter(filePath);//覆盖模式 fw = new FileWriter(filePath, true);//追加模式 fw.write("abcdefg\n".toCharArray()); fw.write("abcdefgh\n".toCharArray(), 0, 3); } catch (IOException e) { throw new RuntimeException(e); } finally {//记得关闭或刷新流!! if(fw != null) fw.close(); } }
- 字符串写入
@Test public void writer_FileWriter_String() throws IOException { String filePath = "D:\\JavaCode\\projects\\JavaDemo\\hsp_ch19\\testfile\\news05.txt"; FileWriter fw = null; try { //fw = new FileWriter(filePath);//覆盖模式 fw = new FileWriter(filePath, true);//追加模式 fw.write("abcdefg\n"); fw.write("abcdefgh\n", 0, 3); } catch (IOException e) { throw new RuntimeException(e); } finally {//记得关闭或刷新流!! if(fw != null) fw.close(); } }
BufferedWriter
-
带缓冲字符输出流
-
new BufferedWriter(new xxxWriter)
- 字符串写入文件
import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; /** * @author: sea-365 * @date: 2023/4/21 16:52 */ public class FileIO_BufferedWriter01 { public static void main(String[] args) throws IOException { String filePath = "./hsp_ch19/testfile/bufferedwriter01.txt"; BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(new File(filePath))); bufferedWriter.write("我现在在学Java IO流,感觉不是很有意思啊。。。。"); bufferedWriter.newLine();//插入一个和系统相关的换行符 bufferedWriter.write("还是得学习!!!"); bufferedWriter.close(); } }
OutputStreamWriter
- 转换流
2.5 节点流和处理流
分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 | 分类 |
---|---|---|---|---|---|
抽象基类 | InputStream | OutputStream | Reader | Writer | |
访问文件 | FileInputStream | FileOutputStream | FileReader | FileWriter | 节点流 |
访问数组 | ByteArrayInputStream | 节点流 | |||
访问管道 | PipedInputStream | 节点流 | |||
访问字符串 | 节点流 | ||||
缓冲流 | BufferedInputStream | 处理(包装)流 | |||
转换流 | 处理(包装)流 | ||||
对象流 | ObjectInputStream | 处理(包装)流 | |||
抽象基类 (继承自第二行的基类) | FilterInputStream | FilterOutputStream | FilterReader | FilterWriter | |
打印流 | PrintStream | PrintWriter | 处理(包装)流 | ||
推回输入流 | PushbackInputStream | PushbackReader | 处理(包装)流 | ||
特殊流 | DataInputStream | DataOutputStream | 处理(包装)流 |
2.5.1 节点流
- 节点流可以从一个**特定的数据源(存放数据的地方)**读写数据;
- 如FileReader、FileWriter是从某个文件中读写数据;
2.5.2 处理流
- 处理流也叫包装流,是“连接”在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能;
- 如BufferedReader、BufferedWriter;
- 优点:
- 1.性能的提升:主要以增加缓冲的方式来提高输入输出的效率;
- 2.操作的便捷:处理流 可能提供一系列便捷的方法来一次性输入输出大批量数据,使用更加灵活;
2.5.3 区别和联系
- 1.节点流是底层(低级)流,直接跟数据源相接;
- 2.处理流(包装流)包装节点流,既可以消除不同节点流的实现差异,也可以提供更加方便的输入输出方法;
- 3.处理流对节点流进行包装,使用了修饰器设计模式,不与数据源直接相连;
2.5.4 标准输入输出流
流 | 类型 | 默认设备 | 描述 | 编译类型 | 运行类型 |
---|---|---|---|---|---|
System.in | InputStream | 键盘 | 标准输入 | InputStream | BufferedInputStream |
System.out | OutputStream | 显示器 | 标准输出 | PrintStream | PrintStream |
/**
* @author: sea-365
* @date: 2023/4/26 20:35
*/
public class FileIO_System01 {
public static void main(String[] args) {
System.out.println(System.in.getClass());
System.out.println(System.out.getClass());
}
}
- 输出:
2.5.5 转换流
-
InputStreamReader
- new InputStreamReader(InputStream)
- new InputStreamReader(InputStream, Charset);//可以指定字符集将字节流转换为字符流;
-
OutputStreamWriter
- new OutputStreamWriter(OutputStream)
- new OutputStreamWriter(OutputStream, Charset)
-
是Reader/Writer的子类,是字符流;
-
处理纯文本数据时,使用字符流效率较高,可以有效解决中文乱码问题;
2.5.6 打印流
- PrintStream/PrintWriter
- 继承关系:
- PrintStream 继承 FilterOutputStream 继承 OutputStream;
- PrintWriter 继承 Wirter;
- 字节流,只有输出流,没有输入流;
2.6 Properties
- 例子:读取配置文件中的值
- 配置文件如下:
ip=192.168.0.1
user=root;
password=123456
- 不使用Properties类时
/**
* @author: sea-365
* @date: 2023/4/26 21:40
*/
public class FileIO_Properties01 {
public static void main(String[] args) throws IOException {
//不使用Properties类
String filePath = "./hsp_ch19/testfile/mysql.properties";
BufferedReader br = new BufferedReader(new FileReader(filePath));
String line = "";
while((line = br.readLine()) != null){
String[] split = line.split("=");
System.out.println(split[0] + "=" + split[1]);
}
}
}
-
Properties类介绍
- 专门用于读写配置文件的集合类;
- 格式:键=值
- 注意:键值对中不需要空格,值不需要用引号,默认类型是String;
- 专门用于读写配置文件的集合类;
-
使用Properties类
/**
* @author: SEA
* @date: 2023/4/27
*/
public class FileIO_Properties02{
public static void main(String[] args) throws IOException {
String filePath_1 = "./hsp_ch19/testfile/mysql.properties";
String filePath_2 = "./hsp_ch19/testfile/mysql2.properties";
//new一个Propertes对象
Properties properties = new Properties();
//加载指定的配置文件
properties.load(new FileReader(filePath_1));
//将指定配置文件中的配置信息打印到标准输出(显示器)
properties.list(new PrintStream(System.out));
Properties properties1 = new Properties();
properties1.setProperty("email", "123456@163.com");
properties1.setProperty("call", "123456789");
properties1.setProperty("name", "张三");//出现中文,将会转换成Unicode编码进行保存
properties1.store(new FileOutputStream(filePath_2), "");
properties1.list(new PrintStream(System.out));
}
}