Day 28 学习分享 - IO流和递归

1. IO流的概念和应用场景
1.1 什么是流?
流, 本身是一个非常抽象的概念, 以现实生活中水为例, 我们通过管道把A池子的水放到B池子中这个过程就会产生水流, 而主体是水.
1.2 什么是IO流?
IO流 -- 输入(Input)输出(Output)流
IO流可以看做不同储存设备之间的数据交换产生的 数据流

根据流向分类:
	输入流: 把数据从其他设备上读取到内存中的流 
	输出流: 把数据存内存中写出到其他设备上的流
根据数据类型分类:
	字节流: 以字节为单位读写数据的流
	字符流: 以字符为单位读写数据的流
1.3 为什么需要IO流
实际开发中使用较多, 包括文件上传下载, 文件读写等等都会用到IO流
例如:
	一个简单的记事本的打开保存功能
	程序后台把错误日志数据保存到磁盘文件中
1.4 字节流
	一切文件数据在储存时, 都是以二进制数字的形式保存, 传输时也是如此. 所以, [字节流可以传输任意文件数据]. 
1.4.1 字节输出流常用API
void close ()
	:关闭此输出流并释放与此流相关的任何系统资源
void flush ()
	:刷新此输出流并强制任何缓冲的输出字节被写出
void write (byte[] b)
	:将b.length个数的字节从指定的字节数组写入此输出流
void write (byte[] b, int off, int len)
	:将指定的数组从指定下标off开始写入len个个数的字节到此输出流
	
数据追加续写:
public FileOutputStream(String name, boolean append)
	:创建文件输出流以指定的名称写入文件
1.4.2 字节输入流常用API
void close ()
	:关闭此输入流并释放与此流相关的任何系统资源
int read(byte[] b)
	:从输入流中读取一些字节数,并将它们存储到字节数组 b中
1.5 字符流
	当使用字节流读取文本文件时,可能会有一个小问题
	就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储
	所以Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。
1.5.1 字符输入流常用API
void close()
	:关闭此流并释放与此流相关联的任何系统资源。
int read()
	:从输入流读取一个字符。
int read(char[] ch)
	:从输入流中读取一些字符,并将它们存储到字符数组 ch中 
1.5.2 字符输出流常用API
write(int c)
    : 写入单个字符
write(char[] ch)
    : 写入字符数组
void write(char[] ch, int off, int len)
    : 写入字符数组的某一部分,off数组的开始索引,len写的字符个数
void write(String str)
    : 写入字符串
void write(String str, int off, int len)
    : 写入字符串的某一部分,off字符串的开始索引,len写的字符个数
void flush()
    : 刷新该流的缓冲
void close()
    : 关闭此流,但要先刷新它
1.6 缓冲流
	缓冲流,也叫高效流,是对4个基本的FileXxx 流的增强,所以也是4个流,按照数据类型分类:
    1. 字节缓冲流:
    	BufferedInputStream, BufferedOutputStream
    2. 字符缓冲流:
    	BufferedReader, BufferedWriter
public class BufferedDemo {
    public static void main(String[] args) throws FileNotFoundException {
        // 记录开始时间
      	long start = System.currentTimeMillis();
		// 创建流对象
        try (
        	BufferedInputStream bis = new BufferedInputStream(new FileInputStream("JDK8.zip"));
	        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.zip"));
        ){
        // 读写数据
            int b;
            while ((b = bis.read()) != -1) {
                bos.write(b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
		// 记录结束时间
        long end = System.currentTimeMillis();
        System.out.println("缓冲流复制时间:"+(end - start)+" 毫秒");
    }
}
1.7 转换流
什么是转换流?
	在IDEA中,使用FileReader 读取项目中的文本文件
	由于IDEA的设置,都是默认的UTF-8编码,所以没有任何问题
	但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码
	 这时, 就需要用转换流进行编码集转换
1.7.1 InputStreamReader
	转换流java.io.InputStreamReader,是Reader的子类,是从字节流到字符流的桥梁
	它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集
public class ReaderDemo2 {
    public static void main(String[] args) throws IOException {
      	// 定义文件路径,文件为gbk编码
        String FileName = "E:\\file_gbk.txt";
      	// 创建流对象,默认UTF8编码
        InputStreamReader isr = new InputStreamReader(new FileInputStream(FileName));
      	// 创建流对象,指定GBK编码
        InputStreamReader isr2 = new InputStreamReader(new FileInputStream(FileName) , "GBK");
		// 定义变量,保存字符
        int read;
      	// 使用默认编码字符流读取,乱码
        while ((read = isr.read()) != -1) {
            System.out.print((char)read); // ��Һ�
        }
        isr.close();
      
      	// 使用指定编码字符流读取,正常解析
        while ((read = isr2.read()) != -1) {
            System.out.print((char)read);// 大家好
        }
        isr2.close();
    }
}
1.7.2 OutputStreamWriter
	转换流java.io.OutputStreamWriter ,是Writer的子类,是从字符流到字节流的桥梁
	使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。 
public class OutputDemo {
    public static void main(String[] args) throws IOException {
      	// 定义文件路径
        String FileName = "E:\\out.txt";
      	// 创建流对象,默认UTF8编码
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(FileName));
        // 写出数据
      	osw.write("你好"); // 保存为6个字节
        osw.close();
      	
		// 定义文件路径
		String FileName2 = "E:\\out2.txt";
     	// 创建流对象,指定GBK编码
        OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream(FileName2),"GBK");
        // 写出数据
      	osw2.write("你好");// 保存为4个字节
        osw2.close();
    }
}
1.7.3 代码演示
public class TransDemo {
   public static void main(String[] args) {      
    	// 1.定义文件路径
     	String srcFile = "file_gbk.txt";
        String destFile = "file_utf8.txt";
		// 2.创建流对象
    	// 2.1 转换输入流,指定GBK编码
        InputStreamReader isr = new InputStreamReader(new FileInputStream(srcFile) , "GBK");
    	// 2.2 转换输出流,默认utf8编码
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(destFile));
		// 3.读写数据
    	// 3.1 定义数组
        char[] cbuf = new char[1024];
    	// 3.2 定义长度
        int len;
    	// 3.3 循环读取
        while ((len = isr.read(cbuf))!=-1) {
            // 循环写出
          	osw.write(cbuf,0,len);
        }
    	// 4.释放资源
        osw.close();
        isr.close();
  	}
}
2. 递归
2.1 递归概述
递归:
	指在当前方法内调用自己的这种现象
	
递归的分类:
	直接递归:
		方法自身调用自己的方式叫做直接递归
	间接递归:
		A方法调用B方法, B方法调用C方法, C方法调用A方法的方式就叫做间接递归
		
注意事项:
	1. 递归一定要有条件限定, 以保证递归能够停止, 否则会发生栈内存溢出
	2. 虽然有条件限定, 但是递归次数不能太多, 否则也会发生栈内存溢出
	3. 构造方法禁止递归
2.2 代码演示:
public class Demo1 {
	public static void main(String[] args) {
		// a();
		b(1);
	}
	
	/*
	 * 3.构造方法,禁止递归
	 * 编译报错:构造方法是创建对象使用的,不能让对象一直创建下去
	 */
	public Demo01DiGui() {
		//Demo01DiGui();
	}


	/*
	 * 2.在递归中虽然有限定条件,但是递归次数不能太多。否则也会发生栈内存溢出。
	 * 4993
	 * 	Exception in thread "main" java.lang.StackOverflowError
	 */
	private static void b(int i) {
		System.out.println(i);
		//添加一个递归结束的条件,i==5000的时候结束
		if(i==5000){
			return;//结束方法
		}
		b(++i);
	}

	/*
	 * 1.递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出。 Exception in thread "main"
	 * java.lang.StackOverflowError
	 */
	private static void a() {
		System.out.println("a方法");
		a();
	}
}
**计算1 ~ n的和**

**分析**:num的累和 = num + (num-1)的累和,所以可以把累和的操作定义成一个方法,递归调用

public class Demo2 {
	public static void main(String[] args) {
		//计算1~num的和,使用递归完成
		int num = 5;
      	// 调用求和的方法
		int sum = getSum(num);
      	// 输出结果
		System.out.println(sum);
		
	}
  	/*
  	  通过递归算法实现.
  	  参数列表:int 
  	  返回值类型: int 
  	*/
	public static int getSum(int num) {
      	/* 
      	   num为1时,方法返回1,
      	   相当于是方法的出口,num总有是1的情况
      	*/
		if(num == 1){
			return 1;
		}
      	/*
          num不为1时,方法返回 num +(num-1)的累和
          递归调用getSum方法
        */
		return num + getSum(num-1);
	}
}
搜索`D:\aaa` 目录中的`.java` 文件。

**分析**1. 目录搜索,无法判断多少级目录,所以使用递归,遍历所有目录。
2. 遍历目录时,获取的子文件,通过文件名称,判断是否符合条件。

public class Demo3 {
    public static void main(String[] args) {
        // 创建File对象
        File dir  = new File("D:\\aaa");
      	// 调用打印目录方法
        printDir(dir);
    }

    public static void printDir(File dir) {
      	// 获取子文件和目录
        File[] files = dir.listFiles();
      	
      	// 循环打印
        for (File file : files) {
            if (file.isFile()) {
              	// 是文件,判断文件名并输出文件绝对路径
                if (file.getName().endsWith(".java")) {
                    System.out.println("文件名:" + file.getAbsolutePath());
                }
            } else {
                // 是目录,继续遍历,形成递归
                printDir(file);
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值