28.独特流

1.内存流:ByteArrayOutputStream,内存流效率高.内存流关闭无效.
eg:public static void main(String[] args) throws IOException {
//1.创建流对象
ByteArrayOutputStream baos=new ByteArrayOutputStream();
//2.用流对象向内存中写入内容
baos.write(“abdefefefeefefefeffef我是中国人,我爱中国.写个50个字符试试,试试就试试.我爱学习,学习爱我.我想静静,静静是谁”.getBytes());
System.out.println(“内容写入成功”);
//3.关流
baos.close();

	//第一种:获得内存输出流中数据toByteArray()
	byte[] content=baos.toByteArray();	
	String s1=new String(content);
	System.out.println("第一种:"+s1);
	
	//第二种:获得内存输出流中数据toString()
	String s2=baos.toString();
	System.out.println("第二种:"+s2);
	
	//第三种:获得内存输出流中数据,将数据写入到文件中writeTo()
	baos.writeTo(new FileOutputStream("aa"+File.separator+"a1.txt"));
	System.out.println("第三种获得数据写入文件成功");
	
	/*第四种:用内存读取流来读取内存中数据*/
	//创建流对象
	ByteArrayInputStream bais=new ByteArrayInputStream(baos.toByteArray());
	
	//准备一个数组
	byte[] b=new byte[1024];
	//用流对象调用方法读取数据,返回读取的长度,读取的内容存在数组中
	int len;
	while ((len=bais.read(b))!=-1) {
		//将读取的内容转换字符串输出
		String s4=new String(b, 0, len);
		System.out.println(s4);
	}
	System.out.println("第四种读取完毕");
	//关流
	bais.close();
}

2.打印流:
2.1:字节打印流:PrintStream
eg:public static void main(String[] args) {
//声明流对象
PrintStream ps1=null;
try {
//1.创建流对象
ps1=new PrintStream(“aa”+File.separator+“a2.txt”);
//2.用流对象向文件中写入内容
ps1.append(“第一阶段Java注重规范和语法”);
ps1.print(“第二阶段Java注重项目综合能力及调试bug能力”);
ps1.println(“第三阶段Java注重企业级开发,框架使用及团队开发”);
ps1.write(“第四阶段Java注重分布式和微服务开发,注重项目性能”.getBytes());
ps1.printf("%.2f", 3.1415926);
System.out.println(“写入成功!”);
} catch (Exception e) {
e.printStackTrace();
}finally {
//3.关流
if (ps1!=null) {
ps1.close();
}
}
}

2.2:字符打印流:
	eg:public static void main(String[] args) {
	//声明流对象
	PrintWriter pw=null;
	try {
		//1.创建流对象
		pw=new PrintWriter("aa"+File.separator+"a3.txt");
		//2.用流对象向文件中写入内容
		pw.append("第一阶段Java注重规范和语法");
		pw.print("第二阶段Java注重项目综合能力及调试bug能力");
		pw.println("第三阶段Java注重企业级开发,框架使用及团队开发");
		pw.write("第四阶段Java注重分布式和微服务开发,注重项目性能");
		pw.printf("%.2f", 3.1415926);
		pw.printf("%d%%", 50);
		System.out.println("写入成功!");
	} catch (Exception e) {
		e.printStackTrace();
	}finally {
		//3.关流
		if (pw!=null) {
			pw.close();
		}
	}
}

2.3:输出重定向(重新定义一个方向输出):将原来在控制台输出的内容,改变方向,写入到			文件中.
eg:public static void main(String[] args) throws IOException {
	//声明一个存原来打印输出流对象
	PrintStream p1=System.out;
	
	//输出重定向,输出到文件中
	System.setOut(new PrintStream("aa"+File.separator+"a4.txt"));
	//输出内容
	System.out.append("别无我有");
	System.out.print("别有我优");
	System.out.println("无所畏惧");
	System.out.write("别优我精".getBytes());
	System.out.printf("%.3f", 3.141592631415927);
	
	//输出重定向,输出到控制台
	System.setOut(p1);
	System.out.println("今天中午乌云散去了");
	System.out.println("控制台,我又回来了");
}

2.4:输入重定向(重新定义一个方向来接收数据):将原来从控制台接收的数据,改变方向,		从文件中接收数据.

eg:public static void main(String[] args) throws FileNotFoundException {
//声明一个变量存标准输入流
InputStream is=System.in;

	//输入重定向,在文件中接收数据
	System.setIn(new FileInputStream("aa"+File.separator+"a5.txt"));
	
	//创建Scanner类的对象,输入一个输入流作为参数,调用方法从键盘上接收数据
	Scanner input=new Scanner(System.in);
	System.out.println("请输入姓名:");
	String sname=input.next();
	System.out.println("请输入爱好:");
	String shobby=input.next();
	System.out.println("接收姓名为:"+sname+",爱好为:"+shobby);
	
	//输入重定向,在控制台接收数据
	Scanner input2=new Scanner(is);
	System.out.println("请输入一句话:");
	String word=input2.next();
	System.out.println("接收话为:"+word);
}

3.对象流:用来程序间交换数据.
3.1:序列化:将程序(内存)中对象存到磁盘的文件中,叫序列化.
持久化:将内存中短暂存储的数据存长久存储的磁盘上叫持久化.
反序列化:将磁盘上文件中对象读取到程序(内存)中,叫反序列化.
3.2:对象输出流:ObjectOutputStream
注意:对象输出流向文件中写入对象的过程,其实就是序列化.
eg:public static void main(String[] args) throws IOException {
//声明流对象
ObjectOutputStream oos=null;

	try {
		//1.创建流对象
		oos=new ObjectOutputStream(new FileOutputStream("aa"+File.separator+"a6"+File.separator+"a11.txt"));
		/*2.用流向文件中写入对象*/
		
		//第一种:写入字符串对象
		//String word1="先死后活,死去活来";	
		//将字符串对象写入文件中
		//oos.writeObject(word1);
		
		//第二种:写入自定义的对象
		//Student stu1=new Student("赵天慧", 18,"girl");
		//将自定义对象写入文件中
		//oos.writeObject(stu1);
		
		//第三种:写入多个对象存到集合中,再将集合写入到文件中
		//创建一个集合
		List<Student> stuList=new ArrayList();
		stuList.add(new Student("张三", 11, "man"));
		stuList.add(new Student("李四", 21, "man"));
		stuList.add(new Student("王五", 31, "man"));
		//将对象集合写入文件中
		oos.writeObject(stuList);
		
		System.out.println("写入成功");
	} catch (Exception e) {
		e.printStackTrace();
	}finally {
		//3.关流
		if (oos!=null) {
			oos.close();
		}
	}
}
	
3.3:对象输入流:ObjectInputStream
	注意:对象输入流将文件中数据读取到程序中过程,其实就反序列化.
eg:public static void main(String[] args) throws IOException {
	//声明流对象
	ObjectInputStream ois=null;
	
	try {
		//1.创建流对象
		ois=new ObjectInputStream(new FileInputStream("aa"+File.separator+"a6"+File.separator+"a11.txt"));
		/*2.用流来读取文件中对象*/
		
		//第一种:读取一个字符串对象
		//Object word2=ois.readObject();
		//System.out.println("读取的内容为:"+word2);
		
		//第二种:读取写入的自定义的对象
		//Student stu2=(Student) ois.readObject();
		//System.out.println(stu2);
		
		//第三种:读取,写入多个对象存到集合中,再将集合写入到文件中
		List<Student> stulist2=(List<Student>) ois.readObject();
		for (Student stu : stulist2) {
			System.out.println(stu);
		}
		
		System.out.println("读取完毕");
	} catch (Exception e) {
		e.printStackTrace();
	}finally {
		//3.关流
		if (ois!=null) {
			ois.close();
		}
	}
}

3.4:对象输入流读取的方法与对象输出流写入的方法类型要一致,
	否则会报错EOFException.(write数据类型()和read数据类型()这两个方法的数据类型要一致)

3.5:只有实现序列化接口java.io.Serializable接口的类的对象,才能(序列化)用对象输		出流写入到文件中.

3.6:版本号错误:local class incompatible: stream classdesc serialVersionUID = 
		-1243946572963888417, local class serialVersionUID = 3821573340049539149
	操作:先将学生类的一个对象进行序列化(用对象输出流存到文件中),再修改学生类,再将现在的学生类反序				列化取数据,就报版本号错误.
	原因:学生类只实现序列化接口,但是没有因定化序列化版本号,这样学生类每修改一次就会重新产生一个新			的序列化版本号,如果你用原来序列化版本号对应类的对象存的数据,用新的序列化版本号就取不出数			据.
	解决:给每个序列化类固定版本号.

3.7:如果序列化类中属性不想实现序列化,就用static或transient来修饰就可以

3.8:如果想用对象流存多个对象到文件中,可以先将多个对象存在集合中,再把集合存到			文件中.

4.随机流(RandomAccessFile):可读取文件中内容,也可以向文件中写入内容.操作的字节.

断点续传案例:	

eg:public static void main(String[] args) throws IOException {
//声明流对象
RandomAccessFile r=null;
RandomAccessFile w=null;

	try {
		//1.创建流对象
		r=new RandomAccessFile("D:"+File.separator+"1.20181126"+File.separator+"4.上课视频"+File.separator+"28.4对象流.mp4", "r");
		w=new RandomAccessFile("aa"+File.separator+"a6"+File.separator+"a13.mp4", "rw");
		
		//2.获得断点的位置
		Long position=w.length();
		System.out.println("断点位置:"+position);
		//设置流的初始的读写位置
		r.seek(position);
		w.seek(position);
		
		/*3.用流实现文件拷贝*/
		//准备一个数组
		byte[] b=new byte[100];
		//声明一个变量存读取的长度
		int len;
		while ((len=r.read(b))!=-1) {
			//每读取一次就写入一次
			w.write(b, 0, len);
		}
		
		System.out.println("复制成功");
	} catch (Exception e) {
		e.printStackTrace();
	}finally {
		//4.关流
		if (r!=null) {
			r.close();
		}
		if (w!=null) {
			w.close();
		}
	}
}

5.Properties类:properties配置文件类,按key-value存取值
eg:public static void main(String[] args) throws Exception {
//创建配置对象
Properties p1=new Properties();

	//用配置对象调用方法加载配置文件
	p1.load(new InputStreamReader(new FileInputStream("src"+File.separator+"jdbc.properties"), "utf-8"));
	//用配置对象调用方法获得配置文件中值,通过Key得到value
	System.out.println("驱动字符串:"+p1.getProperty("driverUrl"));
	System.out.println("连接字符串:"+p1.getProperty("url"));
	System.out.println("用户名:"+p1.getProperty("username"));
	System.out.println("密码:"+p1.getProperty("password"));
	
	//动态向配置文件对象中写入值,值存在p1对象中
	p1.setProperty("stuName", "吴鹏程");
	
	//用配置对象调用方法获得配置文件中值
	System.out.println("学生姓名:"+p1.getProperty("stuName"));
}

6.(扩展)jdbc结合流存文件和二进制数据到数据库的表中
6.1:存文本文件到数据库的表中:longText
eg:public static void main(String[] args) throws Exception {
//声明连接对象,执行对象,结果集对象
Connection conn=null;
PreparedStatement state=null;
ResultSet rs=null;

	//声明一个变量存要赶往数据库的文本文件
	File f1=new File("aa"+File.separator+"从前有座灵剑山.txt");
	
	try {
		//1.加载驱动
		Class.forName("com.mysql.jdbc.Driver");
		//2.创建连接对象
		conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/myschool","root","root");
		//3.准备Sql语句,?表示占位符,占位符从1开始计数的
		String sql="insert into t_book(bookName,bookContent) values(?,?)";
		System.out.println("***"+sql);
		
		
		//4.创建预编译执行对象,将sql语句编译好
		state=conn.prepareStatement(sql);
		//向sql语句中占位符的位置上传参数,第一个参数是占位符的位置,第二个参数是要传的参数
		state.setString(1, f1.getName());
		state.setCharacterStream(2, new InputStreamReader(new FileInputStream(f1)), (int)f1.length());
		
		//5.用执行对象调用相应的方法将Sql语句传到数据库中去执行,并得到返回结果
		int result=state.executeUpdate();
		//6.处理结果
		if (result>0) {
			System.out.println("插入图书信息成功");
		}else {
			System.out.println("插入图书信息失败");
		}
		
	} catch (Exception e) {
		e.printStackTrace();
	}finally {
		//7.关闭对象,释放资源,先开后关
		if (rs!=null) {
			rs.close();
		}
		if (state!=null) {
			state.close();
		}
		if (conn!=null) {
			conn.close();
		}
	}
}

6.2:读取数据库的表中的文本文件:
	eg:public static void main(String[] args) throws Exception {
	//声明连接对象,执行对象,结果集对象
	Connection conn=null;
	PreparedStatement state=null;
	ResultSet rs=null;
	
	try {
		//1.加载驱动
		Class.forName("com.mysql.jdbc.Driver");
		//2.创建连接对象
		conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/myschool","root","root");
		//3.准备Sql语句,?表示占位符,占位符从1开始计数的
		String sql="select bookName,bookContent from t_book";
		System.out.println("***"+sql);
		
		
		//4.创建预编译执行对象,将sql语句编译好
		state=conn.prepareStatement(sql);
		
		//5.用执行对象调用相应的方法将Sql语句传到数据库中去执行,并得到返回结果
		rs=state.executeQuery();
		//6.处理结果
		while (rs.next()) {
			//获得当前行数据指定列的数据
			String bookName=rs.getString("bookName");

			//用结果集对象调用字符流的方法得到图书内容
			Reader r= rs.getCharacterStream("bookContent");
			//声明一个字符写入流
			Writer w=new OutputStreamWriter(new FileOutputStream("bb"+File.separator+bookName));
			//声明一个数组
			char[] c=new char[100];
			//用流来读取图书内容,边读取边写入
			//声明一个变量存每次读取的长度
			int len;
			while ((len=r.read(c))!=-1) {
				//每读取一次就写入一次
				w.write(c,0,len);
			}
		}
		System.out.println("读取成功!");
	} catch (Exception e) {
		e.printStackTrace();
	}finally {
		//7.关闭对象,释放资源,先开后关
		if (rs!=null) {
			rs.close();
		}
		if (state!=null) {
			state.close();
		}
		if (conn!=null) {
			conn.close();
		}
	}
}

6.3:存二进制数据到数据库的表中:longBlob
	eg:public static void main(String[] args) throws Exception {
	//声明连接对象,执行对象,结果集对象
	Connection conn=null;
	PreparedStatement state=null;
	ResultSet rs=null;
	
	//声明一个变量存要插往数据库的二进制文件
	File f1=new File("aa"+File.separator+"b.jpg");
	
	try {
		//1.加载驱动
		Class.forName("com.mysql.jdbc.Driver");
		//2.创建连接对象
		conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/myschool","root","root");
		//3.准备Sql语句,?表示占位符,占位符从1开始计数的
		String sql="insert into t_image(imgName,imgContent) values(?,?)";
		System.out.println("***"+sql);
		
		//4.创建预编译执行对象,将sql语句编译好
		state=conn.prepareStatement(sql);
		//向sql语句中占位符的位置上传参数,第一个参数是占位符的位置,第二个参数是要传的参数
		state.setString(1, f1.getName());
		//图片参数类型是二进制类型
		state.setBinaryStream(2, new FileInputStream(f1), (int)f1.length());
		
		//5.用执行对象调用相应的方法将Sql语句传到数据库中去执行,并得到返回结果
		int result=state.executeUpdate();
		//6.处理结果
		if (result>0) {
			System.out.println("插入图片信息成功");
		}else {
			System.out.println("插入图片信息失败");
		}
		
	} catch (Exception e) {
		e.printStackTrace();
	}finally {
		//7.关闭对象,释放资源,先开后关
		if (rs!=null) {
			rs.close();
		}
		if (state!=null) {
			state.close();
		}
		if (conn!=null) {
			conn.close();
		}
	}
}

6.4:读取数据库的表中的二进制数据:
	eg:public static void main(String[] args) throws Exception {
	//声明连接对象,执行对象,结果集对象
	Connection conn=null;
	PreparedStatement state=null;
	ResultSet rs=null;
	
	try {
		//1.加载驱动
		Class.forName("com.mysql.jdbc.Driver");
		//2.创建连接对象
		conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/myschool","root","root");
		//3.准备Sql语句,?表示占位符,占位符从1开始计数的
		String sql="select imgName,imgContent from t_image";
		System.out.println("***"+sql);
		
		
		//4.创建预编译执行对象,将sql语句编译好
		state=conn.prepareStatement(sql);
		
		//5.用执行对象调用相应的方法将Sql语句传到数据库中去执行,并得到返回结果
		rs=state.executeQuery();
		//6.处理结果
		while (rs.next()) {
			//获得当前行数据指定列的数据
			String imgName=rs.getString("imgName");

			//用结果集对象调用二进制流的方法得到图片内容
			InputStream r= rs.getBinaryStream("imgContent");
			
			//声明一个字符写入流
			OutputStream w=new FileOutputStream("bb"+File.separator+imgName);
			//声明一个数组
			byte[] b=new byte[100];
			//用流来读取图片内容,边读取边写入
			//声明一个变量存每次读取的长度
			int len;
			while ((len=r.read(b))!=-1) {
				//每读取一次就写入一次
				w.write(b,0,len);
			}
		}
		System.out.println("读取成功!");
	} catch (Exception e) {
		e.printStackTrace();
	}finally {
		//7.关闭对象,释放资源,先开后关
		if (rs!=null) {
			rs.close();
		}
		if (state!=null) {
			state.close();
		}
		if (conn!=null) {
			conn.close();
		}
	}
}

7.装饰者模式:
作用:封装原有类,使其功能更强大.
要实现装饰者模式,注意以下几点内容:
a.装饰者类要实现真实类同样的接口 或继承同样父类.
b.装饰者类内有一个真实对象的引用(可以通过装饰者类的构造器传入)
c.装饰类对象在主类中接受请求,将请求发送给真实的对象(相当于已经将引用传递到了 装饰类的真实对象)
d.装饰者可以在传入真实对象后,增加一些附加功能(因为装饰对象和真实对象都有同样 的方法,装饰对象可 以添 加一定操作在调用真实对象的方法,或者先调用真实 对象的方法,再添加自己的方法)

猜你喜欢

转载自blog.csdn.net/qq_44949002/article/details/119943329