递归就是“在一个方法内可以再次调用自身”,如下,method方法又调用了method方法。
package cn.demo.digui; public class DiGui { /* * 递归: 方法自己调用自己 . public void fun(){ fun(); } */ public static void main(String[] args) { story(); } static int count = 2; public static void story() { count++; System.out.println("东方红"); System.out.println("太阳升"); System.out.println("中国出了个大醉侠"); System.out.println("他为人民谋幸福 呼儿嗨哟 "); System.out.println(count); story(); } }
上面的程序运行后,控制台会一直打印:调用method();当然,运行不久就会看到JVM抛出“堆栈溢出异常”——它类似于“无限循环”,但它比循环更消耗内存;
堆栈溢出异常如下:
递归方法开始调用后,在内存中会存在多个method方法,每个method方法均会等待它调用的method方法执行完毕,自己才会执行完毕。
2 递归的注意事项
-
递归调用必须要在某个条件下结束,否则就是死递归。
-
递归调用的层次不能太多,否则会堆栈溢出。
-
构造方法不能递归调用
IO概述
回想之前写过的程序,数据都是在内存中,一旦程序运行结束,这些数据都没有了,等下次再想使用这些数据,可是已经没有了。那怎么办呢?能不能把运算完的数据都保存下来,下次程序启动的时候,再把这些数据读出来继续使用呢?其实要把数据持久化存储,就需要把内存中的数据存储到内存以外的其他持久化设备(硬盘、光盘、U盘等)上。
当需要把内存中的数据存储到持久化设备上这个动作称为输出(写)Output操作。
当把持久设备上的数据读取到内存中的这个动作称为输入(读)Input操作。
因此我们把这种输入和输出动作称为IO操作。
1 IO流分类
按照流向分:输入流与输出流,每个IO流对象均要绑定一个IO资源
按照类型分:常以字节流与字符流区分
分类关系如下:
-
字节流
-
字节输入流 InputStream 抽象类
-
FileInputStream 操作文件的字节输入流
-
-
字节输出流 OuputStream 抽象类
-
FileOutputStream 操作文件的字节输出流
-
-
-
字符流
-
字符输入流 Reader抽象类
-
InputStreamReader 输入操作的转换流
-
FileReader 用来操作文件的字符输入流(简便的流)
-
-
字符输出流 Writer抽象类
-
OutputStreamWriter 输出操作的转换流
-
FileWriter 用来操作文件的字符输出流(简便的流)
-
-
-
数据单位:
-
操作字节的流: 字节流 , 任何数据,底层都是字节. (文档,图片,mp3.....)
-
操作字符的流: 字符流 . 只能操作文本文件.
-
-
2 字节流
2.2.1 一切均为字节
在数据传输过程中,一切数据(文本、图像、声音等)最终存储的均为一个个字节,即二进制数字。所以数据传输过程中使用二进制数据可以完成任意数据的传递。
我们向一个文件中存储一定数据(一些数字),如果使用文本方式打开,则会以文本的方式解释数据。如果以视频的方式打开,则会以视频的方式解释数据。音频、可行执行文件等亦是如此。所以,在文件传输过程中,我们要时刻明确,传输的始终为数据。
2.2.2 字节输出流
输出流:OutputStream(抽象类):FileOutputStream(基本输出流)
构造方法:需要绑定IO资源
public FileOutputStream(String name) 创建覆盖写出对象
public FileOutputStream(String name,boolean append) 创建指定是否追加写出对象
其他方法: 写出时,如果没有该文件对象,会自动创建文件对象
-
write(int n):输出一个字节;(使用int替代了byte)
write(byte[] b):输出一个字节数组;
write(byte[] b, int off , int len):输出字节数组的一部分;
flush():刷新此输出流并强制写出所有缓冲的输出字节;
close(): 由于每个IO流都需要绑定一个IO资源,在使用时,需要回收资源
3 FileOutputStream类,文件输出流
OutputStream有很多子类,其中子类FileOutputStream可用来写入数据到文件。
FileOutputStream类,即文件输出流,是用于将数据写入 File的输出流。
2 FileOutputStream类写入数据到文件中
-
将数据写到文件中,代码演示如下:
package cn.demo.digui; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; public class Demo2 { public static void main(String[] args) throws IOException { // 需求:将数据写入到文件中。 // 创建存储数据的文件。 File file = new File("D:\\FileDemo\\01.txt"); // 创建一个用于操作文件的字节输出流对象。一创建就必须明确数据存储目的地。 // 输出流目的是文件,会自动创建。如果文件存在,则覆盖。 FileOutputStream fos = new FileOutputStream(file); // 调用父类中的write方法。 byte[] data = "我是中国人".getBytes(); fos.write(data); // 关闭流资源。 fos.close(); } }
-
输出结果如下:
4 给文件中续写和换行
我们直接new FileOutputStream(file)这样创建对象,写入数据,会覆盖原有的文件,那么我们想在原有的文件中续写内容怎么办呢?
继续查阅FileOutputStream的API。发现在FileOutputStream的构造函数中,可以接受一个boolean类型的值,如果值true,就会在文件末位继续添加。
package cn.demo.digui; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class Demo3 { public static void main(String[] args) throws IOException { // fun(); fun2(); // 追加数据 // 创建存储数据的文件。 File file = new File("D:\\FileDemo\\02.txt"); // 创建流对象 FileOutputStream fos = new FileOutputStream("D:\\FileDemo\\02.txt", true); // true // 表示可以追加 // 写出数据 fos.write(65); // 关闭 资源 fos.close(); } private static void fun2() throws FileNotFoundException, IOException { //1.创建流对象 FileOutputStream fos = new FileOutputStream("D:\\FileDemo\\02.txt"); // 2.写出数据 String s = "hello io "; byte[] bytes = s.getBytes(); fos.write(bytes); // 3.关闭流资源 fos.close(); } }
文本复制:这块很重要,在实际开发中,经常用到,在这里只是非常的简单,还请多多练习,
(一个人可以被毁灭,但不能被打败。人生中到处是坎坷,你若不努力,爱情与面包都是别人的成果,对自己加油,不放弃!没有学习计算机的天分,那就只能多多练习)
package cn.demo.digui; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /** * 复制文本与图片 */ public class CopyPhoto { public static void main(String[] args) throws IOException { // 1,明确源和目的。复制文本 File srcFile = new File("D:\\FileDemo\\02.txt");// D:\\FileDemo\\02.txt File destFile = new File("D:\\FileDemo\\copyTest.txt"); // 复制图片 // File srcFile = new // File("D:\\FileDemo\\008.png");//D:\\FileDemo\\008.png // File destFile = new File("D:\\FileDemo\\copyTest.png"); // 2,明确字节流 输入流和源相关联,输出流和目的关联。 FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(destFile); // 3, 使用输入流的读取方法读取字节,并将字节写入到目的中。 int ch = 0; while ((ch = fis.read()) != -1) { fos.write(ch); } // 4,关闭资源。 fos.close(); fis.close(); } }
输出结果如下图所示:
上述代码输入流和输出流之间是通过ch这个变量进行数据交换的。
上述复制文件有个问题,每次都从源文件读取一个,然后在写到指定文件,接着再读取一个字符,然后再写一个,一直这样下去。效率极低。
临时数组方式复制文件
上述代码复制文件效率太低了,并且频繁的从文件读数据,和写数据,能不能一次多把文件中多个数据都读进内容中,然后在一次写出去,这样的速度一定会比前面代码速度快。
package cn.demo.digui; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /** * 复制文本与图片 */ public class CopyPhoto2 { public static void main(String[] args) throws IOException { // 1,明确源和目的。复制文本, File srcFile = new File("D:\\FileDemo\\03.txt");// D:\\FileDemo\\02.txt //创建文件,如果文件不存在,创建true,如果文件存在,则创建false,如果文件路径错误,IOException. //判断03.txt是否存在 boolean b1 = srcFile.exists(); System.out.println("b1="+b1); //创建03.txt文本 boolean b2 = srcFile.createNewFile(); System.out.println("b2="+b2); //复制的路径 File destFile = new File("D:\\FileDemo\\copyTest3.txt"); // 复制图片 // File srcFile = new // File("D:\\FileDemo\\008.png");//D:\\FileDemo\\008.png // File destFile = new File("D:\\FileDemo\\copyTest.png"); // 2,明确字节流 输入流和源相关联,输出流和目的关联。 FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(destFile); /*// 3, 使用输入流的读取方法读取字节,并将字节写入到目的中。 int ch = 0; while ((ch = fis.read()) != -1) { fos.write(ch); }*/ //3.1定义一个缓冲区。 byte[] buf = new byte[1024]; int len = 0; while ((len = fis.read(buf)) != -1) { fos.write(buf, 0, len);// 将数组中的指定长度的数据写入到输出流中,buf 表示 存数据的数组, 0 表示开始的位置, len 有效字符个数 } // 4,关闭资源。 fos.close(); fis.close(); } }
本文来自博客园,作者:大码王,转载请注明原文链接:https://www.cnblogs.com/huanghanyu/