二十一、IO流


第一关:字节流-输入输出


任务描述
本关任务:使用输入输出流读写文件。
相关知识
为了完成本关任务,你需要掌握:
1.如何使用输入流;
2.如何使用输出流。
输入流
我们通过一个示例,来看看输入流应该如何使用,首先我们在D盘下创建一个hello.txt文件。输入文本Hello Java Hello InputStream。
在main方法中加入如下代码:
在这里插入图片描述

输出:

Hello Java Hello InputStream

代码解释:
这个例子我们主要目的是,读取文件中的数据并将数据显示在控制台。
实现步骤是:首先读取文件转换成文件输入流(FileInputStream),然后定义一个字节数组作为容器用来存储即将读取到的数据。fs.read(b)函数的作用是将数据读取到b数组中,最后通过编码表,将字节数组编码成字符。
在这里插入图片描述

输出流
我们使用输出流将字符串hello educoder写入到一个文件中:
在这里插入图片描述

运行这段代码,打开D盘下你会发现test.txt文件被创建了,并且文件的内容是hello educoder。
代码解释:
在这里插入图片描述

最佳实践
上面作为示例的两段代码都是存在很大问题的,什么问题呢?
因为在Java中对于流的操作是非常消耗资源的,如果我们使用流对一个资源进行操作了之后却没有释放它的资源,这就会造成系统资源的浪费,如果积累了很多这种空置的资源,最后可能会导致系统崩溃。
上述代码的最佳实践为:

OutputStream out = null;
try {
    String file = "D://test.txt";
    out = new FileOutputStream(file);
    String str = "hello educoder";
    byte[] b = str.getBytes();
    out.write(b);
    out.flush();
} catch (Exception e) {
    e.printStackTrace();
} finally {
    if (out != null) {
        try {
            out.close(); // 释放该输出流
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

核心就是在使用完流之后,释放它所占用的资源。
编程要求
请仔细阅读右侧代码,根据方法内的提示,在Begin - End区域内进行代码补充,具体任务如下:
读取src/step2/input/目录下的task.txt文件信息并输出到控制台,使用Java代码将字符串learning practice写入到src/step2/output/目录下的output.txt,若文件目录不存在,则创建该目录。
注意:临时字节数组需要定义长度为8位,否则会有空格。
测试说明
补充完代码后,点击测评,平台会对你编写的代码进行测试,当你的结果与预期输出一致时,即为通过。

代码实现

package step2;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Task {
	public void task() throws IOException{
		/********* Begin *********/
		File file = new File("src/step2/input/task.txt");
		FileInputStream fs = new FileInputStream(file);  //定义一个文件输入流
		byte[] b = new byte[8];                         //定义一个字节数组
		fs.read(b);                                     //将输入流的数据读入到字节数组
		String str = new String(b,"UTF-8");             //通过utf-8编码表将字节转换成字符
		System.out.println(str);
		File dir = new File("src/step2/output");
		if(!dir.exists()){
			dir.mkdir();
		}
		FileOutputStream out = new FileOutputStream("src/step2/output/output.txt"); //创建输出流
		String str1 = "learning practice";
		byte[] c = str1.getBytes();   //将字符串转换成字节
		out.write(c);                 //写数据
		out.flush();                  //刷新缓存区数据
		fs.close();					  //释放资源
		out.close();
		/********* End *********/
	}
}

第2关:字符流 - 输入输出


任务描述
本关任务:使用字符流对文本进行读写操作。

相关知识
为了完成本关任务,你需要掌握:

1.如何使用字符流读数据;

2.如何使用字符流写数据。

Writer
字符流的使用很简单,和字节输入流类似,以FileWriter举例:
在这里插入图片描述

执行上述代码即可看到在D盘下创建了一个名为hello.txt的文件,文件的内容为hello。

上面代码fw.flush()和fw.close()也可以省略fw.flush(),只写fw.close()就可以了,但是都省略是不对的,如果都省略你会发现文本没有写入到hello.txt文件。

Reader
Reader的使用也很简单,以FileReader为例:

在这里插入图片描述

输出:

hello+ 1019个空格

使用上述代码的会输出hello.txt中的内容,但是会有一个问题:输出hello的同时还输出了1019个空格,这是什么原因呢,如何解决这些问题呢?请你思考。

我们在下一关中揭晓答案。

编程要求
请仔细阅读右侧代码,根据方法内的提示,在Begin - End区域内进行代码补充,具体任务如下:

将src/step3/input/目录下的input.txt文件复制到src/step3/output/目录下;

复制的新文件命名为output.txt;

input.txt文件中只有8个字符。

测试说明
补充完代码后,点击测评,平台会对你编写的代码进行测试,当你的结果与预期输出一致时,即为通过。

代码实现

package step3;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Task {
	public void task() throws IOException{
		/********* Begin *********/
		String file1 = "src/step3/input/input.txt";
		FileReader fr = new FileReader(file1);
		char[] ch = new char[8];
		fr.read(ch);
		String file2 = "src/step3/output/output.txt";
		FileWriter fw = new FileWriter(file2);
		fw.write(ch);
		fr.close();
		fw.flush();
		fw.close();
		/********* End *********/		
	}
}

第三关:复制文件


任务描述
本关任务:复制文本文件,复制图片文件。
相关知识
上一关中最后,我们遇到了一个问题:hello.txt文件只有五个字符,而用来存储字符的数组有1024个字符,直接使用FileReader的read()方法读取然后输出就会有1019个空字符,如何来解决这个问题呢?
很容易想到的方法就是,我们定义一个长度为5的字符数组就可以了,这样确实可以暂时解决问题,可是我们往往不知道读取的文件有多大,如果文件中不止5个字符,而是有几万个字符我们又应该怎么办呢?
这就需要我们深入的了解IO流的常用函数了。
read()方法
我们来看read方法的详细解释:

理解了read方法,之前的问题就好解决了。
代码:

String file = "D://hello.txt";
FileReader fr = new FileReader(file);
char[] cbuf = new char[1024];
int len = fr.read(cbuf);//将数据读入到cbuf中并返回读取到的数据长度
StringBuilder builder = new StringBuilder();
builder.append(cbuf,0,len); //将cbuf 0 到len长度的数据添加到builder 
System.out.println(builder.toString());

运行这段代码,我们会发现输出是正确的,没有再打印出多余的空格。
可能我们又会有疑问了,如果文本文件大于1K,这段代码肯定就行不通了,怎么办呢?
很简单,加个循环就可以啦:

String file = "D://hello.txt";
FileReader fr = new FileReader(file);
char[] cbuf = new char[1024];
int len = 0; // 每次读取的长度
StringBuilder builder = new StringBuilder();
while ((len = fr.read(cbuf)) != -1) {
    builder.append(cbuf,0,len);
}
System.out.println(builder.toString());

这样修改之后我们就可以读取任意的文件,并将其内容输出到控制台了。
write()方法
write()方法有两种常用的重载方法:

理解了这两种方法,我们现在如果要复制一个文本文件就很方便了,现在我们就来将D盘下hello.txt文件复制到E盘下,并重命名为abc.txt:

FileReader fr = new FileReader("D://hello.txt"); //定义FileReader读取文件
int len = 0;    //每次读取的字符数量
char[] cbuf = new char[1024];    //每次读取数据的缓冲区
FileWriter fw = new FileWriter("E://abc.txt"); //定义FileWriter写文件
while((len = fr.read(cbuf)) != -1){
    fw.write(cbuf,0,len);
}
fw.close();    //释放资源 刷新缓冲区
fr.close();

这段代码就是一个边读边写的过程,运行之后我们发现E盘下已经有了abc.txt文件并且内容和hello.txt一致。
使用字节流读写文件
到目前为止我们一直操作的都是文本文件,不过我们计算机中存储的文件可不止有文本文件,还有很多其他类型的,比如图片,视频,等等。
如果要对非文本类型的文件进行操作,应该怎么做呢?这个时候字符流还能不能派上用场呢?
答案是否定的,字符流只适用于操作字符类型的文件,不能操作非字符类型的。
所以这个时候应该用什么来操作呢?
相信你已经想到了:字节流。
是的我们需要使用字节流来操作非字符类文件。
接下来,我们使用字节流来复制一个图片文件,代码:

FileInputStream fs = new FileInputStream("D://user.jpg"); //定义文件输入流读取文件信息
FileOutputStream fos = new FileOutputStream("E://new.jpg");//定义文件输出流写文件
int len = 0;        //每次读取数据的长度
byte[] bys = new byte[1024];    //数据缓冲区
while( (len = fs.read(bys)) != -1){
    fos.write(bys, 0, len);
}
//释放资源  刷新缓冲区
fs.close();
fos.close();

运行即可看到E盘下生成了一个名为new.jpg的文件,且内容和user.jpg一致
可以发现上述代码和之前的字符流很像,确实原理都是类似的。
可能学到这,你会有很多疑问:
字节流既然可以用来读取非字符构成的文件,那可以读取字符类型的文件吗? 答案是可以的,字节流可以操作所有类型的文件,因为计算机中的数据都是以字节的方式存储的;
既然字节流可以用来操作所有的文件,那还要字符流干啥咧? 因为字符流操作字符类型的数据和文件要比字节流快很多。
扩展
使用BufferedReader读取字符文件的速度要比我们之前使用的字节流和FileReader快很多,示例代码:

BufferedReader bf = new BufferedReader(new FileReader("D://hello.txt"));
BufferedWriter writer = new BufferedWriter(new FileWriter("D://abc.txt"));
String str = "";
while( (str = bf.readLine()) != null){
    writer.write(str);
}
bf.close();
writer.close();

编程要求
请仔细阅读右侧代码,根据方法内的提示,在Begin - End区域内进行代码补充,具体任务如下:
复制src/step4/input/目录下的input.txt文件到src/step4/output/目录下,新文件命名为output.txt;
复制src/step4/input/目录下的input.jpg文件到src/step4/output/目录下,新文件命名为output.jpg。
测试说明
补充完代码后,点击测评,平台会对你编写的代码进行测试,当你的结果与预期输出一致时,即为通过。

代码实现

package step4;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Task {
	public void task() throws IOException{
		/********* Begin *********/
		String file1 = "src/step4/input/input.txt";
		FileInputStream fr = new FileInputStream(file1);
		byte[] b = new byte[1024];
		int len = 0;
		String file2 = "src/step4/output/output.txt";
		FileOutputStream fw = new FileOutputStream(file2);
		while((len = fr.read(b))!=-1){
			fw.write(b,0,len);
		}
		fr.close();
		fw.close();
		String file3 = "src/step4/input/input.jpg";
		String file4 = "src/step4/output/output.jpg";
		FileInputStream fs = new FileInputStream(file3); //定义文件输入流读取文件信息
		FileOutputStream fos = new FileOutputStream(file4);//定义文件输出流写文件
		len = 0;        //每次读取数据的长度
		byte[] bys = new byte[1024];    //数据缓冲区
		while( (len = fs.read(bys)) != -1){
			fos.write(bys, 0, len);
		}
		//释放资源  刷新缓冲区
		fs.close();
		fos.close();
		/********* End *********/		
	}
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

请你吃茶去

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值