前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >第二十一天 IO-递归&字节流&字符流【悟空教程】

第二十一天 IO-递归&字节流&字符流【悟空教程】

作者头像
Java帮帮
发布2018-07-26 15:42:33
7050
发布2018-07-26 15:42:33
举报

第二十一天 IO-递归&字节流&字符流【悟空教程】

第21天 IO

第1章 递归

1.1 递归的概念

递归就是“在一个方法内可以再次调用自身”,如下,method方法又调用了method方法。

public class Demo {

public static void main(String[] args) {

method();

}

private static void method() {

System.out.println("调用method()");

method();

}

}

上面的程序运行后,控制台会一直打印:调用method();当然,运行不久就会看到JVM抛出“堆栈溢出异常”——它类似于“无限循环”,但它比循环更消耗内存;

递归方法开始调用后,在内存中会存在多个method方法,每个method方法均会等待它调用的method方法执行完毕,自己才会执行完毕。

/*

* 递归: 方法自己调用自己 .

* public void fun(){

* fun();

* }

*/

public class Demo {

public static void main(String[] args) {

story();

}

static int count = 0;

public static void story() {

count++;

System.out.println("从前有座山");

System.out.println("山里有个庙");

System.out.println("庙里有个老和尚给小和尚讲故事");

System.out.println("讲什么呢? ");

System.out.println(count);

story();

}

}

1.2 递归的注意事项

  • 递归调用必须要在某个条件下结束,否则就是死递归。
  • 递归调用的层次不能太多,否则会堆栈溢出。
  • 构造方法不能递归调用

1.3 算法案例

1.3.1 有些问题可以使用“循环”,也可以使用“递归”解决:求5的阶乘:表示为:1 * 2 * 3 * 4 * 5

  • 使用循环:

public static void main(String[] args) {

int max = 5;

int num = 1;

int result = 1;

while(num <= max){

result *= num;

num++;

}

System.out.println("result = " + result);

}

  • 使用递归:

算法分析:

5! = 5 * 4!;

4! = 4 * 3!;

3! = 3 * 2!;

2!= 2 * 1!;

1! = 1;

先求1的阶乘,再求2的阶乘......求5的阶乘;

代码:

public static void main(String[] args) {

System.out.println("递归结果:" + jieCheng(5));

}

public static int jieCheng(int num){

if(num == 1){

return 1;

}

return num * jieCheng(num - 1);

}

1.4 递归两种方法

递归分为两种,直接递归和间接递归。

直接递归称为方法自身调用自己。间接递归可以A方法调用B方法,B方法调用C方法,C方法调用A方法。

1.4.1 递归的代码演示,计算1-n之间的和,使用递归完成

public class DiGuiDemo {

public static void main(String[] args) {

//计算1~num的和,使用递归完成

int n = 5;

int sum = getSum(n);

System.out.println(sum);

}

public static int getSum(int n) {

if(n == 1){

return 1;

}

return n + getSum(n-1);

}

}

1.4.2 代码执行流程图解

注意:递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出。

在递归中虽然有限定条件,但是递归次数不能太多。否则也会发生栈内存溢出。

1.5 递归打印所有子目录中的文件路径

编写一个方法用来打印指定目录中的文件路径,并进行方法的调用

要求:若指定的目录有子目录,那么把子目录中的文件路径也打印出来

步骤:

  • 1. 指定要打印的目录File对象
  • 2. 调用getFileAll()方法
    • 2.1 获取指定目录中的所有File对象
    • 2.2 遍历得到每一个File对象
    • 2.3 判断当前File 对象是否是目录
      • 判断结果为true,说明为目录,通过递归,再次调用步骤2的getFileAll()方法
      • 判断结果为false,说明是文件,打印文件的路径
  • 代码演示

public class FileDemo2 {

public static void main(String[] args) {

File file = new File("d:\\test");

getFileAll(file);

}

//获取指定目录以及子目录中的所有的文件

public static void getFileAll(File file) {

File[] files = file.listFiles();

//遍历当前目录下的所有文件和文件夹

for (File f : files) {

//判断当前遍历到的是否为目录

if(f.isDirectory()){

//是目录,继续获取这个目录下的所有文件和文件夹

getFileAll(f);

}else{

//不是目录,说明当前f就是文件,那么就打印出来

System.out.println(f);

}

}

}

}

第2章 IO概述

回想之前写过的程序,数据都是在内存中,一旦程序运行结束,这些数据都没有了,等下次再想使用这些数据,可是已经没有了。那怎么办呢?能不能把运算完的数据都保存下来,下次程序启动的时候,再把这些数据读出来继续使用呢?其实要把数据持久化存储,就需要把内存中的数据存储到内存以外的其他持久化设备(硬盘、光盘、U盘等)上。

当需要把内存中的数据存储到持久化设备上这个动作称为输出(写)Output操作。

当把持久设备上的数据读取到内存中的这个动作称为输入(读)Input操作。

因此我们把这种输入和输出动作称为IO操作。

2.1 IO流分类

按照流向分:输入流与输出流,每个IO流对象均要绑定一个IO资源

按照类型分:常以字节流与字符流区分

分类关系如下:

  • 字节流
    • 字节输入流 InputStream 抽象类
      • FileInputStream 操作文件的字节输入流
    • 字节输出流 OuputStream 抽象类
      • FileOutputStream 操作文件的字节输出流
  • 字符流
    • 字符输入流 Reader抽象类
      • InputStreamReader 输入操作的转换流
      • FileReader 用来操作文件的字符输入流(简便的流)
    • 字符输出流 Writer抽象类
      • OutputStreamWriter 输出操作的转换流
      • FileWriter 用来操作文件的字符输出流(简便的流)
  • 数据单位:
    • 操作字节的流: 字节流 , 任何数据,底层都是字节. (文档,图片,mp3.....)
    • 操作字符的流: 字符流 . 只能操作文本文件.

2.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资源,在使用时,需要回收资源

2.2.3 FileOutputStream类

OutputStream有很多子类,其中子类FileOutputStream可用来写入数据到文件。

FileOutputStream类,即文件输出流,是用于将数据写入 File的输出流。

  • 构造方法
2.2.3.1 写出一个字节

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

/*

* 字节输出流

* FileOutputStream(File file) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。

* FileOutputStream(String name) 创建一个向具有指定名称的文件中写入数据的输出文件流。

*

*/

public class Demo2 {

public static void main(String[] args) throws IOException {

//创建 字节输出流 对象.

FileOutputStream fos = new FileOutputStream("aaa.txt");

// 写出数据

fos.write(97);

// 关闭资源 , 必须做.

fos.close();

}

}

2.2.3.2 FileOutputStream类写入数据到文件中
  • 将数据写到文件中,代码演示:

public class FileOutputStreamDemo {

public static void main(String[] args) throws IOException {

//需求:将数据写入到文件中。

//创建存储数据的文件。

File file = new File("c:\\file.txt");

//创建一个用于操作文件的字节输出流对象。一创建就必须明确数据存储目的地。

//输出流目的是文件,会自动创建。如果文件存在,则覆盖。

FileOutputStream fos = new FileOutputStream(file);

//调用父类中的write方法。

byte[] data = "abcde".getBytes();

fos.write(data);

//关闭流资源。

fos.close();

}

}

2.2.4 给文件中续写和换行

我们直接new FileOutputStream(file)这样创建对象,写入数据,会覆盖原有的文件,那么我们想在原有的文件中续写内容怎么办呢?

继续查阅FileOutputStream的API。发现在FileOutputStream的构造函数中,可以接受一个boolean类型的值,如果值true,就会在文件末位继续添加。

  • 构造方法
  • 给文件中续写数据和换行,代码演示:

public class FileOutputStreamDemo2 {

public static void main(String[] args) throws Exception {

File file = new File("c:\\file.txt");

FileOutputStream fos = new FileOutputStream(file, true);

String str = "\r\n"+"fdm";

fos.write(str.getBytes());

fos.close();

}

}

2.2.4.1 写出多个数据&追加数据

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

/*

* 1.创建流对象

* 2.写出数据

* 3.关闭流资源

*

* 当使用流对象 ,写出数据到一个文件时, 原来文件中的内容会被清掉.新的数据 写出.

*

* 为了解决这个问题.

* FileOutputStream(String name, boolean append) 创建一个向具有指定 name 的文件中写入数据的输出文件流。

*/

public class Demo3 {

public static void main(String[] args) throws IOException {

//fun();

//fun2();

//追加数据

//创建流对象

FileOutputStream fos = new FileOutputStream("ccc.txt" , true ); // true 表示可以追加 .

//写出数据

fos.write(65);

// 关闭 资源

fos.close();

}

private static void fun2() throws FileNotFoundException, IOException {

// * 1.创建流对象

FileOutputStream fos = new FileOutputStream("ccc.txt");

// * 2.写出数据

String s = "hello io " ;

byte[] bytes = s.getBytes();

fos.write(bytes);

// * 3.关闭流资源

fos.close();

}

private static void fun() throws FileNotFoundException, IOException {

// 1.创建流对象

FileOutputStream fos = new FileOutputStream("bbb.txt");

// 2.写出数据

fos.write(98);

fos.write(99);

fos.write(100);

fos.write(101);

// 3.关闭流资源

fos.close();

}

}

2.2.5 字节输入流

输入流:InputStream(抽象类):FileInputStream(基本输入流)

构造方法:需要绑定IO资源

public FileInputStream(String name)

其他方法:读取时,返回数据时,使用int替代了byte

int read():读取一个字节, 返回的是字节内容本身,读取到末尾返回-1

int read(byte[] b):读取一个字节数组

close(): 由于每个IO流都需要绑定一个IO资源,在使用时,需要回收资源

2.2.6 FileInputStream类

InputStream有很多子类,其中子类FileInputStream可用来读取文件内容。

FileInputStream 从文件系统中的某个文件中获得输入字节。

  • 构造方法

2.2.7 FileInputStream类读取数据read方法

在读取文件中的数据时,调用read方法,实现从文件中读取数据

2.2.7.1 读取一个字节

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

/*

* 字节输入流

* 构造方法 FileInputStream(String name)

*

* 字节流在读取数据的时候,字节类型的数据会被提升为int类型, 读取到文件结尾,返回 -1.

*/

public class Demo {

public static void main(String[] args) throws IOException {

//fun();

//创建 字节输入流

FileInputStream fis = new FileInputStream("bbb.txt");

// 读取数据

int i = fis.read();

System.out.println((char) i);

i = fis.read();

System.out.println((char) i);

i = fis.read();

System.out.println((char) i);

i = fis.read();

System.out.println((char) i);

i = fis.read();

System.out.println(i);

i = fis.read();

System.out.println(i);

i = fis.read();

System.out.println(i);

i = fis.read();

System.out.println(i);

// 关闭资源

fis.close();

}

private static void fun() throws FileNotFoundException, IOException {

//创建 字节输入流

FileInputStream fis = new FileInputStream("aaa.txt");

// 读取一个字节

int i = fis.read();

System.out.println(i); // i 就表示你读取到数据.

char ch =(char)i; // 基本的类型强制转换.

System.out.println(ch);

// 关闭资源

fis.close();

}

}

2.2.7.2 循环读取文件(读取字节)

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

/*

* 循环读取文件.

*

* 1.创建输入流对象

* 2.读取文件 read

* 3.关闭资源

*/

public class Demo2 {

public static void main(String[] args) throws IOException {

// * 1.创建输入流对象

FileInputStream fis = new FileInputStream("ccc.txt");

// * 2.读取文件 read

//定义 变量.保存读取的字节数据.

int i ;

while ((i=fis.read())!=-1) {

System.out.println((char)i);

}

// * 3.关闭资源

fis.close();

}

}

2.2.8 读取数据read(byte[])方法

在读取文件中的数据时,调用read方法,每次只能读取一个,太麻烦了,于是我们可以定义数组作为临时的存储容器,这时可以调用重载的read方法,一次可以读取多个字符。

2.2.8.1 使用字节数组读取文件

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

/*

* 使用字节数组读取文件. 提高读取的效率

*

* 使用数组读取,每一个都把数据添加到数组中返回, 返回值 len ,表示当前次读取到的有效字符数.

*/

public class Demo3 {

public static void main(String[] args) throws IOException {

// 创建输入流对象

FileInputStream fis = new FileInputStream("aaa.txt");

// 使用字节数组读取.

byte[] b = new byte[2];

int len = fis.read(b); // 每一次读取, 会向 字节数组中,添加2个字节

//打印 读取的数据

System.out.print((char)b[0]);

System.out.println((char)b[1]);

System.out.println(len);

System.out.println("===========");

len = fis.read(b);

System.out.print((char)b[0]);

System.out.println((char)b[1]);

System.out.println(len);

System.out.println("===========");

len = fis.read(b);

System.out.print((char)b[0]);

System.out.println((char)b[1]);

System.out.println(len);

// 关闭资源

fis.close();

}

}

2.2.8.2 len有效字节数组(复制文本文件)

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

/*

* len 有效字节数组 ,

*

*/

public class Demo4 {

public static void main(String[] args) throws IOException {

// 创建流对象

FileInputStream fis = new FileInputStream("aaa.txt");

FileOutputStream fos = new FileOutputStream("aaa2.txt");

// 操作数据

byte[] b = new byte[2]; // 建议 1024的整数倍. 2,4, 8 .

int len; // 有效字节 数. 如果是文件结尾 返回 -1

while (( len = fis.read(b))!=-1) {

fos.write(b , 0 , len); // b 表示 存数据的数组, 0 表示开始的位置, len 有效字符个数

}

// 关闭资源

fos.close();

fis.close();

}

}

2.2.8.3 字节数组复制图片文件

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

/*

* 边读边写,复制文本文件.

*

* 1.创建流对象. 输入和输出流

* 2.操作数据 . 读取数据和写出数据

* 3.关闭资源 . 关两个流.

*/

public class Demo {

public static void main(String[] args) throws IOException {

// copy_txt();

// copy_pic();

// copy_pic2();

// 创建 流对象

FileInputStream fis = new FileInputStream("hi.jpg");

FileOutputStream fos = new FileOutputStream("hi2.jpg");

// 读写数据, 使用 数组 .

byte[] b = new byte[1024];

int len ;

// 循环读取

while ((len = fis.read(b))!=-1) {

fos.write(b, 0, len);

}

// 关闭资源

fos.close();

fis.close();

System.out.println("高效复制完毕");

}

private static void copy_pic2() throws FileNotFoundException, IOException {

FileInputStream fis = new FileInputStream("hi.jpg");

FileOutputStream fos = new FileOutputStream("hi_copy.jpg");

int b;

while ((b = fis.read()) != -1) {

fos.write(b);

}

fos.close();

fis.close();

System.out.println("复制图片完毕");

}

private static void copy_pic() throws FileNotFoundException, IOException {

FileInputStream fis = new FileInputStream("aa.jpg");

FileOutputStream fos = new FileOutputStream("aa_copy.jpg");

int b;

while ((b = fis.read()) != -1) {

fos.write(b);

}

fos.close();

fis.close();

System.out.println("复制图片完毕");

}

private static void copy_txt() throws FileNotFoundException, IOException {

// 创建流对象

FileInputStream fis = new FileInputStream("ccc.txt");

FileOutputStream fos = new FileOutputStream("E:\\ccc.txt");

// 操作数据

int i;

// 读取数据

while ((i = fis.read()) != -1) {

// 写出数据

fos.write(i);

}

// 关闭资源 . 后开先关, 先开后关.

fos.close();

fis.close();

System.out.println("复制文件完毕");

}

}

2.2.9 字节流练习

2.2.9.1 复制文件

原理;读取一个已有的数据,并将这些读到的数据写入到另一个文件中。

public class CopyFileTest {

public static void main(String[] args) throws IOException {

//1,明确源和目的。

File srcFile = new File("c:\\YesDir\test.JPG");

File destFile = new File("copyTest.JPG");

//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这个变量进行数据交换的。

上述复制文件有个问题,每次都从源文件读取一个,然后在写到指定文件,接着再读取一个字符,然后再写一个,一直这样下去。效率极低。

2.2.9.2 临时数组方式复制文件

上述代码复制文件效率太低了,并且频繁的从文件读数据,和写数据,能不能一次多把文件中多个数据都读进内容中,然后在一次写出去,这样的速度一定会比前面代码速度快。

public class CopyFileByBufferTest {

public static void main(String[] args) throws IOException {

File srcFile = new File("c:\\YesDir\test.JPG");

File destFile = new File("copyTest.JPG");

// 明确字节流 输入流和源相关联,输出流和目的关联。

FileInputStream fis = new FileInputStream(srcFile);

FileOutputStream fos = new FileOutputStream(destFile);

//定义一个缓冲区。

byte[] buf = new byte[1024];

int len = 0;

while ((len = fis.read(buf)) != -1) {

fos.write(buf, 0, len);// 将数组中的指定长度的数据写入到输出流中。

}

// 关闭资源。

fos.close();

fis.close();

}

}

2.3 字符流

2.3.1 方便程序员的IO流

在IO开发过程中,我们传输最频繁的数据为字符,而以字节方式传输字符需要每次将字符串转换成字节再处理,而且也丧失了程序员对数据内容的判断(因为程序员只认识字符,不认识字节)。所以,为了让程序员方便对字符进行操作,Java提供了专门以字符作为操作单位的类——字符流,其底层仍然为字节流。

显然,字符流只能操作字符,无法操作其他数据,如声音、视频等。

2.3.2 字符输出流FileWirter

既然有专门用于读取字符的流对象,那么肯定也有写的字符流对象,查阅API,发现有一个Writer类,Writer是写入字符流的抽象类。其中描述了相应的写的动作。

2.3.3 FileWriter类

查阅FileOutputStream的API,发现FileOutputStream 用于写入诸如图像数据之类的原始字节的流。要写入字符流,请考虑使用 FileWriter。

打开FileWriter的API介绍。用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节高效区大小都是可接受的。

  • 构造方法

2.3.4 FileWirter写数据

  • 构造方法
    • FileWriter(String fileName) 传递一个文件名称
  • 成员方法
    • void write(String str) 往文件中写入一个字符串。
    • void flush() 刷新该流的缓冲,把内存缓冲区中的数据刷新到文件中。
    • void close() 关闭此流,但要先刷新它。
  • 输出流写数据的步骤:
    • 1.创建输出流对象
    • 2.调用输出流对象的写数据的方法
    • 3.释放资源

2.3.5 FileWriter写入中文到文件中

  • 写入字符到文件中,先进行流的刷新,再进行流的关闭。

public class Demo01FileWriter {

public static void main(String[] args) throws IOException {

//创建输出流对象

FileWriter fw = new FileWriter("d:\\a.txt");

/*

* 创建输出流对象做了哪些事情:

* A:调用系统资源创建了一个文件

* B:创建输出流对象

* C:把输出流对象指向文件

*/

//调用输出流对象的写数据的方法

//写一个字符串数据

fw.write("IO流你好");

//数据没有直接写到文件,其实是写到了内存缓冲区

fw.flush();

//释放资源

//通知系统释放和该文件相关的资源

fw.close();

//while(true) {}

}

}

2.3.6 FileWriter写数据路径问题及关闭和刷新方法的区别

2.3.6.1 路径:
  • 相对路径:相对当前项目而言的,在项目的根目录下(a.txt)
  • 绝对路径:以盘符开始的路径(d:\\a.txt)
2.3.6.2 close()和flush()方法的区别:

flush():将流中的高效区高效的数据刷新到目的地中,刷新后,流还可以继续使用。

close():关闭资源,但在关闭前会将高效区中的数据先刷新到目的地,否则丢失数据,然后在关闭流。流不可以使用。如果写入数据多,一定要一边写一边刷新,最后一次可以不刷新,由close完成刷新并关闭。

public class Demo02FileWriter {

public static void main(String[] args) throws IOException {

//创建输出流对象

//FileWriter fw = new FileWriter("d:\\a.txt");

FileWriter fw = new FileWriter("a.txt");

//调用输出流对象的写数据方法,并刷新缓冲区

fw.write("helloworld");

fw.flush();

fw.write("java");

fw.flush();

//释放资源

fw.close();

//Stream closed

//fw.write("javaee");

//fw.flush();

}

}

2.3.7 FileWriter写数据的5个方法

  • void write(String str):写一个字符串数据
  • void write(String str,int index,int len):写一个字符串中的一部分数据, index:开始索引,len:写几个
  • void write(int ch):写一个字符数据,这里写int类型的好处是既可以写char类型的数据,也可以写char对应的int类型的值。'a',97
  • void write(char[] chs):写一个字符数组数据
  • void write(char[] chs,int index,int len):写一个字符数组的一部分数据, index:开始索引,len:写几个

public class Demo03FileWriter {

public static void main(String[] args) throws IOException {

//创建输出流对象

FileWriter fw = new FileWriter("b.txt");

//void write(String str):写一个字符串数据

fw.write("abcde");

//void write(String str,int index,int len):写一个字符串中的一部分数据, index:开始索引,len:写几个

fw.write("abcde",0,5);

fw.write("abcde",1,3);

//void write(int ch):写一个字符数据,这里写int类型的好处是既可以写char类型的数据,也可以写char对应的int类型的值。'a',97

fw.write('a');

fw.write(97);

//void write(char[] chs):写一个字符数组数据

char[] chs = {'a','b','c','d','e'};

//fw.write(chs);

//void write(char[] chs,int index,int len):写一个字符数组的一部分数据, index:开始索引,len:写几个

fw.write(chs,0,5);

fw.write(chs,2,3);

//释放资源

fw.close();

}

}

2.3.8 FileWriter写数据之换行和追加写

2.3.8.1 续写问题
  • FileWriter(String fileName, boolean append)
  • 构造放中参数的作用:
    • 第一个参数:写入文件的目的地
    • 第二个参数:append作用

true:可以续写

false:不能续写,覆盖之前的文件

2.3.8.2 换行问题
  • windows:\r\n
  • linux:\n
  • mac:\r
  • 换行符可以写在第一个数据的结尾,也可以写在第二个数据的开头

2.3.9 字符输入流FileReader

2.3.10 FileReader读数据

  • 构造方法
    • FileReader(String fileName) 传递要读取的文件名称
  • 成员方法
  • int read() 读取单个字符并返回
  • int read(char[] cbuf) 一次读取一个字符数组的数据,返回的是实际读取的字符个数
  • 输入流读文件的步骤:
    • 1.创建输入流对象
    • 2.调用输入流对象的读数据方法
    • 3.释放资源

public class Demo01FileReader {

public static void main(String[] args) throws IOException {

//创建输入流对象

//FileReader fr = new FileReader("fr.txt");

FileReader fr = new FileReader("Demo01FileWriter.java");

//调用输入流对象的读数据方法

//int read():一次读取一个字符

int ch;

/*

* while循环的条件表达式一共做了3件事情

* 1:fr.read() 读取一个字符

* 2:ch=fr.read() 把读取的字符赋值给ch

* 3:ch != -1 判断ch是否为-1

*/

while((ch=fr.read())!=-1) {

//System.out.println(ch);

//System.out.println((char)ch);

System.out.print((char)ch);

}

//释放资源

fr.close();

}

}

  • 注意:如果构造方法中的文件不存在,会抛异常
    • java.io.FileNotFoundException: fr.txt (系统找不到指定的文件。)

2.3.11 FileReader类

查阅FileInputStream的API,发现FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader。

打开FileReader的API介绍。用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节高效区大小都是适当的

  • 构造方法

2.3.12 FileReader读取包含中文的文件

  • 使用FileReader读取包含中文的文件

public class CharStreamDemo {

public static void main(String[] args) throws IOException {

//给文件中写中文

writeCNText();

//读取文件中的中文

readCNText();

}

//读取中文

public static void readCNText() throws IOException {

FileReader fr = new FileReader("D:\\test\\cn.txt");

int ch = 0;

while((ch = fr.read())!=-1){

//输出的字符对应的编码值

System.out.println(ch);

//输出字符本身

System.out.println((char)ch);

}

}

//写中文

public static void writeCNText() throws IOException {

FileOutputStream fos = new FileOutputStream("D:\\test\\cn.txt");

fos.write("a奋斗蒙教程".getBytes());

fos.close();

}

}

2.3.12.1 字符流:读取文件,一次读写一个字符

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;

/*

* 字符流 :读取文本文件

*

* 字符输入流 Reader 的子类, FileReader .

*/

public class Demo {

public static void main(String[] args) throws IOException {

//fun();

// 循环读取

FileReader fr = new FileReader("ddd.txt");

int c ;

while (( c = fr.read())!=-1) {

System.out.print((char)c);

}

fr.close();

}

private static void fun() throws FileNotFoundException, IOException {

//创建字符输入流对象

FileReader fr = new FileReader("ddd.txt");

// 读取数据

int c = fr.read(); // 读取一次,返回一个字符.

System.out.println((char)c); //20320 你

c = fr.read();

System.out.println((char)c); //22909 好

c = fr.read();

System.out.println(c);

// 关闭资源

fr.close();

}

}

2.3.12.2 复制文本文件: 一次读写一个字符复制文本文件
  • 操作步骤:
    • 1.创建FileReader对象,并且绑定数据源
    • 2.创建FileWriter对象,并且绑定数据目的地
    • 3.调用FileReader中读取字符的方法read
    • 4.调用FileWriter中写入字符的方法write
    • 5.释放资源

public class Demo01CopyFile {

public static void main(String[] args) throws IOException {

//创建输入流对象

FileReader fr = new FileReader("Demo01FileWriter.java");

//创建输出流对象

FileWriter fw = new FileWriter("Copy.java");

//读写数据

int ch;

while((ch=fr.read())!=-1) {

fw.write(ch);

}

//释放资源

fw.close();

fr.close();

}

}

2.3.12.3 FileReader读数据一次一个字符数组
  • int read(char[] cbuf) 一次读取一个字符数组的数据,返回的是实际读取的字符个数

public class Demo02FileReader {

public static void main(String[] args) throws IOException {

//创建输入流对象

//FileReader fr = new FileReader("fr2.txt");

FileReader fr = new FileReader("FileWriterDemo.java");

//调用输入流对象的读数据方法

//int read(char[] cbuf):一次读取一个字符数组的数据,返回的是实际读取的字符个数

char[] chs = new char[1024]; //这里可以是1024及其整数倍

int len;

/*

* while循环的条件表达式一共做了3件事情

* 1:fr.read(chs) 把数据读取到数组中

* 2:len=fr.read(chs) 把读取的有效个数赋值给len

* 3:len != -1 判断读取的有效个数是否为-1

*/

while((len=fr.read(chs))!=-1) {

System.out.print(new String(chs,0,len));

}

//释放资源

fr.close();

}

}

2.3.12.4 FileReader读取数据的两种方式图解
2.3.12.5 复制文本文件: 一次读写一个字符数组复制文本文件

public class Demo02CopyFile {

public static void main(String[] args) throws IOException {

//创建输入流对象

FileReader fr = new FileReader("Demo01FileWriter.java");

//创建输出流对象

FileWriter fw = new FileWriter("Copy.java");

//读写数据

char[] chs = new char[1024];

int len;

while((len=fr.read(chs))!=-1) {

fw.write(chs, 0, len);

}

//释放资源

fw.close();

fr.close();

}

}

第3章 本日自习作业:

3.1 知识点相关题

3.1.1 知识点:字节输出流FileOutputStream各种方法

题目:

1) 定义类Test1,定义main()方法,按以下要求编写代码:

  • 构造一个FileOutputStream对象,指向项目目录下的test01.txt(文件可以不存在);
  • 向文件中写入:H(调用write(int c)方法)
  • 向文件中写入:e
  • 向文件中写入:l
  • 向文件中写入:l
  • 向文件中写入:o
  • 关闭输出流;
  • 打开文件,查看文件中的内容;
  • 反复多次运行此程序,并且更改一些输出内容,再次查看文件中的内容,发现什么?

2) 定义类Test2,定义main()方法,按以下要求编写代码:

  • 构造一个File对象,指向项目目录下的test02.txt。
  • 使用这个File对象构造一个FileOutputStream对象;
  • 定义一个byte[]数组,里面存储“HelloJava”的每个字符对应的ASCII码值(自己查)
  • 向文件中写入这个数组中的Java部分;(调用write(byte[] b , int off,int len)方法)
  • 关闭输出流;
  • 打开文件,查看文件中的内容;

3) 定义类Test3,定义main()方法,按以下要求编写代码:

  • 使用追加写入的方式构造一个FileOutputStream;
  • 向文件中写入:”你好”(调用write(byte[]) 方法,需要先将String转换为byte[]数组);
  • 向文件中写入:换行符;
  • 向文件中写入:我爱Java
  • 向文件中写入:换行符;
  • 向文件中写入:这是我用字节输出流写入的内容;
  • 向文件中写入:换行符
  • 关闭流
  • 查看文件内容;
  • 多运行几次这个程序,再次查看这个文件;请说明是怎样实现“追加写入”的?

3.1.2 知识点:字节输入流FileInputStream各种方法

题目:

1) 定义类Test4,定义main()方法,按以下要求编写代码:

  • 在项目目录下新建文本文件:test4.txt,里面写入:HelloWorld几个字符 + 换行;
  • 在main()方法中实例化一个FileInputStream对象,指向这个文件;
  • 使用“一次读取一个字节”的方式,循环从文件中读取,并打印读取的字符(需要将读取的字节转换为字符);
  • 关闭输入流;
  • 观察打印结果,程序一共读取了几个字符?

2) 定义类Test5,定义main()方法,按以下要求编写代码:

  • 在项目目录下新建文本文件:test5.txt,里面写入:HelloWorld几个字符 + 换行;
  • 使用这个File对象构造一个FileInputStream对象;
  • 定义一个2个长度的byte[]数组;
  • 使用“一次读取一个字节数组”的方式,循环从文件中读取,并打印读取的字节数组(需要将字节数组转换为String);
  • 关闭输出流;
  • 观察打印结果,程序一共读取了几次?

3.1.3 知识点:使用字节流实现文件复制

题目:

1) 定义类Test6,定义main()方法,按以下要求编写代码:

  • 构造一个字节输入流,指向某个已存在的文件;
  • 构造一个字节输出流,指向一个新位置使用新的文件名;
  • 一次读、写一个字节复制文件;
  • 分别关闭输入、输出流;
  • 复制完毕后,查看新文件。

2) 定义类Test7,定义main()方法,按以下要求编写代码:

  • 构造一个字节输入流,指向某个已存在的文件;
  • 构造一个字节输出流,指向一个新位置使用新的文件名;
  • 一次读、写一个字节数组复制文件;
  • 分别关闭输入、输出流;
  • 复制完毕后,查看新文件。

3.1.4 请写出FileWriter的五种输出的方法;

3.1.5 字符输出流FileWriter操作

定义类Test1,定义main()方法,按以下要求编写代码:

  • 构造一个字符输出流FileWriter,指向项目目录下的test07.txt(此文件不存在)
  • 向文件中写入:”孙悟空”
  • 向文件中写入:换行
  • 关闭流
  • 运行程序,查看文件内容;

3.1.6 请写出FileRader的两种读取的方法;

3.1.7 字符输入流FileReader操作

定义类Test2,定义main()方法,按以下要求编写代码:

  • 构造一个字符输入流:FileReader,指向test07.txt;
  • 使用循环一次读取一个字符,并打印;
  • 关闭流;
  • 运行程序,查看执行结果;

3.1.8 掌握使用字符流复制文件的方式

定义类Test3,定义main()方法,按以下要求编写代码:

  • 构造一个字符输入流,指向某个文件;
  • 构造一个字符输出流,指向某个位置以及使用某个新文件名;
  • 使用一次读、写一个字符的方式复制这个文件;
  • 关闭流;
  • 运行程序,复制完毕,查看复制后的新文件;

3.1.9 使用递归定义方法,求1-N的和

3.1.10 字节流复制文件操作

3.1.11 使用字节流复制一张图片或者音频(不要过大!),请问是否可以使用字符流完成相同操作,为什么?

3.1.12 完成单级文件夹的复制,即:

a文件夹下有多个文件,没有文件夹,将a文件夹中的所有内容,复制到b文件夹中即可。

建议方法声明:

public static void copyDir(File srcDir,File destDir) {

将srcDir文件夹的内容,复制到destDir文件夹中

}

3.1.13 使用递归求斐波那契数列:给定第几项,求该项的值。

3.1.14 复制多级目录,将a文件夹所有内容(包含a文件夹本身),复制到b文件夹中。

注意:a文件夹中还会有2级、3级、n级目录,每级目录内容均要被复制。

3.1.15 使用递归的方式获取这个目录下所有的子目录的名字

定义类,定义main()方法,按以下要求编写代码:

  • 构造一个File对象,指向你D盘的某个目录;
代码语言:javascript
复制
package day10_Test基础练习题;

import java.io.File;

public class Test001 {

/*

 * 7)定义类,定义main()方法,按以下要求编写代码:

l构造一个File对象,指向你D盘的某个目录;

l使用递归的方式获取这个目录下所有的子目录的名字;

 */

public static void main(String[] args) {

File file = new File("D:\\Haozip");

dayin(file);

}

public static void dayin(File file){

File[] files = file.listFiles();

for (File file2 : files) {

if(file2.isDirectory()){

dayin(file2);

}else{

System.out.println(file2);

}

}

}

}

3.2 代码题

3.2.1 求1*2!*3!+...*20!的和

答案:

代码语言:javascript
复制
public class Prog21{

public static void main(String[] args){

long sum = 0;

for(int i=0;i<20;i++)

  sum += factorial(i+1);

System.out.println(sum);

}

//阶乘

private static long factorial(int n){

int mult = 1;

for(int i=1;i<n+1;i++)

  mult *= i;

return mult;

}

}

3.2.2 使用字符流,将一个路径下的文本文件复制到另一路径下;

答案:

代码语言:javascript
复制
public class CopyTextFile {

public static void main(String[] args) throws IOException {

//数据源

String srcPath = "a.txt";

//目的地

String destPath = "b.txt";

method(srcPath,destPath);

}



//字符流: 一次一个字符数组

public static void method(String srcPath, String destPath) throws IOException {

FileReader fr = new FileReader(srcPath);

FileWriter fw = new FileWriter(destPath);

//读

char[] buffer = new char[1024];

int len = 0;

while((len = fr.read(buffer)) != -1){

//写

fw.write(buffer, 0, len);

}

fr.close();

fw.close();

}

}

3.2.3 将100-999(包含)之间的二十个随机数存在集合中,并将集合中是3的倍数的数字存放在文件number.txt中

答案:

代码语言:javascript
复制
public static void main(String[] args) throws IOException {

//创建ArrayList集合

ArrayList<Integer>  arr = new ArrayList<>();

//获取随机数

Random r = new Random();

for (int i = 0; i < 20; i++) {

    int nextInt = r.nextInt(900)+100;

arr.add(nextInt);

}



//遍历获取的随机数并存入number.txt文件中



//1.创建字符输出流,FileWriter;

FileWriter   fw = new FileWriter("number.txt");

//2.遍历符合条件的数据

for (int i = 0; i < arr.size(); i++) {



//判断条件

if(arr.get(i)%3==0){

//

Integer integer = arr.get(i);

fw.write(integer+",");

fw.flush();



}

}

    //关闭流

fw.close();



}

 

3.2.4 获取srcPath.txt文件中“悟空教程_我是一名程序员”(字符串需使用IO流写入)中下划线后面的部分写入destPath.txt文本中

答案:

代码语言:javascript
复制
public static void main(String[] args) throws IOException {

String str = "悟空教程_我是一名程序员";

//将str写入到“srcPath.txt”中,并关流

FileWriter fw = new FileWriter("srcPath.txt");

fw.write(str);

fw.close();

//创建并获取源文件和目的文件路径

FileReader srcPath = new FileReader("srcPath.txt");

FileWriter destPath = new FileWriter("destPath.txt");



//调用copyFile方法

copyFile(srcPath, destPath);



}

public static void copyFile(FileReader srcPath,FileWriter destPath) throws IOException{



char[] ch = new char[1024];



int len = 0;



while((len=srcPath.read(ch))!=-1){

//在索引5取元素,长度为7

destPath.write(ch, 5, 7);



}

//关流

srcPath.close();

destPath.close();

}

3.2.5 使用递归,遍历 1 至100之间的每个数字

代码语言:javascript
复制
package day10_Test拓展三道编程题;

public class Test001 {

//使用递归,遍历 1 至100之间的每个数字

public static void main(String[] args) {

test(100);

}

public static void test(int num){

if(num >= 1){

System.out.println(num);

num--;

test(num);

}

}

}

3.2.6 键盘录入一个路径,如果不是文件夹,并且是.java文件,那么把文件更改为.txt文件

代码语言:javascript
复制
package day10_Test拓展三道编程题;

import java.io.File;

import java.util.Scanner;

public class Test002 {

//键盘录入一个路径,如果不是文件夹,并且是.java文件,那么把文件更改为.txt文件

public static void main(String[] args) {

Scanner sc = new Scanner(System.in);

System.out.println("请输入一个文件路径:");

String path = sc.nextLine();

//封装为文件对象

File file = new File(path);

if(file.isDirectory()){

System.out.println("这是文件夹");

} else {

String name = file.getAbsolutePath();

//判断文件名

if(name.endsWith(".java")){

//新文件的名字

String newName = name.replace(".java", ".txt");

//创建新文件对象

File newFile = new File(newName);

boolean b = file.renameTo(newFile);

System.out.println("修改成功?" + b);

} else {

System.out.println("不是.java文件");

}

}

}

}

3.2.7 给定一个文件夹,递归打印这个文件夹下的所有.java文件的绝对路径(包含子文件夹)

代码语言:javascript
复制
package day10_Test拓展三道编程题;

import java.io.File;

public class Test003 {

//给定一个文件夹,递归打印这个文件夹下的所有.java文件的绝对路径(包含子文件夹)

public static void main(String[] args) {

File file = new File("D:/Java/JavaSE/2016/javahelp0505/day23");

changeJavaToText(file);

}

private static void changeJavaToText(File file) {

//取出当前目录下所有的子级

File[] sons = file.listFiles();

//循环遍历所有子级

for(File son : sons){

//如果是文件夹

if(son.isDirectory()){

changeJavaToText(son);

} else {

String name = son.getAbsolutePath();

if(name.endsWith(".java")){

System.out.println(name);

}

}

}

}

}

3.2.8 使用字节流,将一个路径下的视频复制到另一路径下

答案:

代码语言:javascript
复制
public class CopyVideo {

public static void main(String[] args) throws IOException {

method("D:\\video01.avi", "D:\\video02.avi");



}

 

//字节流,一次可以一个字节一个字节的读写,但是效率太低,因此在这一次一个字节数组

public static void method(String srcPath, String destPath) throws IOException {

FileInputStream fis = new FileInputStream(srcPath);

FileOutputStream fos = new FileOutputStream(destPath);

//读取数据

byte[] buffer = new byte[1024];

int len  = 0;

while( (len=fis.read(buffer)) != -1){

//写数据到目的地

fos.write(buffer, 0, len);

}

fos.close();

fis.close();

}

}

3.2.9 使用字符流,将一个路径下的文本文件复制到另一路径下

答案:

代码语言:javascript
复制
public class CopyTextFile {

public static void main(String[] args) throws IOException {

//数据源

String srcPath = "a.txt";

//目的地

String destPath = "b.txt";

method(srcPath,destPath);

}



//字节流:

public static void method(String srcPath, String destPath) throws IOException {

    FileInputStream  fis = new FileInputStream(srcPath);

    FileOutputStream fos = new FileOutputStream(destPath);

//读

    byte[] buffer = new byte[1024];

    int len  = 0;

    while( (len=fis.read(buffer)) != -1){

//写数据到目的地

fos.write(buffer, 0, len);

    }

    fis.close();

    fos.close();

}

}

3.2.10 请编写程序,复制单层文件夹,并测试

答案:

代码语言:javascript
复制
public class CopyDirectory {

public static void main(String[] args) throws IOException {

//封装数据源

File srcPath = new File("E:\\resource");

//封装目的地

File destPath = new File("dest");

//创建目的地文件夹

destPath.mkdirs();

//2:获取到数据源中所有的File对象

File[] files = srcPath.listFiles();

//3:遍历, 得到每一个File对象

for (File file : files) {

//4:复制文件



//得到名字

String name = file.getName();

//组成目的地File对象

File dest = new File(destPath, name);

copyFile(file, dest);

}

}

 

//复制文件

private static void copyFile(File srcPath, File destPath) throws IOException {

FileInputStream fis = new FileInputStream(srcPath);

FileOutputStream fos = new FileOutputStream(destPath);

//读取数据

byte[] buffer = new byte[1024];

int len  = 0;

while( (len=fis.read(buffer)) != -1){

//写数据到目的地

fos.write(buffer, 0, len);

}

fos.close();

fis.close();

}

}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-06-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java帮帮 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第1章 递归
    • 1.1 递归的概念
      • 1.2 递归的注意事项
        • 1.3 算法案例
          • 1.3.1 有些问题可以使用“循环”,也可以使用“递归”解决:求5的阶乘:表示为:1 * 2 * 3 * 4 * 5
        • 1.4 递归两种方法
          • 1.4.1 递归的代码演示,计算1-n之间的和,使用递归完成
          • 1.4.2 代码执行流程图解
        • 1.5 递归打印所有子目录中的文件路径
        • 第2章 IO概述
          • 2.1 IO流分类
            • 2.2 字节流
              • 2.2.1 一切均为字节
              • 2.2.2 字节输出流
              • 2.2.3 FileOutputStream类
              • 2.2.4 给文件中续写和换行
              • 2.2.5 字节输入流
              • 2.2.6 FileInputStream类
              • 2.2.7 FileInputStream类读取数据read方法
              • 2.2.8 读取数据read(byte[])方法
              • 2.2.9 字节流练习
            • 2.3 字符流
              • 2.3.1 方便程序员的IO流
              • 2.3.2 字符输出流FileWirter
              • 2.3.3 FileWriter类
              • 2.3.4 FileWirter写数据
              • 2.3.5 FileWriter写入中文到文件中
              • 2.3.6 FileWriter写数据路径问题及关闭和刷新方法的区别
              • 2.3.7 FileWriter写数据的5个方法
              • 2.3.8 FileWriter写数据之换行和追加写
              • 2.3.9 字符输入流FileReader
              • 2.3.10 FileReader读数据
              • 2.3.11 FileReader类
              • 2.3.12 FileReader读取包含中文的文件
          • 第3章 本日自习作业:
            • 3.1 知识点相关题
              • 3.1.1 知识点:字节输出流FileOutputStream各种方法
              • 3.1.2 知识点:字节输入流FileInputStream各种方法
              • 3.1.3 知识点:使用字节流实现文件复制
              • 3.1.4 请写出FileWriter的五种输出的方法;
              • 3.1.5 字符输出流FileWriter操作
              • 3.1.6 请写出FileRader的两种读取的方法;
              • 3.1.7 字符输入流FileReader操作
              • 3.1.8 掌握使用字符流复制文件的方式
              • 3.1.9 使用递归定义方法,求1-N的和
              • 3.1.10 字节流复制文件操作
              • 3.1.11 使用字节流复制一张图片或者音频(不要过大!),请问是否可以使用字符流完成相同操作,为什么?
              • 3.1.12 完成单级文件夹的复制,即:
              • 3.1.13 使用递归求斐波那契数列:给定第几项,求该项的值。
              • 3.1.14 复制多级目录,将a文件夹所有内容(包含a文件夹本身),复制到b文件夹中。
              • 3.1.15 使用递归的方式获取这个目录下所有的子目录的名字
            • 3.2 代码题
              • 3.2.1 求1*2!*3!+...*20!的和
              • 3.2.2 使用字符流,将一个路径下的文本文件复制到另一路径下;
              • 3.2.3 将100-999(包含)之间的二十个随机数存在集合中,并将集合中是3的倍数的数字存放在文件number.txt中
              • 3.2.4 获取srcPath.txt文件中“悟空教程_我是一名程序员”(字符串需使用IO流写入)中下划线后面的部分写入destPath.txt文本中
              • 3.2.5 使用递归,遍历 1 至100之间的每个数字
              • 3.2.6 键盘录入一个路径,如果不是文件夹,并且是.java文件,那么把文件更改为.txt文件
              • 3.2.7 给定一个文件夹,递归打印这个文件夹下的所有.java文件的绝对路径(包含子文件夹)
              • 3.2.8 使用字节流,将一个路径下的视频复制到另一路径下
              • 3.2.9 使用字符流,将一个路径下的文本文件复制到另一路径下
              • 3.2.10 请编写程序,复制单层文件夹,并测试
          相关产品与服务
          数据保险箱
          数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档