Java 流模型 ---- (下)

目录

 

Java流模型 --- (下)

过滤流类型

桥接转换流

缓冲流

数据流

打印流

对象流


Java流模型 --- (下)

过滤流类型

过滤流就是在节点流的基础上附加功能。

过滤流使用必须有对应的节点流,因为过滤流是装饰节点流,不是有具体的操作目标。
//Java 内置类 FilterInputStream
public class FilterInputStream extends InputStream { // 典型的装饰模式
	protected volatile InputStream in; // 被装饰目标
	protected FilterInputStream(InputStream in) { // 通过构造器组装被装饰对象
		this.in = in;
	}
	public int read() throws IOException {// 调用Filter中的read方法时实际操作是由被装饰对象实现的 
                return in.read(); 
	}
}
       所谓的过滤流实际上就是类似上面的加密处理,在输入之后(后置处理,被装饰对象先执行)或者输出之前(前置处理,先处理然后被装饰对象执行)进行一下额外的处理,最终实际操作是调用被装饰对象的方法完成工作,依靠 这种装饰模式实现在节点流的基础上附加额外功能 . 当然也允许多个过滤流嵌套从而达到功能累加的目的 FilterInputStream 实际上就是一个装饰抽象角色
 
自定义流实现循环13加密:
package IO;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FilterReader;
import java.io.IOException;
import java.io.Reader;

public class D24 {
	public static void main(String[] args) throws IOException {
		Reader a = new JiaMi(new FileReader("C:/Users/苑/Desktop/JAVA_DY/JiaMi.txt"));
		int cc = 0;
		while ((cc = a.read()) != -1) {
			System.out.print((char) cc);

		}
		a.close();
	}

}

class JiaMi extends FilterReader {// 装饰方实例
	protected JiaMi(Reader in) {
		super(in);
	}

	public int read() throws IOException {
		int c = super.read();
		if (c >= 'a' && c <= 'z') {
			c = (c - 'a' + 13) % 26 + 'a';
		} else if (c >= 'A' && c <= 'Z') {
			c = (c - 'A' + 13) % 26 + 'A';
		}
		return c;
	}
}

桥接转换流

  • InputStreamReaderOutputStreamWriter提供了字节流和字符流之间的桥接转换功能。
  • 用于与字节数据到字符数据之间的转换,无需编程实现将字节拼接为字符。
  • 转换流可以在构造时指定其编码字符集。
  • InputStreamReader用于将一个InputStream类型的输入流自动转换为Reader字符流。
  • OutputStreamWriter用于将一个Writer字符输出流转换为OutputStream字节输出流。
package IO;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;

public class D26 {// InputStreamReader用于将一个InputStream类型的输入流自动转换为Reader字符流
	public static void main(String[] args) throws IOException {
		// InputSteram is=new InputStreamReader(System.in,”iso8859-1”);
		Reader a = new InputStreamReader(System.in, "gbk");// System内部类的静态属性 public final static InputStream in = null;
		System.out.println("请在控制台进行输入:");
		int kk = a.read();// InputStreamReader对象 调用read 在控制台读取
		int bb = System.in.read();// 这个是直接用InputStream类型读取
		System.out.println((char) kk);// 只能输出一个字符
		System.out.println((char) bb);// 只能输出一个字节 实际读取的是"中"的一个字节,输出显示为?
	}
}
/*
 * 请在控制台进行输入: 
 * 中国 
 * 中国 
 * 中 
 * ?
 */

缓冲流

  • 缓冲流是套接在响应的节点流之上,对续写的数据提供缓冲的功能
  • 提高读写的效率,同时增加了一些新方法
  • 以介质是硬盘为例,字节流和字符流的弊端:在每一次读写的时候,都会访问硬盘。 如果读写的频率比较高的时候,其性能表现不佳。
  • 为了解决以上弊端,采用缓存流。缓存流在读取的时候,会一次性读较多的数据到缓存中,以后每一次的读取,都是在缓存中访问,直到缓存中的数据读取完毕,再到硬盘中读取。
  • 使用缓冲流并没有添加什么额外方法,只是它能够在执行过程中自动引入缓存,从而提高执行效率 。
构造方法
  • BufferedReader(Reader)不定义缓存大小,默认8192;
  • BufferedReader(Reader in, int size)size为自定义缓冲区的大小;
  • BufferedWriter(Writer) ;
  • BufferedWriter(Writer out, int size)size为自定义缓冲区的大小;
  • BufferedInputStream(InputStream) ;
  • BufferedInputStream(InputStream in, int size)size为自定义缓冲区的大小 ;
  • BufferedOutputStream(OutputStream) ;
  • BufferedOutputStream(OuputStream out, int size)size为自定义缓冲区的大小 ;
缓冲输入流的方法
  • BuffedReader提供了一个方法readLine():String;
  • 但是BufferedInputStream中并没有这个 BufferedReader提供了readLine方法用于读取一行字符串,以\r\n分割(换行符);
  • 如果读取内容为null,则表示读取到了流的末尾 readLine方法会自动剔除本行内容末尾的换行符;
  • BufferedWriter提供了newLine方法用于写入一个行分隔符 ;
  • 对于输出的缓冲流,写入的数据会先在内存中缓存,使用flush方法会使内存中的数据立即写出 。
键盘录入
  • System.in:InputStream用于指代系统默认的输入设备—键盘。
  • 方法read():int 可以实现代码执行到这里则会阻塞等待,只要输入数据为止。
package IO;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class D27 {
	public static void main(String[] args) throws IOException {
		BufferedReader a = new BufferedReader(new InputStreamReader(System.in));
		System.out.println("输入数据:");
		String temp = "";
		while ((temp = a.readLine()).trim().length() > 0) {
			if ("quit".equals(temp))
				break;
			System.out.println(temp);
		}

	}
}
/*
输入数据:
daiyuan'
daiyuan'
sd
sd
quit
*/
package IO;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintStream;

public class D28 {
	public static void main(String[] args) throws IOException {
		BufferedWriter a = new BufferedWriter(new OutputStreamWriter(System.out));// public final static PrintStream out = null;																			
		a.write("只有缓冲区满才自动进行输出显示");
		a.flush(); // 刷新缓冲区,否则看不到输出内容
     	        System.in.read();//控制台输入
		a.close(); // 关闭输出时会首先自动进行刷新缓冲区
	}
}
  • 执行close方法会自动关闭被装饰的对象,所以不需要再关闭FileReaderFileWriter。
  • 执行flush会自动刷新数据到节点流上,但是并没有执行关闭流。针对输出流关闭时会自动先flush缓存再执行关闭。

数据流

DataInputStramDataOutputStream 分别继承自 InputStream OuputStream ,属于过滤流。
需要分别套接在 InputStream OutputStream 类型的节点流上
只有字节流,没有对应的字符流
DataInputStream DataOutputStream 提供了可以存取与机器无关的 Java原始类型数据的方法
DataInputSteram DataOutputStream 构造方法为
  • DataInputStream(InputStream) ;
  • DataOutputStream(OutputStream)。
package IO;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class D29 {//读取、写出一个double数据到文件中
	public static void main(String[] args) throws IOException {
		// 使用数据流就可以直接操作简单类型数据
		double dd = 123.456789;
		FileOutputStream fos = new FileOutputStream("C:/Users/苑/Desktop/JAVA_DY/JAVA2/src/IO/dddd.txt",true);
		fos.write((dd + "  ").getBytes());//  String.getBytes(String decode)方法会根据指定的decode编码返回某字符串在该编码下的byte数组表示:
		fos.close(); 
		
		
	}
}
需要写一个 double ,然后一个 String ,然后再一个 int
需要将输入内容转换为 String ,并且为了区分数据需要引入特殊符号,例如 @@ ,输入数据为 123.456@@shi zxy@@12 。从功能角度上说没问题,但是编码太复杂了,所以引入 Data 类型的输入输出流。
package IO;

import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class D30 {
	public static void main(String[] args) throws IOException {
		// 这里不使用OutputStream定义变量的原因是:需要使用DataOutputStream中定义的特殊方法,而不是父类中 定义的通用方法
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("C:/Users/苑/Desktop/JAVA_DY/JAVA2/src/IO/dddd.txt", true));
		dos.writeDouble(123.456);
		dos.writeChars("!");
		dos.writeInt(12);
		dos.close();
	}
}
package IO;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class D32 {
	public static void main(String[] args) throws IOException {//读取数据判断文件结束EOFException,这里没有-1 在具体应用中建议针对字串使用readUTF和writeUTF
		DataOutputStream dos = new DataOutputStream(new FileOutputStream(("C:/Users/苑/Desktop/JAVA_DY/JAVA2/src/IO/aaaa.txt")));
		dos.writeDouble(6666.66);// 读取数据的前提是必须知道数据的结构
		String str = "我还年轻吃苦趁现在!";
		dos.writeUTF(str);//针对字符串的
		dos.writeInt(99);
		dos.close();
		DataInputStream dis = new DataInputStream(new FileInputStream(("C:/Users/苑/Desktop/JAVA_DY/JAVA2/src/IO/aaaa.txt")));
		double d1 = dis.readDouble();
		String ss = dis.readUTF();//针对字符串的
		int kk = dis.readInt();
		System.out.println(d1 + "\t" + ss + "\t" + kk);
		dis.close();
	}
}

打印流

  • PrintStreamPrintWriter都属于输出流,分别针对字节和字符 ;
  • PrintWriterPrintStream都提供了重载的printprintln方法用于输出多种类型数据 ;
  • print(Object):void。
println表示输出后自动换行
  • PrintWriterPrintStream的输出操作不会抛出异常,用户通过检测错误状态获取错误信息 ;
  • PrintWriterPrintStream有自动的flush功能 textOut.flushBuffer();
  • PrintWriter(Writer) ;
  • PrintWriter(Writer out, boolean autoFlush)自动刷新----println 。

PrintWriter(OutputStream out参数是一个字节流,但是不需要通过桥接处理。

对象流

使用DataInputStream或者DataOutputStream可以读写对象数据,但是操作比较繁琐 。

SUN 提供了 ObjectInputStream/ObjectOutputStream 可以直接将 Object 写入或读出,实际上还有针对 8 种简单类型及其包装类的操作方法,以及针对 String 类型的操作方法 。
  • readObject():Object
  • writeObject(Object):void

读写一个对象的前提是这个类型的对象是可以被序列化的;

对象的序列化的实现方便了对象间的克隆,使得复制品实体的变化不会引起原对象实体的变化。

对象序列化【简单来说就是将对象可以直接转换为二进制数据流】
对象的反序列化【可以将二进制数据流转换为对象】,这一般依靠 JVM 实现
编程中只做声明对象序列化的目标是将对象保存到磁盘中,或允许在网络中直接传 输对象。对象序列化机制允许把内存中的 Java 对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保 存在磁盘上,通过网络将这种二进制流传输到另一个网络节点,其他程序一旦获取到这种二进制流,都可以将这种 二进制流恢复成原来的 Java 对象。
 
  • 如何声明对象所属于的类可以进行序列化和反序列化Serializable/Externalizable接口
  • 其中的接口没有任何定义,仅仅只起到了说明的作用,这种接口叫做标志接口或者旗标接口
  • 可以通过ObjectInputStreamreadObject():Object】和ObjectOutputStreamwriteObject(Object):void提供的方法直接操作对象 。
package IO;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class D33 {
	public static void main(String[] args) throws IOException, IOException, ClassNotFoundException {
		User user = new User();
		user.setId(100);
		user.setUsername("zhangsan");
		user.setPassword("123456");
		//输出对象
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:/Users/苑/Desktop/JAVA_DY/JAVA2/src/IO/abcd.txt",true));
		oos.writeObject(user);
		oos.close();
		// 读取对象
		ObjectInputStream ois = new ObjectInputStream(
				new FileInputStream("C:/Users/苑/Desktop/JAVA_DY/JAVA2/src/IO/abcd.txt"));
		Object temp = ois.readObject();
		if (temp != null && temp instanceof User) {
			User users = (User) temp;
			System.out.println(users);
			ois.close();
		}
	}
}

class User implements Serializable {
	private long id;
	private String Username;
	private String Password;

	public void setId(long l) {
		this.id = l;
	}

	public void setUsername(String string) {
		this.Username = string;
	}

	public void setPassword(String string) {
		this.Password = string;
	}

}
关于对象流的实际应用(用户注册登录)
package IO;

import java.io.IOException;

public interface UseDao {// 接口

	public boolean login(UserBean userBean) throws IOException;// 登录判定

	public void creat(UserBean userBean) throws IOException, ClassNotFoundException;// 创建用戶信息
}
package IO;

import java.io.*;

public class UserDao implements UseDao {
	public boolean login(UserBean userBean) throws IOException {// 登录判定
		ObjectInputStream ob = new ObjectInputStream(new BufferedInputStream(
				new FileInputStream("C:/Users/苑/Desktop/JAVA_DY/JAVA2/src/IO/abcd.txt")));
		boolean flag = false;
		while (true) {
			try {
				Object o = ob.readObject();
				System.out.println(o);
				if (o instanceof UserBean) {
					UserBean u = (UserBean) o;

					if (u.getId().equals(userBean.getId()) && u.getPassword().equals(userBean.getPassword())) {
						flag = true;
						break;
					}
				}
			} catch (Exception e) {
				break;
			}
		}
		ob.close();
		return flag;
	}

	public void creat(UserBean userBean) throws IOException, ClassNotFoundException {// 注册时调用创建
		// ByteArrayOutputStream byo = new ByteArrayOutputStream();
		InputStream inputStream = new FileInputStream("C:/Users/苑/Desktop/JAVA_DY/JAVA2/src/IO/abcd.txt");
		FileOutputStream fileOutputStream = new FileOutputStream(
				"C:/Users/苑/Desktop/JAVA_DY/JAVA2/src/IO/abcd.txt");
		int kk;
		while ((kk = inputStream.read()) > -1) {
			fileOutputStream.write(kk);
		}
		inputStream.close();
		fileOutputStream.close();
		ObjectOutputStream objectOutputStream = new ObjectOutputStream(new BufferedOutputStream(
				new FileOutputStream("C:/Users/苑/Desktop/JAVA_DY/JAVA2/src/IO/abcd.txt", true)));
		objectOutputStream.writeObject(userBean);
		objectOutputStream.close();
	}
}
package IO;

import java.io.BufferedReader;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Serializable;

class UserBean implements Serializable {// 声明对象所属于的类可以进行序列化和反序列化Serializable/Externalizable接口
										// ,接口没有任何定义,仅仅只起到了说明的作用,这种接口叫做标志接口或者旗标接口 。
	private String id; // 私有用户属性
	private String password; // 私有密码属性

	@Override
	public String toString() { // 打印UserBean对象
		return "UserBean{" + "id='" + id + '\'' + ", password='" + password + '\'' + '}';
	}

	public String getId() { // 获取私有id属性
		return id;
	}

	public void setId(String id) { // 设置私有id属性
		this.id = id;
	}

	public String getPassword() { // 获取私有password属性
		return password;
	}

	public void setPassword(String password) { // 设置私有password属性
		this.password = password;
	}
}

public class UserManager {
	private static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
	private static UserDao userDao = new UserDao();// 静态属性

	public static void main(String[] args) throws IOException, ClassNotFoundException {
		while (true) {
			System.out.println("1---登录");
			System.out.println("2---注册");
			String s = bf.readLine();// 缓存流接收一个字符输入
			switch (s) {
			case "1":
				login();// 登陆判定
				break;
			case "2":
				creat();// 用来注册登陆需要的信息
				break;
			case "exit":
				System.exit(0);
				System.out.println("bye~");
			default:
				System.out.println("输入不合法");
			}
		}

	}

	public static void creat() throws IOException, ClassNotFoundException {// 注册方法

		UserBean u = new UserBean();// new 一个UserBean的对象
		u.setId(getString("输入用户名:"));// 调用setId方法给私有属性id赋值 ,调用自定义gerString方法,返回一个bf.readLine();的字符串UserName
		u.setPassword(getString("输入密码"));// 调用setPassword方法给私有属性id赋值 ,调用自定义gerString方法,返回一个bf.readLine();的字符串UserName
		System.out.println(u);
		userDao.creat(u);
	}

	public static void login() throws IOException { // 登录方法
		System.out.println("输入登录的用户名(输入exit退出):");
		while (true) {
			UserBean u = new UserBean();// new 一个UserBean的对象
			String username = bf.readLine();
			if (username.equals("exit")) {
				break;
			}
			u.setId(username); // bf.readLine();方法给对象u的私有属性id赋值
			System.out.println("输入密码:");
			String password = bf.readLine();
			u.setPassword(password);// bf.readLine();方法给对象u的私有属性password赋值

			if (userDao.login(u)) {// 用了UserDao的login方法
				System.out.println("登录成功!");
				break;
			} else {
				System.out.println("登录失败");
			}

		}
	}

	public static String getString(String s) throws IOException {// 获取userName字符串方法
		System.out.println(s);
		while (true) {
			String userName = bf.readLine();
			if (userName.trim().length() > 0 && userName.length() < 21) {
				return userName;
			}
		}
	}
}
/*
 * 1---登录 2---注册 2 输入用户名: dy 输入密码 12138 UserBean{id='dy', password='12138'}
 * 1---登录 2---注册 1 输入登录的用户名(输入exit退出): dy 输入密码: 12138 UserBean{id='dy',
 * password='12138'} 登录成功! 1---登录 2---注册
 */

需要通过对象流读写的对象必须实现了序列化接口,否则java.io.NotSerializableException。

所有的序列化和反序列化操作由 JVM 负责实现。
 
Externalizable 接口定义为 public interface Externalizable extends java.io.Serializable ,这个接口中包含两个方法需要实现 writeExternal 自定义实现对象的序列化, readExternal 自定义实现对象的反序列化。除非特殊需求一般 不使用 Externalizable 接口,因为没有必要自定义。
 
一般针对敏感数据不应该进行序列化操作,针对不需要进行序列操作的属性可以添加一个关键字transient,表示该属性不参与序列化和反序列化操作。
class User implements Serializable {
private String username ;
private transient String password ;
private Role role ; // 因为 Role 没有实现序列化接口,所以写出 user 对象时会有报错NotSerializableException 。处理报错的方法有: 1 、可以给 Role 类定义添加序列接口。 2 、在 role 属性上添加 transient 表示这个属性不序列化处理
}
 
如果某个类的属性类型不是基本类型或者String类型,且没有实现可序列化接口,则该类型属性类是不可序列化。
 
 
 
 
 
 
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值