IO 流
一.概述
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
I : input 输入
O : output 输出
二.分类
-
按处理数据类型的不同,分为字节流和字符流
-
按数据流向的不同,分为输入流和输出流。(入和出是相对于内存来讲的)
-
按功能不同,分为节点流和处理流
-
节点流:直接操作数据源
-
处理流:对其他流进行处理
-
三.四大抽象类
3.1 InputStream
3.2 OutputStream
3.3 Reader
3.4 Writer
四.文件流
文件流 : 用来打开文件链接, 操作数据
分为以下几类
-
FileInputStream 字节输入
-
FileOutputStream 字节输出
-
FileReader 字符输入
-
FileWriter 字符输出
4.1 FileInputStream
4.1.1 概述
FilelnputStream 字节输入流,用于把某个文件已字节的形式读取进来
找到这个文件方法:
-
相对路径∶以当前文件为准,去找其他文件,./表示当前目录, ../表示上级目录,../ ../
-
绝对路径∶以系统跟盘符为准,比如D盘E盘
4.1.2 常用方法
4.1.3 实例
注意 : 当读取一个后后续循环将从第二个字节开始读取
package io;
import java.io.FileInputStream;
public class IO_01_FileInputStream {
public static void main(String[] args) {
//在Eclipse中,./定位当前项目JavaSE_08_Io
try (FileInputStream fis = new FileInputStream(
"./src/io/IO_01_FileInputStream.java")) {
//单个读取,read:读取一个字节,返回读到的字节对应的ASCII码值,到达文件末尾返回-1
int i1 = fis.read();
System.out.println(i1);
//循环读取
int temp = 0;
while((temp = fis.read()) != -1){
System.out.print((char)temp);
}
//read[]:重载的read方法,可以传入字节数组,从而提高读取效率,返回值是本次读取到的个数
//如果到达文件末尾,返回-1
//available 可读取的字节个数
byte[] bytes = new byte[fis.available()];
int temp = 0;
while((temp = fis.read(bytes)) != -1){
//转换为字符串
//每一次读取,数组并不会清空,所以读到几个,就把那几个转换为字符串,避免冗余数据
System.out.print(new String(bytes,0,temp));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
4.2 FileReader
4.2.1 概念
FileReader 一次读取一个字符,也就是2字节,而unicode编码也是2字节,所以读取文本文件时,不会出现乱码问题
4.2.2 实例
public class IO_02_FileReader {
public static void main(String[] args) {
try (FileReader fr = new FileReader(
"./src/io/IO_01_FileInputStream.java")) {
//读取一个字符,返回对应的ASCII码值,到达文件末尾,返回-1
int i1 = fr.read();
//方法重载,读取一个字符数组,返回此次读取的个数,到达文件末尾返回-1
char[] chars = new char[500];
int temp = 0;
while((temp = fr.read(chars)) != -1){
System.out.println(new String(chars,0,temp));
}
}
catch (Exception e) {
e.printStackTrace();
}
}
4.3 FileOutputStream
4.3.1 概述
FileOutputStream是字节输出流,用于将内存中数据写出去,需要传入文件路径,如果该文件不存在,则会自动创建(但是不会创建目录)
4.3.2 常用方法
4.3.3 实例
public class IO_03_FileOutputStream {
public static void main(String[] args) {
try (
// 只传入文件路径.,是覆盖写入,会先把对应文件内容清空
// FileOutputStream fos = new FileOutputStream("./src/test.txt");
// 传入一个true,表示追加写入,false或不写,代表覆盖写入
FileOutputStream fos = new FileOutputStream("./src/test.txt");) {
//写出int类型,ASCII码值
fos.write(97);
//写出字节数组(ASCII码)
byte[] bytes = { 97, 98, 99, 100 };
fos.write(bytes);
//写出字符串需要先把字符串转换为字符串数组
String s = "墙里秋千墙外道。墙外行人,墙里佳人笑。——苏轼《蝶恋花·春景》";
fos.write(s.getBytes());
//刷缓冲
fos.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
4.4 FileWriter
4.4.1 概念
FileWriter是字符输出流,输出的是字符,用于防止中文乱码
4.4.2 实例
public class IO_04_FileWrite {
public static void main(String[] args) {
try (
// 覆盖写出
FileWriter fw = new FileWriter("./src/test.txt");) {
// 写出int类型,ASCII码
fw.write(97);
// 写出char数组
char[] chars = { 'a', 'b', 'c' };
fw.write(chars);
// 写出字符串
fw.write("世界微尘里,吾宁爱与憎。——李商隐《北青萝》");
// 刷缓存
fw.flush();
} catch (Exception e) {
// TODO: handle exception
}
}
}
五.缓冲流
【特点】
-
主要是为了提高效率而存在的,减少物理读取次数
-
提供readLine()、newLine()这样的便捷的方法(针对缓冲字符流)
-
在读取和写入时,会有缓存部分,调用flush为刷新缓存,将内存数据写入到磁盘
-
字节缓冲流和字符缓冲流相应方法使用相同
5.1 BufferedReader
public class IO_05_BufferedReader {
public static void main(String[] args) {
try(
FileReader fr = new FileReader("./src/test.txt");
BufferedReader br = new BufferedReader(fr);
) {
//新增读一行功能,返回读取到的内容String,读取到末尾返回null
String temp = null;
while((temp = br.readLine()) != null){
System.out.println(temp);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
5.2 BufferedWriter
public class IO_06_BufferedWriter {
public static void main(String[] args) {
try(
FileWriter fw = new FileWriter("./src/test.txt",true);
BufferedWriter bw = new BufferedWriter(fw);
) {
bw.write("花非花,雾非雾。 夜半来,天明去。——白居易《花非花》");
//新增换行操作
bw.newLine();
bw.write("清时有味是无能,闲爱孤云静爱僧。——杜牧《将赴吴兴登乐游原》");
bw.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
六.转换流
【特点】
-
转换流是指将字节流向字符流的转换,主要有lnputStreamReadex.和OutputStreamWriter
-
lnputStreamReader主要是将字节流输入流转换成字符输入流
-
OutputStreamWriter主要是将字节流输入流转换成字符输出流
6.1 lnputStreamReader
public class IO_07_InputStreamReader {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("./src/test.txt");
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);) {
int temp = br.read();
while(temp != -1){
System.out.println((char)temp);
temp = br.read();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
6.2 OutputStreamWriter
public class IO_08_OutputStreamWriter {
public static void main(String[] args) {
try (
// 字节输出流
FileOutputStream fos = new FileOutputStream("./src/test.txt",true);
// 转换为字符输出流
OutputStreamWriter osw = new OutputStreamWriter(fos);
// 字符输出缓冲流
BufferedWriter bw = new BufferedWriter(osw);) {
bw.write("饮散落花流水各西东。后会不知何处是,烟浪远,暮云重。——秦观《江城子·南来飞燕北归鸿》");
bw.newLine();
bw.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
6.3 处理乱码问题
//为了防止编码不一致导致的乱码问题,在转换流中可以规定编码格式
InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8");
七.打印流
7.1 概念
【特点】
-
打印流是输出最方便的类
-
包含字节打印流PrintStream,字符打印流PrintWriter.
-
PrintStream是OutputStream的子类,把一个输出流的实例传递到打印流之后,可以更加方便地输出内容,相当于把输出流重新包装一下
-
PrintStream类的print()方法被重载很多次print(int i)、print(boolean b)、print(charc)
【示例】 使用StringReader读取字符串,然后使用打印流打印到控制台。
【标准输入/输出】 Java 的标准输入/输出分别通过System.in和System.out 来代表,在默认的情况下分别代表键盘和显示器,当程序通过System.in来获得输入时,实际上是通过键盘获得输入。当程序通过System.out执行输出时,程序总是输出到屏幕。
在System类中提供了三个重定向标准输入/输出的方法
-
static void setErr(PrintStream err)重定向"标准"错误输出流
-
static void setIn(InputStream in)重定向"标准"输入流
-
static void setOut(PrintSteam out)重定向"标准"输出流
7.2 实例
public class IO_09_Print {
public static void main(String[] args) {
try(
//创建字节输出流
FileOutputStream fos = new FileOutputStream("./src/test.txt");
//封装打印流
PrintStream ps = new PrintStream(fos);
) {
ps.println();
ps.println("无情有恨何人觉?月晓风清欲堕时。 ——陆龟蒙《白莲》");
ps.println(false);
ps.println(5.53);
//out就是打印流,只不过默认打印在控制台
System.out.println("夜发清溪向三峡,思君不见下渝州。——李白《峨眉山月歌》");
//另外system提供了修改out打印路径的方式
System.setOut(ps);
System.out.println("长风几万里,吹度玉门关。——李白《关山月》");
} catch (Exception e) {
e.printStackTrace();
}
}
}
八.数据流
8.1 概述
-
DataOutputStream和 DatalnputStream是为了不同的平台间读取数据的统一性
-
操作系统对数据有不同的处理和保存方式,为了弥补这些差一些,Java平台提供了两个轻量级的方法
-
只要每个平台安装jre,就可以保证数据的一致性
-
以二进制传输
-
数据 --> 加密 --> 传递 --> 读取 --> 解密 --> 数据
8.2 实例
读取顺序和类型,必须和写出时一样 否则会导致读取错误
public class IO_10_DataOutputStream {
public static void main(String[] args) {
try (FileOutputStream fos = new FileOutputStream("./src/date.txt");
DataOutputStream dos = new DataOutputStream(fos)) {
dos.writeInt(123);
dos.writeDouble(5.76);
dos.writeBoolean(false);
dos.writeUTF("谁家玉笛暗飞声,散入春风满洛城。——李白《春夜洛城闻笛》");
dos.flush();
// 关闭资源,先打开的后关闭
// 关闭外层,内层也会关闭
dos.close();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class IO_11_DataInputStream {
public static void main(String[] args) {
try(FileInputStream fis = new FileInputStream("./src/data.txt");
DataInputStream dis = new DataInputStream(fis)) {
//读取数据
//读取顺序和类型,必须和写出时一样
System.out.println(dis.readInt());
System.out.println(dis.readDouble());
System.out.println(dis.readBoolean());
System.out.println(dis.readUTF());
dis.close();
fis.close();
} catch (Exception e) {
// TODO: handle exception
}
}
}
九.file
9.1 概述
File类是java提供对文件和文件夹(目录)进行操作的API,与平台无关的 创建,删除,重名名都可以 lO只能操作数据,File只能操作文件和文件夹
9.2 构造方法
public File(String pathname)以pathname为路径创建File对象,可以是绝对路径或者相对路径,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储。
绝对路径:是一个固定的路径,从盘符开始
相对路径:是相对于某个位置开始
lpublic File(String parent,String child)以parent为父路径,child为子路径创建File对象。
lpublic File(File parent,String child)根据一个父File对象和子文件路径创建File对象
9.3 常用方法
获取功能:
-
public String getAbsolutePath():获取绝对路径
-
public String getPath() :获取路径
-
public String getName() :获取名称
-
public String getParent():获取上层文件目录路径。若无,返回null
-
public long length() :获取文件长度(即:字节数)。不能获取目录的长度。
-
public long lastModified() :获取最后一次的修改时间,毫秒值
-
public String[] list() :获取指定目录下的所有文件或者文件目录的名称数组
-
public File[] listFiles() :获取指定目录下的所有文件或者文件目录的File数组
重命名功能:
-
public boolean renameTo(File dest):把文件重命名为指定的文件路径
判断功能:
-
public boolean isDirectory():判断是否是文件目录
-
public boolean isFile() :判断是否是文件
-
public boolean exists() :判断是否存在
-
public boolean canRead() :判断是否可读
-
public boolean canWrite() :判断是否可写
-
public boolean isHidden() :判断是否隐藏
创建删除功能:
-
public boolean createNewFile() :创建文件。若文件存在,则不创建,返回false
-
public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。 如果此文件目录的上层目录不存在,也不创建。
-
public boolean mkdirs() :创建文件目录。如果上层文件目录不存在,一并创建
注意事项:如果你创建文件或者文件目录没有写盘符路径,那么,默认在项目 路径下。
-
public boolean delete():删除文件或者文件夹
删除注意事项:
-
Java中的删除不走回收站。
-
要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录
9.4 实例
// 创建对象
File file = new File("E:/com/a.txt");
// 获取全路径
System.out.println(file.getAbsolutePath());
// 获取文件名,包括扩展名
// 目录只获取目录名字, 如果是文件 则获取文件名+扩展名
System.out.println(file.getName());
// 获取父路径(上级目录)
String parentPath = file.getParent();
System.out.println(parentPath);
// 获取父(上级) 对象
File parentFile = file.getParentFile();
// 判断是否是文件,如果文件不存在,也是false
System.out.println(file.isFile());
// 判断是否是目录
System.out.println(file.isDirectory());
// 获取最后一次修改时间,返回毫秒数
long timer = file.lastModified();
System.out.println(new Date(timer));
// 判断是否存在
System.out.println(file.exists());
// 创建文件,返回布尔型,true,表示创建好了,false表示没有创建
// 只创建文件,不会创建目录
System.out.println(file.createNewFile());
// 删除,成功返回true
System.out.println(file.delete());
File f1 = new File("E:/a/b/c");
// 创建目录,只会创建c,a和b不会创建
System.out.println(f1.mkdir());
// 会创建所有目录
System.out.println(f1.mkdirs());
// 得是目录才行
f1 = new File("E:/a/b/c/d.txt");
// 如果想要创建d.txt对应的目录,不能直接创建,否则会把d.txt也当成目录
// f1.mkdirs();
// 需要先获取父目录,对父目录进行创建
File f2 = f1.getParentFile();
if (!f2.exists()) {
f2.mkdirs();
}
f1.createNewFile();
十.对象流
10.1 概述
创建对象:
-
new 用的最多
-
反射机制
-
clone对象克隆,已过时,被序列化代替
-
反序列化
序列化就是把数据持久化保存在硬盘中,比如堆内存对象,保存到本地文件
反序列化就是把硬盘中序列化的数据,反序列化到内存中
-
对象流,就是以java对象为传输主体的IO过程java对象必须要被序列化后才能进行传输
-
就是把对象转换为二进制数据流的一种实现手段,通过将对象序列化,可以方便的实现对象的传输及保存
-
想要实现序列化,必须实现Serializable接口,该接口没有其他方法功能,仅仅是标记可以被序列化而已
数据-->序列化-->二进制流-->加密处理-->网络传输-->解密处理-->二进制流-->反序列化-->数据
10.2 注意
-
该类必须实现java.io.Serializable接口,否则会抛出
NotSerializableException
。 -
该类的所有字段都必须是可序列化的。如果一个字段不需要序列化,则需要使用
transient
关键字进行修饰。
10.3 序列化
public static void ser(String serPath, Object obj) throws Exception{
FileOutputStream fos = new FileOutputStream(serPath);
BufferedOutputStream bos = new BufferedOutputStream(fos);
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();
oos.close();
}
10.4 反序列化
public static Object unser(String serPath) throws Exception {
FileInputStream fis = new FileInputStream(serPath);
BufferedInputStream bis = new BufferedInputStream(fis);
ObjectInputStream ois = new ObjectInputStream(bis);
Object obj = ois.readObject();
ois.close();
return obj;
}
10.5 serialVersionUID
-
如果不加serialVersionUID每次修改类都会重新生成一个新的
-
该目的就是序列化对象的版本控制,当serialVersionUID对应不上的时候,就会报错
-
如果我们此次修改较小,希望向下兼容,则不需要修改
-
如果我们删除了一个属性,或者更改了类继承等,比如不兼容旧数据,这时候就应该手动更改版本
-
值可以随意指定,只用于对象和类之间的一个绑定关系
private static final long serialVersionUID = 1L;
10.6 Transient
-
transient修饰后,不能被序列化,该属性的值,不会进行序列化存储
-
可以把没必要的字段进行transient修饰,降低序列化文件大小,从而提高反序列化效率
private transient String name;