JavaIO流之字符流

1.字符流

1.1 什么是字符流

字符流是可以直接读写字符的IO流
使用字符流从文件中读取字符时, 需要先读取到字节数据, 然后转为字符.
使用字符流往文件写入字符时, 需要把字符转为字节再写入文件.

1.2 字符流有两大派

Reader和Writer,这两个类是抽象类,一般使用它们的子类
FileReader和FileWrite

FileReader的使用
FileReader 用于读取字符,调用read方法的时候,是读取一个字符
read方法的返回值是int,它是把char 转成int
以后读纯文本文件,使用FileReader这个类
继承关系 :
在这里插入图片描述

注意:
在这里插入图片描述
这是一段思考字符char大小和字符流怎么读取字符的代码:

try (Reader reader = new FileReader("a.txt");
				Writer writer = new FileWriter("E:\\javaEclipse\\面试基础学习\\a\\a.txt");
				InputStream inputStream = new FileInputStream("a.txt");) {
			char[] c = new char[2];
			System.out.println("字符流读取---------");

			System.out.println(reader.read(c));
			System.out.println(c[0]);
			System.out.println(c[1]);
	

			System.out.println("字节流读取---------");

			System.out.println((byte)inputStream.read());
			System.out.println((byte)inputStream.read());
			System.out.println((byte)inputStream.read());
			System.out.println((byte)inputStream.read());
			

			// 测试结果显示:一般情况下 utf-8 一个中文占三字节
			// char类型的字节数应该不只是二个
			// Java中,外码中char使用UTF8的方式编码,一个字符占用1~6个字节

		} catch (IOException e) {

			e.printStackTrace();
		}

测试结果显示:一般情况下 utf-8编码中 一个中文占三字节 一个英文占一个字节
在 GBK,unicode中,中文的字符的字节都是负数,所以知道怎么去读取
比如 一个中文占三个字节 这三个字节显示为负数(补码)

个人猜测:char类型的字节数应该不只是二个
Java中,外码中char使用UTF8的方式编码,一个字符占用1~6个字节

** FileWriter的使用**

原理:writer(String str),str 转成 字符数组 再转成 字节写入文件
(string -> char[] -> char -> byte)等等 都有一个char转字节的过程。
在这里插入图片描述
继承关系 :
在这里插入图片描述

使用字符流的场景

1.使用FileReader读取字符
原理:先读字节,把字节转成字符(byte -> char)

扫描二维码关注公众号,回复: 11106130 查看本文章

2.使用FileWriter写入字符
原理:好比 writer(String str),str 转成 字符数组 再转成 字节写入文件
(string -> char[] -> char -> byte)等等 都有个
如果是读取文本文件,使用FileReader比较好,不考虑乱码问题
如果是写入文本文件,不建议使用FileWriter,直接使用FileOutputStream好一点
因为是字节直接写入文件,不需要过多数据类型转换

字节流读取文件乱码问题

try (Reader reader = new FileReader("a.txt");
				Writer writer = new FileWriter("E:\\javaEclipse\\面试基础学习\\a\\a.txt");
				InputStream inputStream = new FileInputStream("E:\\javaEclipse\\面试基础学习\\a\\b.txt");
				OutputStream outputStream = new FileOutputStream("E:\\javaEclipse\\面试基础学习\\a\\c.txt")) {
			int length;
			// 字符流操作
			// 读取时是一个字符一个字符的操作
			while ((length = reader.read()) != -1) {
				writer.write(length);
				System.out.println((char) length);
			}
			byte[] b = new byte[3];
			// 字节流操作
			// 读取时是一个字节一个字节操作 可能会中文乱码
			// 当中文字节被拆分时 会乱码
			while ((length = inputStream.read(b)) != -1) {
				   outputStream.write(b,0,length);
			      
			      System.out.println(new String(b,0,length));
			}

		} catch (IOException e) {

			e.printStackTrace();
		}
	}

带缓冲的字符流
概述
BufferedReader/BufferedWriter
1.这两个类,内部都一个缓冲区,字符数组
2.br.read()方法,内部会读8192(8
1024)个字符
3.bw.write(),内部会写8192(81024)个字符

BufferedReader的readLine()
这个方法用于每次读取一行数据,不会读取换行(\r\n)

BufferedWriter的newLine()
newLine方法是用于写文件时,添加换行,相当于”\r\n”

// 使用fileReader和fileWriter读写文本数据时 它是按照项目默认的编码来操作的。
		// 比如项目默认utf-8 那么读写编码为utf-8
		try (Reader reader = new FileReader("E:\\javaEclipse\\面试基础学习\\a\\b.txt");
				Writer writer = new FileWriter("C:\\Users\\Administrator\\Desktop\\b.txt");
				BufferedReader bfr = new BufferedReader(reader);
				BufferedWriter bfw = new BufferedWriter(writer);) {
			    int length;
//			 字符流操作
//			 读取时是一个字符一个字符的操作
//			while ((length = reader.read()) != -1) {
//				writer.write(length);
//				System.out.println((char) length);
//			}
			//bfr.read() 内部会读取到一个字符数组中
//		    while((length=bfr.read())!=-1)
//		    {   
//		         
//		    	System.out.println((char)length);
//		    	bfw.write(length);
//		    }
		    //使用readline方法  读取一行数据   不会读取"\r\n"
		    //使用newLine方法   是用于写文件时,添加换行,相当于”\r\n”
		    String  str=null;
		    while((str=bfr.readLine())!=null)
		    {
		    	System.out.println(str);
		    	bfw.write(str);
		    }
		    

		} catch (IOException e) {

			e.printStackTrace();
		}

案例:获取文本上字符出现的次数
ps 回车换行 两个字符 \r \n

// 使用带缓冲的字符流
		try (BufferedReader bufferedReader = new BufferedReader(new FileReader("a.txt"));
				BufferedWriter bufferedWriter = new BufferedWriter(
						new FileWriter("C:\\Users\\Administrator\\Desktop\\b.txt"));

		) {
			Map<Character, Integer> map = new HashMap<Character, Integer>();
			int length;
			// 看似是一字符一字符的读取 实际上是按内置的字符数组读取(字符缓冲)
			while ((length = bufferedReader.read()) != -1) {

				char c = (char) length;
				System.out.println(c);
				if (map.get(c) == null) {
					map.put(c, 1);
				} else {
					map.put(c, map.get(c) + 1);
				}
			}
			// 遍历map
			for (Map.Entry<Character, Integer> entry : map.entrySet()) {
				String str;
				switch (entry.getKey()) {
				case ' ':
					str = "空格 : " + entry.getValue();
					bufferedWriter.write(str);
					bufferedWriter.newLine();
					break;
				case '\r':
					str = "回车 : " + entry.getValue();
					bufferedWriter.write(str);
					bufferedWriter.newLine();
					break;
				case '\n':
					str = "换行 : " + entry.getValue();
					bufferedWriter.write(str);
					bufferedWriter.newLine();
					break;
				case '\t':
					str = "tab : " + entry.getValue();
					bufferedWriter.write(str);
					bufferedWriter.newLine();
					break;

				default:
					str = entry.getKey() + " : " + entry.getValue();
					bufferedWriter.write(str);
					bufferedWriter.newLine();
					break;

				}

			}

		} catch (IOException e) {
			e.printStackTrace();
		}

编码字符流
InputStreamReader与OutputStreamWriter
这两个类用于使用指定的码表读写字符
FileReader是使用默认码表读取文件, 如果需要使用指定码表读取请使用InputStreamReader(字符流,编码表)
FileWriter是使用默认码表写出文件, 如果需要使用指定码表写入请使用OutputStreamWriter(字符流,编码表)

fileWrite与fileReader的默认读写编码

// 使用fileReader和fileWriter读写文本数据时 它是按照项目默认的编码来操作的。
		// 比如项目默认utf-8 那么读写编码为utf-8
		try (Reader reader = new FileReader("E:\\javaEclipse\\面试基础学习\\a\\b.txt");
				Writer writer = new FileWriter("C:\\Users\\Administrator\\Desktop\\b.txt");
				BufferedReader bfr = new BufferedReader(reader);
				BufferedWriter bfw = new BufferedWriter(writer);) {
			int length;
//			 字符流操作
//			 读取时是一个字符一个字符的操作
//			while ((length = reader.read()) != -1) {
//				writer.write(length);
//				System.out.println((char) length);
//			}
			// bfr.read() 内部会读取到一个字符数组中
//		    while((length=bfr.read())!=-1)
//		    {   
//		         
//		    	System.out.println((char)length);
//		    	bfw.write(length);
//		    }
			// 使用readline方法 读取一行数据 不会读取"\r\n"
			// 使用newLine方法 是用于写文件时,添加换行,相当于”\r\n”
			String str = null;
			while ((str = bfr.readLine()) != null) {
				System.out.println(str);
				bfw.write(str);
			}

		} catch (IOException e) {

			e.printStackTrace();
		}

InputStreamReader与OutputStreamWriter的自定义读写编码

// 使用fileReader和fileWriter读写文本数据时 它是按照项目默认的编码来操作的。
		// 比如项目默认utf-8 那么读写编码为utf-8
		try (Reader reader = new FileReader("E:\\javaEclipse\\面试基础学习\\a\\b.txt");
				Writer writer = new FileWriter("C:\\Users\\Administrator\\Desktop\\b.txt");
				BufferedReader bfr = new BufferedReader(reader);
				BufferedWriter bfw = new BufferedWriter(writer);
				InputStream inputStream = new  FileInputStream("E:\\javaEclipse\\面试基础学习\\a\\a.txt");
				OutputStream outputStream =  new FileOutputStream("a.txt");
				 InputStreamReader  inputStreamReader=new InputStreamReader(inputStream,"gbk");
				OutputStreamWriter outputStreamWriter=new  OutputStreamWriter(outputStream,"utf-8")) 
		{
			int  length=0;
			while((length=inputStreamReader.read())!=-1)
			{
				System.out.println((char)length);
				outputStreamWriter.write(length);
			}
					 
		} catch (IOException e) {

			e.printStackTrace();
		}

装饰(Decorator)设计模式

*一、设计模式【一种固定代码风格】
Java中有哪些设计模式
常用设计模式:装饰模式、单例模式、模版模式、适配器模式、代理模式、工厂模式…

二、装饰(Decorator)设计模式
1.装饰模式的概念:
装饰模式是动态的给一个对象添加一些额外的功能,就增加功能来说,装饰模式比生成子类更为灵活。
装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。
装饰模式是创建一个包装对象,也就是使用装饰来包裹真实的对象。
2.装饰模式的实现方式

  1. 装饰对象和真实对象有相同的接口/抽象类。
  2. 装饰对象包含一个真实对象的引用(reference)
  3. 装饰对象的所有方法,内部实现都可以通过真实对象的引用来调用,然后实现自己的功能
    3.适用性
  4. 需要扩展一个类的功能,或给一个类添加附加职责。
  5. 当不能采用生成子类来实现,比如final类
public class Demo01 {
	public static void main(String[] args) {
	/*	BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
		BufferedOutputStream bos;
		BufferedReader br;
		BufferedWriter bw;*/
		
		/*GYFStudent stu = new GYFStudent();
		stu.code();*/
		
		GYFStudent stu = new GYFStudent(new UniversityStudent());
		stu.code();
	}
}

//1.接口
interface Person{
	public void code();
}

//2.接口实现类
final class UniversityStudent implements Person{
	@Override
	public void code() {
		// TODO Auto-generated method stub
		System.out.println("在大学期间学了一点点C语言...");
	}
}
//UniversityStudent可以继承时 使用继承来扩展
/*class GYFStudent extends UniversityStudent{
	@Override
	public void code() {
		// TODO Auto-generated method stub
		super.code();
		System.out.println("在GYF IT EDU 学习Java语言...");
	}
}*/

//装饰类
class GYFStudent implements Person{

   //真实对象
	private UniversityStudent us;
	public GYFStudent(UniversityStudent us){
		this.us = us;
	}	
	//装饰对象的所有方法,内部实现都是通过真实对象的引用来调用,然后实现自己的功能
	@Override
	public void code() {
		us.code();
		System.out.println("在GYF IT EDU 学习Java语言...");
	}	

发布了23 篇原创文章 · 获赞 17 · 访问量 1283

猜你喜欢

转载自blog.csdn.net/qq_41587409/article/details/105370510