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

Java学习基础部分【二十一】IO流&字符流其他内容&递归

程序员文章站 2024-03-04 22:27:36
...

目录

 

一.字符流FileReader

1.字符流是什么

2.FileReader

3.案例演示

二.字符流FileWriter

1.FileWriter类的write()方法可以自动把字符转为字节写出

三.字符流的拷贝

1.案例演示

四.什么情况下使用字符流

五.字符流是否可以拷贝非纯文本的文件

六.自定义字符数组的拷贝

1.案例演示

七.带缓冲的字符流

1.概念

2.案例演示

八.readLine()和newLine()方法

1.概念

2.案例演示

九.将文本反转

1.案例演示

十.LineNumberReader

1.概念

2.案例演示

十一.装饰设计模式

1.案例演示

十二.使用指定的码表读写字符

1.概念

2.案例演示

十三.转换流图解

 十四.获取文本上字符出现的次数

1.案例演示

十五.试用版软件

1.案例演示

十六.递归

1.概念

2.案例演示

十七.练习


一.字符流FileReader

1.字符流是什么

  • 字符流是可以直接读写字符的IO流
  • 字符流读取字符,就要先读取到字节数据,然后转为字符.如果要写出字符,需要把字符转为字节再写出.

2.FileReader

  • FileReader类的read()方法可以按照字符大小读取

3.案例演示

public class Demo1_FileReader {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		//demo1();
		FileReader fr = new FileReader("xxx.txt"); //创建输入流对象,关联xxx.txt
		int c;
		
		while((c = fr.read()) != -1) { //将读到的字符赋值给ch,通过项目默认的码表一次读取一个字符
			System.out.print((char)c);      //将读到的字符强转后打印
		}
		
		fr.close();
	}

	public static void demo1() throws FileNotFoundException, IOException {
		FileReader fr = new FileReader("xxx.txt");
		int x = fr.read();
		System.out.println(x);
		char c = (char)x;
		System.out.println(c);
		fr.close();
	}

}

二.字符流FileWriter

1.FileWriter类的write()方法可以自动把字符转为字节写出

public class Demo2_FileWriter {

	public static void main(String[] args) throws IOException {
		FileWriter fw = new FileWriter("yyy.txt");
		fw.write("大家好,基础阶段快接近尾声了,大家要努力,要坚持!!!");
		fw.write(97);
		fw.close();
	}

}

三.字符流的拷贝

1.案例演示

public class Demo3_Copy {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		//demo1();
		//demo2();	
		//demo3();
		BufferedReader br = new BufferedReader(new FileReader("xxx.txt"));
		BufferedWriter bw = new BufferedWriter(new FileWriter("yyy.txt"));
		
		int c;
		while((c = br.read()) != -1) {
			bw.write(c);
		}
		
		br.close();
		bw.close();
	}
	public static void demo2() throws FileNotFoundException, IOException {
		//字符流不能拷贝纯文本的文件
		FileReader fr = new FileReader("图片.jpg");
		FileWriter fw = new FileWriter("copy.jpg");
		
		int c;
		while((c = fr.read()) != -1) {
			fw.write(c);
		}
		
		fr.close();
		fw.close();
	}

	public static void demo1() throws FileNotFoundException, IOException {
		FileReader fr = new FileReader("xxx.txt");
		FileWriter fw = new FileWriter("zzz.txt");
		
		int c;
		while((c = fr.read()) != -1) {
			fw.write(c);
		}
		
		fr.close();
		fw.close();				//Writer类中有一个2k的小缓冲区,如果不关流,就会将内容写到缓冲区里,关流会将缓冲区内容刷新,再关闭
	}

}

四.什么情况下使用字符流

  • 字符流也可以拷贝文本文件,但不推荐使用.因为读取时会把字节转为字符,写出时还要把字符转回字节.
  • 程序需要读取一段文本,或者需要写出一段文本的时候可以使用字符流
  • 读取的时候是按照字符的大小读取的,不会出现半个中文
  • 写出的时候可以直接将字符串写出,不用转换为字节数组

五.字符流是否可以拷贝非纯文本的文件

不可以拷贝非纯文本的文件
因为在读的时候会将字节转换为字符,在转换过程中,可能找不到对应的字符,就会用?代替,写出的时候会将字符转换成字节写出去如果是2,直接写出,这样写出之后的文件就乱了,看不了了

六.自定义字符数组的拷贝

1.案例演示

public class Demo3_Copy {
	public static void main(String[] args) throws IOException {
		
		FileReader fr = new FileReader("xxx.txt");    //创建字符输入流,关联aaa.txt
		FileWriter fw = new FileWriter("yyy.txt");    //创建字符输出流,关联bbb.txt
		
		char[] arr = new char[1024];                //创建字符数组
		int len;
		while((len = fr.read(arr)) != -1) {			//将文件上的数据读取到字符数组中
			fw.write(arr,0,len);					//将字符数组中的数据写到文件上
		}
		
		fr.close();	                                //关流释放资源
		fw.close();
	}
}

七.带缓冲的字符流

1.概念

  • BufferedReader的read()方法读取字符时会一次读取若干字符到缓冲区,然后逐个返回给程序,降低读取文件的次数,提高效率
  • BufferedWriter的write()方法写出字符时会先写到缓冲区,缓冲区写满时才会写到文件,降低写文件的次数,提高效率

2.案例演示

public class Demo4_Buffered {
	public static void main(String[] args) throws IOException {
		//demo1();
		BufferedReader br = new BufferedReader(new FileReader("zzz.txt"));
		BufferedWriter bw = new BufferedWriter(new FileWriter("aaa.txt"));
		
		String line;
		while((line = br.readLine()) != null) {
			bw.write(line);
			//bw.newLine();							//写出回车换行符
			//bw.write("\r\n");
		}
		
		br.close();
		bw.close();
	}

	public static void demo1() throws FileNotFoundException, IOException {
		BufferedReader br = new BufferedReader(new FileReader("zzz.txt"));
		String line;
		
		while((line = br.readLine()) != null) {
			System.out.println(line);
		}
		
		br.close();
	}

}

八.readLine()和newLine()方法

1.概念

  • BufferedReader的readLine()方法可以读取一行字符(不包含换行符号)
  • Buffereduriter的newLine()可以输出一个跨平台的换行符号“\r\n"

2.案例演示

public class Demo4_Buffered {
	public static void main(String[] args) throws IOException {
		//demo1();
		BufferedReader br = new BufferedReader(new FileReader("zzz.txt"));
		BufferedWriter bw = new BufferedWriter(new FileWriter("aaa.txt"));
		
		String line;
		while((line = br.readLine()) != null) {
			bw.write(line);                        	//跨平台的
			//bw.newLine();							//写出回车换行符
			//bw.write("\r\n");                    //只支持windows系统
		}
		
		br.close();
		bw.close();
	}

	public static void demo1() throws FileNotFoundException, IOException {
		BufferedReader br = new BufferedReader(new FileReader("zzz.txt"));
		String line;
		
		while((line = br.readLine()) != null) {
			System.out.println(line);
		}
		
		br.close();
	}

}

九.将文本反转

 将一个文本文档上的文本反转,第一行和倒数第一行交换,第二行和倒数第二行交换

1.案例演示

public class Test1 {

	/**
	 * @param args
	 * 将一个文本文档上的文本反转,第一行和倒数第一行交换,第二行和倒数第二行交换
	 * 
	 * 分析:
	 * 1,创建输入输出流对象
	 * 2,创建集合对象
	 * 3,将读到的数据存储在集合中
	 * 4,倒着遍历集合将数据写到文件上
	 * 5,关流
	 * @throws IOException 
	 * 
	 * 注意事项:
	 * 流对象尽量晚开早关
	 */
	public static void main(String[] args) throws IOException {
		//改写后是尽量晚开早关
		// 1,创建输入输出流对象
		BufferedReader br = new BufferedReader(new FileReader("zzz.txt"));
		
		//2,创建集合对象
		ArrayList<String> list = new ArrayList<>();
		//3,将读到的数据存储在集合中
		String line;
		while((line = br.readLine()) != null) {
			list.add(line);
		}
		br.close();											//关流
		
		//4,倒着遍历集合将数据写到文件上
		BufferedWriter bw = new BufferedWriter(new FileWriter("revzzz.txt"));
		for(int i = list.size() - 1; i >= 0; i--) {
			bw.write(list.get(i));
			bw.newLine();
		}
		//5,关流
		
		bw.close();
	}

}

十.LineNumberReader

1.概念

 LineNumberReader是BufferedReader的子类, 具有相同的功能, 并且可以统计行号

  • 调用getLineNumber()方法可以获取当前行号
  • 调用setLineNumber()方法可以设置当前行号

2.案例演示

public class Demo5_LineNumberReader {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		LineNumberReader lnr = new LineNumberReader(new FileReader("zzz.txt"));
		
		String line;
		lnr.setLineNumber(100);                                //设置行号
		while((line = lnr.readLine()) != null) {
			System.out.println(lnr.getLineNumber() + ":" + line);//获取行号
		}
		
		lnr.close();
	}

}

十一.装饰设计模式

1.案例演示

public class Demo6_Wrap {

	/**
	 * @param args
	 * 装饰设计模式的好处是:
	 * 耦合性不强,被装饰的类的变化与装饰类的变化无关
	 */
	public static void main(String[] args) {
		HeiMaStudent hms = new HeiMaStudent(new Student());
		hms.code();
	}

}

interface Coder {
	public void code();
}

class Student implements Coder {

	@Override
	public void code() {
		System.out.println("javase");
		System.out.println("javaweb");
	}
	
}

class HeiMaStudent implements Coder {
	//1,获取被装饰类的引用
	private Student s;						//获取学生引用
	
	//2,在构造方法中传入被装饰类的对象
	public HeiMaStudent(Student s) {
		this.s = s;
	}

	//3,对原有的功能进行升级
	@Override
	public void code() {
		s.code();
		System.out.println("ssh");
		System.out.println("数据库");
		System.out.println("大数据");
		System.out.println("...");
	}
}

十二.使用指定的码表读写字符

1.概念

  • FileReader是使用默认码表读取文件,如果需要使用指定码表读取,那么可以使用InputStreamReader(字节流,编码表)
  • Filewriter是使用默认码表写出文件,如果需要使用指定码表写出,那么可以使用outputStreamuriter(字节流,编码表)

2.案例演示

public class Demo7_TransIO {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		//demo1();
		//demo2();
		BufferedReader br = 								//更高效的读
				new BufferedReader(new InputStreamReader(new FileInputStream("utf-8.txt"), "utf-8"));
		BufferedWriter bw = 								//更高效的写
				new BufferedWriter(new OutputStreamWriter(new FileOutputStream("gbk.txt"), "gbk"));
		int c;
		while((c = br.read()) != -1) {
			bw.write(c);
		}
		
		br.close();
		bw.close();
	}

	public static void demo2() throws UnsupportedEncodingException,
			FileNotFoundException, IOException {
		InputStreamReader isr = new InputStreamReader(new FileInputStream("utf-8.txt"), "uTf-8");	//指定码表读字符
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"), "gbk");	//指定码表写字符
		
		int c;
		while((c = isr.read()) != -1) {
			osw.write(c);
		}
		
		isr.close();
		osw.close();
	}

	public static void demo1() throws FileNotFoundException, IOException {
		//用默认编码表读写,出现乱码
		FileReader fr = new FileReader("utf-8.txt");				
		FileWriter fw = new FileWriter("gbk.txt");
		
		int c;
		while((c = fr.read()) != -1) {
			fw.write(c);
		}
		
		fr.close();
		fw.close();
	}

}

十三.转换流图解

Java学习基础部分【二十一】IO流&字符流其他内容&递归

 十四.获取文本上字符出现的次数

 获取一个文本上每个字符出现的次数,将结果写在times.txt上

1.案例演示

public class Test2 {

	/**
	 * @param args
	 * 获取一个文本上每个字符出现的次数,将结果写在times.txt上
	 * 
	 * 1,创建带缓冲区的输入流对象
	 * 2,创建双列集合对象,目的是把字符当作键,把字符出现的次数当作值
	 * 3,通过读取不断向集合中存储,存储的时候要判断,如果不包含这个键就将键和值为1存储,如果包含就将键和值加1存储
	 * 4,关闭输入流
	 * 5,创建输出流对象
	 * 6,将结果写出
	 * 7,关闭输出流
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		//1,创建带缓冲区的输入流对象
		BufferedReader br = new BufferedReader(new FileReader("zzz.txt"));
		//2,创建双列集合对象,目的是把字符当作键,把字符出现的次数当作值
		HashMap<Character, Integer> hm = new HashMap<>();
		//3,通过读取不断向集合中存储,存储的时候要判断,如果不包含这个键就将键和值为1存储,如果包含就将键和值加1存储
		int c;
		while((c = br.read()) != -1) {
			char ch = (char)c;
			/*if(!hm.containsKey(ch)) {
				hm.put(ch, 1);
			}else {
				hm.put(ch, hm.get(ch) +  1);
			}*/
			
			hm.put(ch, !hm.containsKey(ch)? 1 : hm.get(ch) + 1);
		}
		//4,关闭输入流
		br.close();
		//5,创建输出流对象
		BufferedWriter bw = new BufferedWriter(new FileWriter("times.txt"));
		//6,将结果写出
		
		for (Character key : hm.keySet()) {
			bw.write(key + "=" + hm.get(key));
		}
		
		bw.close();
	}

}

十五.试用版软件

当我们下载一个试用版软件,没有购买正版的时候,每执行一次就会提醒我们还有多少次使用机会用学过的IO流知识,模拟试用版软件,试用10次机会,执行一次就提示一次您还有几次机会,如果次数到了提示请购买正版

1.案例演示

public class Test4 {

	/**
	 *  当我们下载一个试用版软件,没有购买正版的时候,每执行一次就会提醒我们还有多少次使用机会用学过的IO流知识,模拟试用版软件,
	 *  试用10次机会,执行一次就提示一次您还有几次机会,如果次数到了提示请购买正版
	 * @throws IOException 
	 * 分析:
	 * 1,创建带缓冲的输入流对象,因为要使用readLine方法,可以保证数据的原样性
	 * 2,将读到的字符串转换为int数
	 * 3,对int数进行判断,如果大于0,就将其--写回去,如果不大于0,就提示请购买正版
	 * 4,在if判断中要将--的结果打印,并将结果通过输出流写到文件上
	 */
	public static void main(String[] args) throws IOException {
		//1,创建带缓冲的输入流对象,因为要使用readLine方法,可以保证数据的原样性
		BufferedReader br = new BufferedReader(new FileReader("config.txt"));
		//2,将读到的字符串转换为int数
		String line = br.readLine();
		int times = Integer.parseInt(line);					//将数字字符串转换为数字
		//3,对int数进行判断,如果大于0,就将其--写回去,如果不大于0,就提示请购买正版
		if(times > 0) {
			//4,在if判断中要将--的结果打印,并将结果通过输出流写到文件上
			System.out.println("您还有" + times-- + "次机会");
			FileWriter fw = new FileWriter("config.txt");
			fw.write(times + "");
			fw.close();
		}else {
			System.out.println("您的试用次数已到,请购买正版");
		}
		//关闭流
		br.close();
	}

}

十六.递归

1.概念

递归:方法自己调用自己

2.案例演示

 5的阶乘

public class Demo8_Digui {

	/**
	 * @param args
	 * 递归:方法自己调用自己
	 * 5!
	 * 5 * 4 * 3 * 2 * 1
	 * 
	 * 5 * fun(4)(代表4!)
	 * 		4 * fun(3)(代表3!)
	 * 				3 * fun(2)(代表2!) 
	 * 						2 * fun(1)(代表1!)
	 * 递归的弊端:不能调用次数过多,容易导致栈内存溢出
	 * 递归的好处:不用知道循环次数
	 * 
	 * 构造方法是否可以递归调用?
	 * 构造方法不能使用递归调用
	 * 
	 * 递归调用是否必须有返回值?
	 * 不一定(可以有,也可以没有)
	 */
	public static void main(String[] args) {
		/*int result = 1;
		
		for(int i = 1; i <= 5; i++) {
			result = result * i;
		}
		
		System.out.println(result);*/
		System.out.println(fun(6000));
	}
	
	public static int fun(int num) {
		if(num == 1) {
			return 1;
		}else {
			return num * fun(num - 1);
		}
	}
}


十七.练习

从键盘输入接收一个文件夹路径,打印出该文件夹下所有的.java文件名

public class Test5 {

	/**
	 * 需求:从键盘输入接收一个文件夹路径,打印出该文件夹下所有的.java文件名
	 * 
	 * 分析:
	 * 从键盘接收一个文件夹路径
	 * 1,如果录入的是不存在,给与提示
	 * 2,如果录入的是文件路径,给与提示
	 * 3,如果是文件夹路径,直接返回
	 * 
	 * 打印出该文件夹下所有的.java文件名
	 * 1,获取到该文件夹路径下的所有的文件和文件夹,存储在File数组中
	 * 2,遍历数组,对每一个文件或文件夹做判断
	 * 3,如果是文件,并且后缀是.java的,就打印
	 * 4,如果是文件夹,就递归调用
	 */
	public static void main(String[] args) {
		File dir = getDir();
		printJavaFile(dir);
	}

	/*
	 * 获取键盘录入的文件夹路径
	 * 1,返回值类型File
	 * 2,不需要有参数
	 */
	public static File getDir() {
		Scanner sc = new Scanner(System.in);				//创建键盘录入对象
		System.out.println("请输入一个文件夹路径");
		while(true) {
			String line = sc.nextLine();					//将键盘录入的文件夹路径存储
			File dir = new File(line);						//封装成File对象
			if(!dir.exists()) {
				System.out.println("您录入的文件夹路径不存在,请重新录入");
			}else if(dir.isFile()) {
				System.out.println("您录入的是文件路径,请重新录入文件夹路径");
			}else {
				return dir;
			}
		}
	}
	/*
	 * 获取文件夹路径下的所.java文件
	 * 1,返回值类型 void
	 * 2,参数列表File dir
	 */
	public static void printJavaFile(File dir) {
		//1,获取到该文件夹路径下的所有的文件和文件夹,存储在File数组中
		File[] subFiles = dir.listFiles();
		//2,遍历数组,对每一个文件或文件夹做判断
		for (File subFile : subFiles) {
			//3,如果是文件,并且后缀是.java的,就打印
			if(subFile.isFile() && subFile.getName().endsWith(".java")) {
				System.out.println(subFile);
			//4,如果是文件夹,就递归调用
			}else if (subFile.isDirectory()){
				printJavaFile(subFile);
			}
		}
	}
}