概述
流:数据在数据源(文件)和程序(内存)之间经历的路径
输入流:数据从数据源(文件)到程序(内存)的路径
输出流:数据从程序(内存)到数据源(文件)的路径
流的分类
- 按操作数据单位不同分为:字节流(8 bit)二进制文件,字符流(按字符)
- 按数据流的流向不同分为:输入流,输出流
- 按流的角色的不同分为:节点流,处理流,包装流
| 抽象基类 | 字节流 | 字符流 |
|---|---|---|
| 输入流 | InputStream | Reader |
| 输出流 | OutputStream | Writer |
- Java的IO流共涉及40多个类,实际上非常规则,都是从如上4个抽象基类派生的
- 由这个四个类派生出来的子类名称都是以其父类名作为子类名后缀
文件操作
-
常用方式
API 说明 File(String pathname)根据路径构建一个file对象 File(File parent String child)根据父目录文件 + 子路径构建 File(String parent String child)根据父目录路径 + 子路径构建 注意调用 file.createNewFile() 才能真正创建物理文件File file = new File(System.getProperty("user.dir")+"/src/IOExample/files/testFile1.txt"); try { file.createNewFile(); } catch (IOException e) { throw new RuntimeException(e); } -
常用文件操作
-
获取文件相关信息
API 说明 file.getName()获取文件的名称 file.getAbsolutePath()文件的绝对路径 file.getParent()获取父目录 file.length()获取文件大小 按照编码字节file.exists判断文件是否是存在 file.isFile判断是否是文件 file.isDirectory判断是不是一个目录 -
目录的操作和文件删除
API 说明 file.mkdir()创建一级目录 new File("D:\\h").mkdir()file.mkdirs()创建多级目录 new File("D:\\h\z\k").mkdirs()file.delete()删除空目录(如果目录下有文件需要先去清空)
-
IO流
节点流和处理流的区别和关系
- 节点流底层流(低级流)可以从一个特定的数据源读写数据,直接跟数据源相接
- 处理流(也叫包装流)是 连接 在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入
- 处理流对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连
(使用修饰器设计模式)
- 处理流的功能主要体现在以下两个方面
- 性能的提高:主要以增加缓冲的方式来提高输入输出的效率
- 操作的边界:处理流可以提供一系列边界的方法来一次输入输出大批量的数据,使用更加灵活方便
| 分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 | |
|---|---|---|---|---|---|
| 抽象基类 | InputStream | OutputStream | Reader | Writer | 节点流 |
| 访问文件 | FileInputStream | FileOutputStream | FileReader | FileWriter | |
| 访问数组 | ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter | |
| 访问管道 | PipedInputStream | PipedOutputStream | PipedReader | PipedWriter | |
| 访问字符串 | StringReader | StringWriter | |||
| 缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter | 处理流 |
| 转换流 | InputStreamReader | OutputStreamWriter | |||
| 对象流 | ObjectInputStream | ObjectOutputStream | |||
| 抽象基类 | FilterInputStream | FilterOutputStream | FilterReader | FilterWriter | |
| 打印流 | PrintStream | PrintWriter | |||
| 推回输入流 | PushBackInputStream | PushBackInputReader | |||
| 特殊流 | DataInputStream | DataOutputStream |
InputStream
InputStream 字节输入流抽象类是所有类字节输入的超
FileInputStream 文件输入流
// 单字节获取
@Test
public void fileInputStreamDemo1(){
String filePath = System.getProperty("user.dir") + "/src/IOExample/files/testFile1.txt";
int readData = 0;
FileInputStream fileInputStream = null;
try {
// 从该输入流读取一个字节数据,如果没有输入可用,字方法将阻止
// 如果返回 -1 表示读取完毕
// 如果读取正常,返回实际读取的字节数
fileInputStream = new FileInputStream(filePath);
while ((readData = fileInputStream.read()) != -1) {
System.out.println(readData);
// 只能处理英文,无法转成中文
System.out.println((char)readData);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
fileInputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
// 多字节获取
@Test
public void fileInputStreamDemo2(){
String filePath = System.getProperty("user.dir") + "/src/IOExample/files/testFile1.txt";
// 一次读取8个字节
byte[] bytes = new byte[8];
int readLen = 0;
FileInputStream fileInputStream = null;
try {
// 从该输入流读取一个字节数据,如果没有输入可用,字方法将阻止
// 如果返回 -1 表示读取完毕
// 字母遵循 ASCII
fileInputStream = new FileInputStream(filePath);
while ((readLen = fileInputStream.read(bytes)) != -1) {
System.out.println(new String(bytes , 0 , readLen));
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
fileInputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
ByteArrayInputStream 缓冲字节输入流
ObjectInputStream 序列化输入流
OutputStream
FileOutputStream 文件输出流
@Test
public void fileOutputStreamDemo(){
// 如果文件不存在,则创建文件
// 如果有文件则覆盖原信息
String filePath = System.getProperty("user.dir") + "/src/IOExample/files/testFile1.txt";
FileOutputStream fileOutputStream = null;
String str = "hahhahahaah";
try {
// 覆盖的方式
fileOutputStream = new FileOutputStream(filePath);
// 追加的方式
// fileOutputStream = new FileOutputStream(filePath,true);
fileOutputStream.write(str.getBytes());
// 也可以通过长度输入 等价于上面 0 表示第几个位置,str.length() 表示偏移量
// fileOutputStream.write(str.getBytes(),0,str.length());
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
fileOutputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Reader
@Test
public void fileReaderDemo1(){
String filePath = System.getProperty("user.dir") + "/src/IOExample/files/fileDemo.txt";
FileReader fileReader = null;
int data = 0;
try {
fileReader = new FileReader(filePath);
while ((data = fileReader.read()) != -1){
System.out.println( data +":"+(char)data);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Test
public void fileReaderDemo2(){
String filePath = System.getProperty("user.dir") + "/src/IOExample/files/fileDemo.txt";
FileReader fileReader = null;
char[] chars = new char[8];
int readLen = 0;
try {
fileReader = new FileReader(filePath);
// read(chars) 返回的是实际读取的字符数
while ((readLen = fileReader.read(chars)) != -1){
System.out.println(new String(chars,0,readLen));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Writer
注意在 FileWriter 使用后,必须要关闭(close)或刷新(flush),否则写入不到指定文件!close 等于 flush+关闭
@Test
public void fileWriterStreamDemo(){
// 如果文件不存在,则创建文件
// 如果有文件则覆盖原信息
String filePath = System.getProperty("user.dir") + "/src/IOExample/files/fileDemo.txt";
FileWriter fileWriter = null;
String str = "你好哈哈哈哈哈哈哈1";
try {
// 覆盖的方式
fileWriter = new FileWriter(filePath);
// 追加的方式
// fileWriter = new FileWriter(filePath,true);
fileWriter.write(str);
// 1) fileWriter.write(char); 写入单个字符
// 2) fileWriter.write(char[]); 写入字符数组
// 3) fileWriter.write(char[],off,len); 写入字符数组的指定部分
// 4) fileWriter.write(String,off,len); 写入字符串的指定部分
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
fileWriter.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
处理流
BufferedReader & BufferedWriter
字符流一般处理字符类型的文件
/**
* Buffered 字符流 copy
*/
@Test
public void copyFileBufferedDemo() throws IOException {
String inputFilePath = System.getProperty("user.dir") + "/src/IOExample/files/fileDemo.txt";
String outputFilePath = System.getProperty("user.dir") + "/src/IOExample/files/copyfileDemo.txt";
BufferedReader bufferedReader = new BufferedReader(new FileReader(inputFilePath));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(outputFilePath));
String line;
while ((line = bufferedReader.readLine()) != null) {
bufferedWriter.write(line);
// bufferedWriter.newLine();
// bufferedWriter.write("\r\n");
}
bufferedReader.close();
bufferedWriter.close();
}
BufferedInputStream & BufferedOutputStream
字节流一般处理图片,视频的二进制文件
/**
* Buffered 字节流 copy
*/
@Test
public void copyStreamBufferedDemo() {
String inputFilePath = System.getProperty("user.dir") + "/src/IOExample/files/gtx.jpg";
String outputFilePath = System.getProperty("user.dir") + "/src/IOExample/files/copyGtx.jpg";
BufferedInputStream bufferedInputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
bufferedInputStream = new BufferedInputStream(new FileInputStream(inputFilePath));
bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(outputFilePath));
byte[] bytes = new byte[1024];
int readLen = 0;
while ((readLen = bufferedInputStream.read(bytes)) != -1) {
System.out.println(bytes);
bufferedOutputStream.write(bytes,0 ,readLen);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if(bufferedInputStream != null){
bufferedInputStream.close();
}
if (bufferedOutputStream != null) {
bufferedOutputStream.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
ObjectInputStream & ObjectOutputStream
- 序列化和反序列化说明
- 序列化就是在保存数据时,保存数据的值和数据类型
- 反序列化就是在恢复数据时,恢复数据的值和数据类型
- 需要让某个对象支持序列化机制,则必须让其类是可以序列化的,为了让某个类型可序列化的,该类必须实现如下两个接口之一
Serializable,Externalizable
- 注意
- 读写顺序要一致
- 要求实现序列化或反序列化,需要实现
Serializable - 序列化的类中建议添加
SerialVersionUID,为了提高版本的兼容性(jvm 认为是一个升级版,不是一个新的类) - 序列化对象时,默认将里面所有的属性都都进行序列化,但除了
static或transient修饰的成员 - 序列化对象时,要求里面属性的类型也需要实现序列化接口
- 序列化具备可继承性,也就是如果某个类已经实现了序列化,则它的所有子类也已经默认实现了序列化
- 序列化的类中可以定义属性是实现类,依然可以序列化
// 序列化
@Test
public void objectOutputStreamDemo(){
String outputFilePath = System.getProperty("user.dir") + "/src/IOExample/files/dog.dat";
ObjectOutputStream objectOutputStream = null;
try {
objectOutputStream = new ObjectOutputStream(new FileOutputStream(outputFilePath));
objectOutputStream.writeInt(10); // int -> Integer
objectOutputStream.writeBoolean(true); // boolena -> Boolena
objectOutputStream.writeChar('你'); // char -> Character
objectOutputStream.writeChars("吼吼吼");
objectOutputStream.writeDouble(9.5); // double -> Double
objectOutputStream.writeUTF("哈哈哈");
objectOutputStream.writeObject(new Dog("旺财",10));
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
objectOutputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
// 反序列化
@Test
public void objectInputStreamDemo(){
String outputFilePath = System.getProperty("user.dir") + "/src/IOExample/files/dog.dat";
ObjectInputStream objectInputStream = null;
try {
objectInputStream = new ObjectInputStream(new FileInputStream(outputFilePath));
System.out.println(objectInputStream.readInt());
System.out.println(objectInputStream.readBoolean());
System.out.println(objectInputStream.readChar());
// writeChars 需要循环读
System.out.println(objectInputStream.readChar());
System.out.println(objectInputStream.readChar());
System.out.println(objectInputStream.readChar());
System.out.println(objectInputStream.readDouble());
System.out.println(objectInputStream.readUTF());
System.out.println(objectInputStream.readObject());
// 1. 如果需要使用实现类,需要向下转型
// 2. 需要我们将Dog类的定义,拷贝到可以引用的位置
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException(e);
}finally {
try {
objectInputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
System.in & System.out
- 转换流说明
System.in和System.out是 System 类中的一个属性System 类 的 public final static InputStream in = null System 类 的 public final static InputStream out = nullSystem.in编译类型是 InputStream ,运行类型 BufferedInputStram,标准输入 键盘System.out编译类型是 PrintSteam ,运行类型 PrintSteam,表示标准输出,显示器
InputStreamReader & OutputStreamWriter
- 说明
InputStreamReader是Reader的子类,可以将InputStream(字节流)包装成Reader(字符流)OutputStreamReader是Writer的子类,可以将OutputStream(字节流)包装成Writer(字符流)- 当处理纯文本数据时,如果使用字符流效率更高,并且可以有效的解决中文问题,所以建议将字节流转成字符流
- 可以使用指定的编码格式(utf-8,gbk,gb2312,IOS8859-1 ...)
/**
* 转换流
* @throws IOException
*/
@Test
public void transformStreamDemo() throws IOException {
String inputFilePath = System.getProperty("user.dir") + "/src/IOExample/files/fileDemo.txt";
String outputFilePath = System.getProperty("user.dir") + "/src/IOExample/files/copyTransformFileDemo.txt";
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(inputFilePath),"utf-8");
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(outputFilePath), "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
String line;
while ((line = bufferedReader.readLine()) != null){
System.out.println(line);
bufferedWriter.write(line);
bufferedWriter.newLine();
}
bufferedReader.close();
bufferedWriter.close();
}
PrintStream & PrintWriter
- 说明
- 打印流只有
PrintStream(字节打印流),PrintWriter(字符打印流) PrintStream默认情况下 输出数据的位置是标准输出,即显示器
// 字节打印流
@Test
public void printStreamDemo() throws IOException {
PrintStream out = System.out;
out.print("哈哈");
// out.print 本质就只 out.write
out.write("楼吼吼".getBytes());
out.close();
String inputFilePath = System.getProperty("user.dir") + "/src/IOExample/files/printFileDemo.txt";
// 可以修改打印流输出的位置/设备
// public static void setOut(PrintStream out) {
// checkIO();
// setOut0(out); // native 方法,修改了 out
// }
System.setOut(new PrintStream(inputFilePath));
System.out.println("哈哈哈。。。你好");
}
// 字符打印流
@Test
public void printWriterDemo() throws IOException {
PrintWriter printWriter = new PrintWriter(System.out);
printWriter.println("hi,你好");
printWriter.close();
// 可以写入到文件
PrintWriter printWriter1 = new PrintWriter(System.getProperty("user.dir") + "/src/IOExample/files/printFileDemo.txt");
printWriter1.println("hi,你好世界");
printWriter1.close();
}
Properties
- 说明
- load
| API | 说明 |
|---|---|
| load | 加载配置文件的键值对到 Properties 对象 |
| list | 将数据显示到设备 |
| getProperty | 根据key获取去值 |
| setProperty | 设置键值对到 Properties 对象 |
| store | 将 Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件,如果含有中文,会存储为 unicode 码 |
@Test
public void propertiesDemo() throws IOException {
Properties properties = new Properties();
properties.load(new FileReader(System.getProperty("user.dir") + "/src/IOExample/files/sql.properties"));
/*
* 在输出非追加模式下
* 如果Key不存在则追加,如果存在则修改
* 底层是 Hashtable, 具体原因可以看 Hashtable 中的 put 方法
* */
properties.setProperty("email","122");
properties.store(new FileOutputStream(System.getProperty("user.dir") + "/src/IOExample/files/sql.properties"),null);
properties.list(System.out);
properties.getProperty("user");
// 可以打印入文件
PrintWriter printWriter = new PrintWriter(System.getProperty("user.dir") + "/src/IOExample/files/printFileDemo.txt");
properties.list(printWriter);
printWriter.close();
}