欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

字符流和独特流

程序员文章站 2022-04-10 14:45:51
...

字符流

1.所有字符流都是处理流封装字节流.

2.基本字符流:可以设置字符编码,解决乱码问题.还可以实现内容追加.
2.1:基本字符输入流:Reader->InputStreamReader

		eg:public static void main(String[] args) throws IOException {
		//声明流对象
		InputStreamReader isr=null;
		
		try {
			//1.创建流对象
			isr=new InputStreamReader(new FileInputStream("d:\\从前有座灵剑山.txt"),"utf-8");
			/*2.用流来读取内容*/
			//声明一个数
			char[] c=new char[100];
			//声明一个变量存读取的长度
			int len;
			//边读取边输出,返回读取的长度,读取的内容存在数组中了
			while ((len=isr.read(c))!=-1) {
				//将读取的内容转换字符串输出
				String s1=new String(c, 0, len);
				System.out.println(s1);
			}
			System.out.println("读取成功!");
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			//3.关流
			if (isr!=null) {
				isr.close();
			}
		}
	}

2.2:基本字符输出流:Writer->OutputStreamWriter

	eg:public static void main(String[] args) throws IOException {
		//声明流对象
		OutputStreamWriter osw=null;
		
		try {
			//1.创建流对象,可以实现追加内容,设置编码
			osw=new OutputStreamWriter(new FileOutputStream("aa\\a2.txt",true), "utf-8");
			//2.用流对象向文件中写入内容
			osw.write("我是千锋人");
			osw.append("我爱千锋");
			System.out.println("写入成功");
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			//关流
			if (osw!=null) {
				osw.close();
			}
		}
	}

3.富二代字符流:FileReader,FileWriter,特点:使用方便,不没设置字符编码.

eg:public static void main(String[] args) throws IOException {
		//创建流对象
		FileReader fr=null;
		FileWriter fw=null;
		
		try {
			//1.创建流对象
			fr=new FileReader("d:\\从前有座灵剑山.txt");
			fw=new FileWriter("aa\\a3.txt");
			/*2.用流对象调用方法边读取边写入*/
			//准备一个数组
			char[] c=new char[100];
			//声明变量存读取的长度
			int len;
			//返回读取的长度,读取的内容存到数组中
			while ((len=fr.read(c))!=-1) {
				//将读取写入到文件中
				fw.write(c,0,len);
				//刷新
				fw.flush();
			}
			System.out.println("拷贝成功");
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			//关流
			if (fr!=null) {
				fr.close();
			}
			if (fw!=null) {
				fw.close();
			}
		}
	}
	

4.字符缓冲流
4.1:字符缓冲输出流:BufferedWriter

	public static void main(String[] args) throws IOException {
		//声明流对象
		BufferedWriter bw=null;
		try {
			//1.创建流对象
			//bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("aa\\a4.txt",true), "utf-8"));
			bw=new BufferedWriter(new FileWriter("aa\\a4.txt",true));
			/*2.用流来向文件中写入内容*/
			bw.write("我是\n中国人");
			//换行,有两种方式,一种:\n换行,newLine()换行
			bw.newLine();
			//刷新
			bw.flush();
			//接着写入
			bw.append("我爱中国");
			//换行
			bw.newLine();
			//刷新
			bw.flush();
			System.out.println("写入成功");
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			//关流
			if (bw!=null) {
				bw.close();
			}
		}
	}

4.2:字符缓冲输入流:BufferedReader

	eg:public static void main(String[] args) throws IOException {
		//声明流
		BufferedReader br=null;
		try {
			//1.创建流对象
			//br=new BufferedReader(new InputStreamReader(new FileInputStream("aa\\a4.txt"), "utf-8"));
			br=new BufferedReader(new FileReader("aa\\a4.txt"));
			//2.用流对象一行一行的读取内容,前提写入文件中内容要有换行
			//声明一个变量存每次读取的内容
			String content;
			while ((content=br.readLine())!=null) {
				//读取一行输出一行
				System.out.println(content);
			}
			System.out.println("读取成功");
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			//3.关流
			if (br!=null) {
				br.close();
			}
		}
	}

1.字节流的总结:
字符流和独特流
2.字符流的总结:
字符流和独特流

独特流

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.装饰者可以在传入真实对象后,增加一些附加功能(因为装饰对象和真实对象都有同样 的方法,装饰对象可 以添 加一定操作在调用真实对象的方法,或者先调用真实 对象的方法,再添加自己的方法)

独特流的总结:

字符流和独特流