I/O 框架
流的概念
- 内存与存储设备之间传输数据的通道
水(相当于数据)-> 传输水的管道(相当于流)-> 脸盆(相当于内存)
生活用水 -> 流入
家庭废水 -> 流出
流的分类
按方向【重点】
- 输入流:将<存储设备>中的内容读到<内存>中
- 输出流:将<内存>中的内容写到<存储设备>中
按单位
- 字节流:以字节为单位,可以读写所有数据
- 字符流:以字符为单位,只能读写文本数据
按功能
- 节点流:具有实际传输数据的读写功能
- 过滤流:在节点流的基础之上增强功能
字节流
字节流的父类(抽象类)
//InputStream 字节输入流
public int read(){
}
public int read(byte[] b){
}
public int read(byte[] b, int off, int len){
}
// OutputStream 字节输出流
public void write(int n){
}
public void write(byte[] b){
}
public void write(byte[] b, int off, int len){
}
文件字节流
文件输入流
//文件字节输入流
public static void main(String[] args) throws Exception{
//1. 创建FileInputStream,并指定文件路径
FileInputStream file = new FileInputStream("路径/a.txt");
//2. 读取文件
//2.1 单字节读取
int data = 0;
while((data=file.read())!=-1){
System.out.print((char) data);
}
//2.2.1 一次读取多个字节
byte[] buf = new byte[3];
int count = file.read(buf);
System.out.println(new String(buf));
System.out.println(count);
int count2 = file.read(buf);
System.out.println(new String(buf));
System.out.println(count2);
//2.2.1 一次读取多个字节
byte[] buf = new byte[1024];
int count = 0;
while ((count=file.read(buf))!=-1){
System.out.println(new String(buf,0,count));
}
//3. 关闭
file.close();
System.out.println("\n执行完毕");
}
文件输出流
//FileOutputStream
public static void main(String[] args) throws Exception{
//1. 创建FileOutputStream,并指定文件路径
FileOutputStream fos = new FileOutputStream("路径/b.txt",true);
//true 不覆盖
//2. 输出文件
fos.write(97);
fos.write('b');
fos.write('c');
String str = "helloworld";
fos.write(str.getBytes());
//3. 关闭
fos.close();
System.out.println("执行完毕");
}
图片复制案例
public static void main(String[] args) throws Exception {
//使用文件字节流实现文件的复制
// 1 创建流
// 1.1 文件字节输入流
FileInputStream fis = new FileInputStream("路径/a.jpg");
// 1.2 文件字节输出流
FileOutputStream fos = new FileOutputStream("路径/b.jpg");
// 2 边读边写
byte[] buf = new byte[1024];
int count = 0;
while((count=fis.read(buf))!=-1){
fos.write(buf,0,count);
}
// 3 关闭
fis.close();
fos.close();
}
字节缓冲流
缓冲流:BufferedInputStream/ BufferedOutputStream
- 提高IO效率,减少访问磁盘次数
- 数据存储在缓冲区中,flush是将缓冲区的内容写入文件中,也可以直接close
//BufferedInputStream
public static void main(String[] args) throws Exception{
//1. 创建BufferedInputStream
FileInputStream fis = new FileInputStream("路径/a.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
//2. 读取
int data = 0;
while((data=bis.read())!=-1){
System.out.print((char)data);
}
//自己创建缓冲区
byte[] buf = new byte[1024];
int count = 0;
while((count=bis.read(buf))!=-1){
System.out.println(new String(buf,0,count));
}
//3. 关闭
bis.close();
System.out.println("\n执行完毕");
}
public static void main(String[] args) throws Exception{
//1. 创建BufferedOutputStream 字节输出缓冲流
FileOutputStream fos = new FileOutputStream("路径/b2.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
//2. 写入文件
for(int i=0;i<10;i++){
bos.write("helloworld\n".getBytes());//写入缓冲区,没超过8K缓冲区
bos.flush();//刷新到硬盘
}
//3. 关闭
bos.close();
System.out.println("\n执行完毕");
}
对象流
- 增强了缓冲区功能
- 增强了读写8种基本数据类型和字符串的功能
- 增强了读写对象的功能
readObject()
从流中读取一个对象writeObject(Object obj)
向流中写入一个对象
使用流传输对象的过程称为序列化、反序列化
序列化与反序列化
序列化
- 序列化类必须要实现Serializable接口
//实现接口 标记接口
public class Student implements Serializable {
}
//使用ObjectOutputStream 实现对象的序列化
public static void main(String[] args) throws Exception{
//1. 创建对象流
FileOutputStream fos = new FileOutputStream("路径/stu.bin");
ObjectOutputStream oos = new ObjectOutputStream(fos);
//2. 序列化(写入操作)
Student s1 = new Student("zhangsan",20);
oos.writeObject(s1);
//3. 关闭
oos.close();
System.out.println("执行完毕");
}
反序列化
// 使用ObjectInputSteam实现反序列化(读取重构对象)
public static void main(String[] args) throws Exception{
//1. 创建对象流
FileInputStream fis = new FileInputStream("路径/stu.bin");
ObjectInputStream ois = new ObjectInputStream(fis);
//2. 读取文件(反序列化)
Student s = (Student) ois.readObject();
//关闭
ois.close();
System.out.println("执行完毕");
System.out.println(s.toString());//Student{name='zhangsan', age=20}
}
注意事项
- 某个类要想序列化必须实现Serializable接口
- 序列化类中对象属性要求实现Serializable接口
- 序列化版本号ID,保证序列化的类和反序列化的类是同一个类
- 使用transient(瞬间的)修饰属性,这个属性就不能序列化
- 静态属性不能序列化
- 序列化多个对象,可以借助集合来实现
具体的序列化过程是这样的:
序列化操作的时候系统会把当前类的serialVersionUID写入到序列化文件中,当反序列化时系统会去检测文件中的serialVersionUID,判断它是否与当前类的serialVersionUID一致,如果一致就说明序列化类的版本与当前类版本是一样的,可以反序列化成功,否则失败。
//序列化多个对象,可以借助集合来实现
//2. 序列化(写入操作)
Student s1 = new Student("zhangsan",20);
Student s2 = new Student("lisi",25);
ArrayList<Student> list = new ArrayList<>();
list.add(s1);
list.add(s2);
oos.writeObject(list);
//2. 读取文件(反序列化)
//Student s = (Student) ois.readObject();
ArrayList<Student> list = (ArrayList<Student>) ois.readObject();
//关闭
ois.close();
System.out.println("执行完毕");
System.out.println(list.toString());
//[Student{name='zhangsan', age=0}, Student{name='lisi', age=0}]
编码方式
- ISO-8859-1 收录除ASCII外,还包括西欧、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号
- UTF-8 针对Unicode码表的可变长度字符编码
- GB2312 简体中文
- GBK 简体中文、扩充
- BIG5 台湾,繁体中文
字符流
public static void main(String[] args) throws Exception{
//1. 创建FileInputStream对象
FileInputStream fis = new FileInputStream("路径/hello.txt");
//2. 读取
int data = 0;
while((data = fis.read())!=-1){
System.out.print((char)data);
}
//3. 关闭
fis.close();
}
字符流的父类(抽象类)
reader
字符输入流
public int read(){}
public int read(char[] c){}
public int read(char[] b, int off, int len){}
Writer
字符输出流
public void write(int n){}
public void write(String str){}
public void write(char[] c){}
//使用FileReader读取文件
public static void main(String[] args) throws Exception {
//1. 创建FileReader 文件字符输入流
FileReader fr = new FileReader("路径/hello.txt");
//2. 读取
//2.1 单个字符读取
/*
int data = 0;
while ((data = fr.read()) != -1) {
System.out.print((char) data);
}
*/
//2.2 字符缓冲区
char[] buf = new char[1024];
int count = 0;
while((count=fr.read(buf))!=-1){
System.out.println(new String(buf,0,count));
}
//3. 关闭
fr.close();
System.out.println("执行完毕");
}
//使用FileWriter读取文件
public static void main(String[] args) throws Exception {
//1. 创建FileWriter对象
FileWriter fw = new FileWriter("/Users/xay/Desktop/编程/JAVA-FullStack/JavaSE/JavaBasics/src/Demo15/write.txt");
//2. 写入
for (int i = 0; i < 10; i++) {
fw.write("java是世界上最好的语言\n");
fw.flush();
}
//3. 关闭
fw.close();
System.out.println("执行完毕");
}
字符流案例(使用上述内容复制文本)
- 不能复制图片或二进制文件,使用字节流可以复制任意文件
- 使用字节流可以复制任何文件
- 字符流可以复制文本文件
public static void main(String[] args) throws Exception {
//1. 创建FileReader FileWriter
FileReader fr = new FileReader("路径/write.txt");
FileWriter fw = new FileWriter("路径/write2.txt");
//2. 读写
int data = 0;
while((data=fr.read())!=-1){
fw.write(data);
fw.flush();
}
//3. 关闭
fr.close();
fw.close();
System.out.println("执行完毕");
}
字符缓冲流
BufferedReader / BufferedWriter
高效读写、支持输入换行符、可一次写一行读一行
//BufferedReader 使用字符缓冲流读取文件
public static void main(String[] args) throws Exception{
//创建缓冲流
FileReader fr = new FileReader("路径/write.txt");
BufferedReader br = new BufferedReader(fr);
//2. 读取
//2.1 第一种方式
char[] buf = new char[1024];
int count = 0;
while((count=br.read(buf))!=-1){
System.out.print(new String(buf,0,count));
}
//2.2 第二种方式,一行一行读取
String line = null;
while((line = br.readLine())!=null){
System.out.println(line);
}
//3. 关闭
br.close();
System.out.println("执行结束");
}
//BufferedWriter 使用字符缓冲流写入文件
public static void main(String[] args) throws Exception{
//1. 创建BufferedWriter对象
FileWriter fw = new FileWriter("路径/buffer.txt");
BufferedWriter bw = new BufferedWriter(fw);
//2. 写入
for(int i=0;i<10;i++){
bw.write("好好学习,天天向上");
bw.newLine();//换行符
bw.flush();
}
//3. 关闭
bw.close();
System.out.println("执行完毕");
}
PrintWriter
- 封装了
print() / println()
方法 支持写入后换行 - 支持数据原样打印
//PrintWriter 的使用
public static void main(String[] args) throws Exception {
//1. 创建打印流
PrintWriter pw = new PrintWriter("路径/print.txt");
//2. 打印
pw.println(97);//97
pw.println(true);//true
pw.println(3.14);//3.14
pw.println('a');//a
//3. 关闭
pw.close();
System.out.println("执行结束");
}
转换流
- 桥转换流
InputStreamReader / OutputStreamWriter
- 可将字节流转换为字符流
- 可设置字符的编码方式
//InputStreamReader 的使用 读取文件,指定使用的编码
public static void main(String[] args) throws Exception {
//1. 创建InputStreamReader 对象
FileInputStream fis = new FileInputStream("路径/write.txt");
InputStreamReader isr = new InputStreamReader(fis,"utf-8");
//2. 读取文件
int data = 0;
while((data=isr.read())!=-1){
System.out.print((char)data);
}
//3. 关闭
isr.close();
System.out.println("执行完毕");
}
//OutputStreamWriter 写入文件,使用指定编码
public static void main(String[] args) throws Exception {
//1. 创建OutputStreamWriter对象
FileOutputStream fos = new FileOutputStream("路径/info.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos, "utf-8");
//2. 写入
for (int i = 0; i < 10; i++) {
osw.write("你好中国");
osw.flush();
}
//3. 关闭
osw.close();
System.out.println("执行成功");
}
File类
概念:代表物理盘符中的一个文件或者文件夹
File类的使用
- 分隔符
- 文件操作
- 文件夹操作
FileFilter接口
- public interface FileFilter
- boolean accept(File pathname)
- 当调用File类中的listFiles( )方法时,支持传入FileFIlter接口实现类,对获取文件进行过滤,只有满足条件的文件的才可以出现在listFiles( )的返回值中
public class Demo01 {
/*
File类的使用
1. 分隔符
2. 文件操作
3. 文件夹操作
*/
public static void main(String[] args) throws Exception {
separator();
fileOpe();
directoryOpe();
}
// 1. 分隔符
public static void separator() {
System.out.println("路径分隔符" + File.pathSeparator);//:
System.out.println("名称分隔符" + File.separator);///
}
// 2. 文件操作
public static void fileOpe() throws Exception {
// 1. 创建文件
File file = new File("路径/file.txt");
System.out.println(file.toString());
if (!file.exists()) {
boolean b = file.createNewFile();
System.out.println("创建结果:" + b);//创建结果:true
}
// 2. 删除文件
// 2.1 直接删除
//System.out.println("删除的结果:" + file.delete());
// 2.2 使用jvm退出时删除
//ile.deleteOnExit();
//Thread.sleep(5000);
// 3. 获取文件信息
System.out.println("获取绝对路径:" + file.getAbsolutePath());
System.out.println("获取路径:" + file.getPath());
System.out.println("获取文件名称:" + file.getName());
System.out.println("获取父目录:" + file.getParent());
System.out.println("获取文字长度:" + file.length());
System.out.println("文件创建时间:" + new Date(file.lastModified()).toLocaleString());
// 4. 判断
System.out.println("是否可写:" + file.canWrite());
System.out.println("是否是文件:" + file.isFile());
System.out.println("是否隐藏:" + file.isHidden());
}
// 3. 文件夹操作
public static void directoryOpe() throws Exception {
// 1. 创建文件夹
File dir = new File("路径/a/b/c");
System.out.println(dir.toString());
if (!dir.exists()) {
//dir.mkdir();//只能创建单级目录
boolean b = dir.mkdirs();//创建多级目录
System.out.println("创建结果:" + b);
}
// 2. 删除文件夹
// 2.1 直接删除
//System.out.println("删除结果:"+dir.delete());// 只能删除最底层空目录
// 2.2 使用jvm删除
//dir.deleteOnExit();
// 3. 获取文件夹信息
System.out.println("获取绝对路径:" + dir.getAbsolutePath());
System.out.println("获取路径:" + dir.getPath());
System.out.println("获取文件夹名称:" + dir.getName());//最底层文件夹名称
System.out.println("获取父目录:" + dir.getParent());
System.out.println("获取创建时间:" + new Date(dir.lastModified()).toLocaleString());
// 4. 判断
System.out.println("是否是文件夹:" + dir.isDirectory());
System.out.println("是否隐藏:" + dir.isHidden());
// 5. 遍历文件夹
File dir2 = new File("路径/Demo16");
String[] files = dir2.list();
for(String file :files){
System.out.println(file.toString());
}
// FileFilter接口的使用
File[] files2 = dir2.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if(pathname.getName().endsWith(".txt")){
return true;
}
return false;
}
});
for(File file : files2){
System.out.println(file.getName());
}
}
}
递归遍历文件夹
//递归遍历文件夹
public static void main(String[] args) throws Exception {
listDir(new File("/Users/xay/Desktop/编程/JAVA-FullStack/JavaSE/JavaBasics/src"));
}
public static void listDir(File dir) {
File[] files = dir.listFiles();
System.out.println(dir.getName());
if (files != null && files.length > 0) {
for(File file : files){
if(file.isDirectory()){
listDir(file);
}else {
System.out.println(file.getName());
}
}
}
}
递归删除文件夹
public static void deleteDir(File dir){
File[] files = dir.listFiles();
if(files!=null && files.length>0){
for(File file : files){
if(file.isDirectory()){
deleteDir(file);
}else {
//删除文件
System.out.println(file.getAbsolutePath()+"删除"+file.delete());
}
}
}
System.out.println(dir.getAbsolutePath()+"删除"+dir.delete());
}
Properties
- Properties:属性集合
- 特点
- 存储属性名和属性值
- 属性名和属性值都是字符串类型
- 没有泛型
- 和流有关
//Properties集合的使用
public static void main(String[] args) throws Exception{
//1. 创建集合
Properties properties = new Properties();
//2. 添加数据
properties.setProperty("username","zhangsan");
properties.setProperty("age","20");
System.out.println(properties.toString());
//3. 遍历
//3.1 keyset
//3.2 entrySet
//3.3 stringPropertyNames()
Set<String> pronames = properties.stringPropertyNames();
for(String pro : pronames){
System.out.println(pro + "-" + properties.get(pro));
}
//和流有关的方法
//4.1 list方法
PrintWriter pw =new PrintWriter("路径/print.txt");
properties.list(pw);
pw.close();
//4.2 store方法 保存
FileOutputStream fos = new FileOutputStream("路径/print.properties");
properties.store(fos,"注释");
fos.close();
//4.3 load方法 加载
Properties properties2 = new Properties();
FileInputStream fis = new FileInputStream("路径/print.properties");
properties2.load(fis);
fis.close();
System.out.println(properties2.toString());
}