javaIO流
一、IO流的分类
- 按照数据流向,可分为输入流和输出流,输入流读取数据,输出流写入数据。
- 按照读取的数据类型,可分为字节型流和字符型流,字节流操作的最小数据单元是8位的字节,字符流操作的最小数据单元是16位的字符。
- 按照处理功能,可分为节点流和处理流,节点流直接从IO设备或文件等读取或写入数据,也称为低级流,处理流是对节点流的封装,使用装饰者模式,提供了更为丰富便捷的读取方法,不直接操作IO设备及文件等,提高io读写的效率。
二、java IO流类
IO流抽象基类:
字节流基类:InputStream ,OutputStream
字符流基类:Reader,Writer
字节节点输入流:FileInputStream、ByteArrayInputStream、PipedInputStream
字节节点输出流:FileOutPutStream、ByteArrayInputStream、PipedInputStream
字节处理输入流:BufferedInputStream、ObjectInputStream、DataInputStream
字节处理输出流:BufferedOutPutStream、ObjectOutPutStream、DataInputSteam
字符节点输入流:FileReader、CharArrayReader、PipedReader
字符节点输出流:FileWriter、CharArrayWriter、PipedWriter
字符处理输入流:BufferedReader、InputStreamReader
字符处理输出流:BufferedWriter、OutputStreamWriter
节点流一般对文件、数组、管道等进行操作
处理流包括:缓冲流、转换流、对象流等
缓冲流的作用:程序与磁盘交互很慢,节点流每次读写一个数据单元交互一次,效率较低。缓冲流提供一定容量的缓存,将读写的数据存入缓存,当缓存满时再与磁盘交互,增加了每次交互的数据量,减少交互的次数,提高了读写的效率。
转换流的作用:将字节流转换成字符流
对象流的作用(ObjectInputStream/ObjectOutputStream):实现对象的序列化与反序列化
DataInputStream/DataOutputStream:读取/写入基本类型和字符串
1.IO流基本方法
字节流InputStream方法:
int code = read(); 读取一个字节,返回字节的code码
int count = read(byte[] bytes); 读取若干个字节存入数组中,返回有效字节个数
read(byte[] b, int off, int len);读取最多 len 个字节,存储到 b 中,从偏移量 off 开始的位置。返回值是实际读取的字节数,如果已到达流的末尾,则返回 -1
close() 关闭流
字节流OutputStream方法:
write(int code ); 将code对应的字符写入文件
write(byte[] bytes); 将数组中的全部字节写入文件
write(byte[] b, int off, int len);将指定数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
flush();刷新流缓冲
close();关闭流
字符流Reader方法:
read() 返回字符code
read(char[] ch) 读取若干存入数组,返回有效字符个数
read(char[] ch, int off, int len) : 将字符读入数组的某一部分。
close()关闭流
字符流Writer方法:
write(int code ); 将code对应的字符写入文件
write(char[] bytes); 将数组中的全部字节写入文件
write(char[] b, int off, int len);将指定数组中从偏移量 off 开始的 len 个字符写入此文件输出流。
flush();刷新流缓冲
close();关闭流
字符缓冲流特有的两个方法:
BufferedWriter类:newLine();写入一个行分隔符。这个方法会自动适配所在系统的行分隔符。
BufferedReader类: readLine();读取一个文本行。
2.对象的序列化与反序列化
对象的序列化(Serialization)是指将对象转换为字节流的过程,以便于存储到文件或通过网络传输。
反序列化(Deserialization)则是将字节流转换回对象的过程。
1.对象实现serializable接口
2.使用ObjectOutputStream 和 ObjectInputStream 类来实现对象的序列化和反序列化
Person类:
import java.io.Serializable;
public class Person implements Serializable {
private long serialVersionUID = -440948515215806089L;
private String name;
private int age;
public Person(){}
public Person(String name,int age){
this.name=name;
this.age=age;
}
public String toString(){
return "{"+this.name+","+this.age+"}";
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
public void eat(){
System.out.println(this.name+"的吃饭方法");
}
}
序列化并存储到test.txt文件
public static void main(String[] args){
try {
//将对象直接记录在文件中
//对象的序列化
Person p1 = new Person("zhangsan",18);
//对象输出流
FileOutputStream fos = new FileOutputStream("test.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);//高级流
oos.writeObject(p1);//将对象拆分成字节碎片 序列化到文件里
oos.flush();
oos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
执行结果
对象反序列化
public static void main(String[] args){
//需要一个对象输入流
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("test.txt"));
Person p = (Person)ois.readObject();
System.out.println(p);
p.eat();//EOFException说明没有对象 通常会将所有记录的对象存在一个集合
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
}
执行结果:
3.文件流应用
文件流构造方法
FileInputStream(File file );
FileInputStream(String fileName);
FileReader(File file);
FileReader(String name);
FileOutPutStream(File file);
FileOutputStream(String fileName);
FileWriter(File file);
FileWriter(String fileName);
此外上述构造方法均有带两个参数的重载,第二个参数为booleanl类型,表示是否追加,不追加则写时覆盖原文件内容
需求简单介绍:
小系统目前已实现登录注册修改用户信息留言等功能,但是数据并未持久化存储,总是需要先进行注册才能进行登录。
改进:
可将用户信息存入文件中,系统初始化时读取文件中的用户信息,注册时将用户信息写入文件,修改用户信息时需要同步修改文件中某一行的信息
用户信息存储在userdata/userdata.properties中
UserService 类中有一个Map类型的属性userMap,存储用户名和用户的映射
创建UserService时需要读取userdata.properties文件,按照一定的规则进行解析,并将解析后的数据存储至userMap中
注册时需要向userMap中添加新用户并将新用户写入文件
修改用户信息时需要修改userMap中的对象并修改文件中对应的某一行
文件内容
系统初始化读取用户信息
public void init(){
FileReader reader = null ;
BufferedReader bfReader = null;
//使用流读取文件
try {
reader = new FileReader("userdata\\userdata.properties");
bfReader = new BufferedReader(reader);
String str ;
while((str = bfReader.readLine())!=null){
String[] kv = str.split("=");
System.out.println("kv.length="+kv.length+"kv[0]="+kv[0]);
String[] userValue =kv[1].split("\\+");
User user = new User(userValue[0],userValue[1],userValue[2],userValue[3]);
//消息列表
if(userValue.length > 4){
String msgList = userValue[4];
String [] msgs = msgList.split(",");
ArrayList<String> list = new ArrayList<>();
for(String s:msgs){
list.add(s);
}
user.setMsgList(list);
}
userMap.put(kv[0],user);
System.out.println(userMap);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if(reader !=null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bfReader != null){
try {
bfReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
注意点:
读取每一行时尽量写成下面的形式,避免多次调用readLine()方法导致读取时部分数据丢失
String line;
while((line = bfReader.readLine())!=null){}
用户进行注册时,将用户信息按照自已定义的规则写入文件中
//注册方法
public String regist(String name , String psw , String repsw ,String tele ,String email ){
String ret =null;
if(name.length()<3 || name.length() > 8){
ret = "账号长度应在3-8之间";
}else if(userMap.containsKey(name)){
ret ="该账户已被注册";
}else if(psw == null ){
ret = "密码不能为空";
} else if( !psw.equals(repsw)){
ret ="两次密码输入不一致";
}else {
User user = new User(name,psw,email,tele);
write("userdata.properties",user);
userMap.put(name,user);
ret = "注册成功";
}
return ret;
}
//向文件写入新用户方法
public void write(String filename ,User user){
FileWriter f = null ;
BufferedWriter writer = null;
try {
f = new FileWriter("userdata\\"+filename,true);
writer = new BufferedWriter(f);
String str = userToString(user);
writer.write(str);
writer.newLine();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(f !=null){
try {
f.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
注意点:
在写入新用户时需要保留原来所有的用户信息,因此在创建FileWriter时指定了是否追加,为true表示追加
更新用户信息时修改文件某一行数据
文件的修改本质上就是将数据重新读出,修改后再写回文件
public void update(String name ,User newUser){
//将user对象转换成文件中存储的格式文本
String replaceTxt =userToString(newUser);
FileReader reader = null ;
BufferedReader bufferedReader = null;
FileWriter writer = null ;
BufferedWriter bufferedWriter = null;
try {
//读取文件暂时存储到list中,遇到目标用户替换文本行
reader = new FileReader("userdata\\userdata.properties");
bufferedReader = new BufferedReader(reader);
List<String> list = new ArrayList<>();
String line;
while((line = bufferedReader.readLine())!=null){
// System.out.println("line ="+line);
if(line.split("=")[0].equals(name)){
list.add(replaceTxt);
}else{
list.add(line);
}
}
// System.out.println("list="+list);
//输出流将list中的文本行写回文件
writer = new FileWriter("userdata\\userdata.properties");
bufferedWriter = new BufferedWriter(writer);
for(String s : list){
bufferedWriter.write(s);
bufferedWriter.newLine();
}
} catch (Exception e) {
e.printStackTrace();
}finally{
//finally中关闭输入和输出流
if(reader != null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bufferedReader != null){
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bufferedWriter != null){
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(writer != null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}