Educoder/头歌JAVA——JAVA高级特性:IO流

目录

第1关:什么是IO流

相关知识

什么是字节

什么是字符

什么是IO流

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

相关知识

输入流

输出流

最佳实践

扫描二维码关注公众号,回复: 15467072 查看本文章

编程要求

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

相关知识

Writer

Reader

编程要求

 第4关:复制文件

相关知识

read()方法

write()方法

使用字节流读写文件

扩展

编程要求


第1关:什么是IO流

相关知识

什么是字节

字节是指一小组相邻的二进制数码。通常是8位作为一个字节。它是构成信息的一个小单位,并作为一个整体来参加操作,比字小,是构成字的单位。

字节(Byte) 是一种计量单位,表示数据量的多少,它是计算机信息技术用于计量存储容量的一种计量单位.

什么是字符

我们想象一下,给你一串二进制码,要你来分辨它是什么含义,是代表数字还是字母还是汉字,你能有效的分辨吗?

显然不能,一般来说,我们是比较难以理解一串二进制码代表的含义的,而且一串二进制码是代表什么含义也无法很直观的表示出来。

我们比较好识别的是文字,字母和符号。

所以就有了字符,字符是指计算机中使用的文字和符号,比如1、2、3、A、B、C、~!·#¥%……—*()——+、等等。

字符在计算机中可以看做:字节+编码表

我们知道,计算机是只识别二进制的,但是我们日常操作电脑,需要输入文字,字母,数字这些,我们不可能先去记住一串二进制数字,比如说A这个字母的二进制是什么,因为这样太麻烦,也记不住,所以编码表,就诞生了,编码表的作用就是在我们进行输入的时候,将我们输入的字符转换成计算机能识别的二进制,在我们阅读数据的时候,将二进制转换成我们人能识别的文字字母和数字

最先普及的就要数ASCLL码表了,ASCLL码表是美国信息交换标准代码,是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。

看到这你肯定会有疑问,这ASCLL码表只有英语和西欧语呀,那汉语呢,其他语言呢?自从ASCLL码表推出之后,很多国家也都推出了本国语言的编码表。像中国就有GB2312GBK等等。

现在我们一起设想一个场景,当我们编辑一个文本文件,输入了很多字符,这些字符都用ASCLL码表编码,然后我们查看这个文本文件的时候,是使用的GBK码表解码,会出现什么问题吗?

相信你已经有答案了,这会出现软件开发中非常常见的问题:乱码

当我们对字节进行编码的时候使用的是一种编码表,而解码的时候使用的是另一种编码表的时候,就会出现乱码的问题了,是因为每一个编码表,它的字符对应二进制的字节是不一致的。但是互联网是一个互联互通的平台,所以如果每个国家都使用自己的一套编码器,就会出现许多问题。

1992年的时候,推出了UTF-8编码规范,是一种针对Unicode的可变长度字符编码,又称万国码,UTF-8用1到6个字节编码Unicode字符。用在网页上可以统一页面显示中文简体繁体及其它语言(如英文,日文,韩文)。

UTF-8也是我们目前在应用开发中使用的最多的编码格式。

Java中默认采用的是Unicode编码格式(具体来说是UTF-16编码)。

什么是IO流

IO流中的IOInputOutput,输入和输出的意思,是用来处理设备与设备之间的数据传输的,不仅能处理内部设备(比如CPUGPU、内存),还能处理外部设备(比如手机和PC,客户端与服务器)。

在Java中定义数据按照流向,分为输入流输出流

首先我们来了解输入流,从字面上就很容易理解,凡是从外部流入的数据都可以通过输入流来处理。比如读取文件。

输出流,就表示从内部流出的数据,比如:我们编辑了一个文本文件,当我们按下ctrl+s的时候,就将该文件从内存保存到了硬盘,这就是一个将数据从内存中输出到硬盘的过程。

除了输出和输入流,流按照操作的数据还分为:字节流字符流

总体结构如下图:

好了,IO流的简单介绍就到这里啦,使用本关所学知识来完成选择题吧。

第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中对于流的操作是非常消耗资源的,如果我们使用流对一个资源进行操作了之后却没有释放它的资源,这就会造成系统资源的浪费,如果积累了很多这种空置的资源,最后可能会导致系统崩溃。

上述代码的最佳实践为:

  1. OutputStream out = null;
  2. try {
  3. String file = "D://test.txt";
  4. out = new FileOutputStream(file);
  5. String str = "hello educoder";
  6. byte[] b = str.getBytes();
  7. out.write(b);
  8. out.flush();
  9. } catch (Exception e) {
  10. e.printStackTrace();
  11. } finally {
  12. if (out != null) {
  13. try {
  14. out.close(); // 释放该输出流
  15. } catch (IOException e) {
  16. e.printStackTrace();
  17. }
  18. }
  19. }

核心就是在使用完流之后,释放它所占用的资源。

编程要求

请仔细阅读右侧代码,根据方法内的提示,在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");  //指定字符格式         
		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 *********/
	}	
}

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

相关知识

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 *********/		
	}
}

 第4关:复制文件

相关知识

上一关中最后,我们遇到了一个问题:hello.txt文件只有五个字符,而用来存储字符的数组有1024个字符,直接使用FileReaderread()方法读取然后输出就会有1019个空字符,如何来解决这个问题呢?

很容易想到的方法就是,我们定义一个长度为5的字符数组就可以了,这样确实可以暂时解决问题,可是我们往往不知道读取的文件有多大,如果文件中不止5个字符,而是有几万个字符我们又应该怎么办呢?

这就需要我们深入的了解IO流的常用函数了。

read()方法

我们来看read方法的详细解释:

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

代码:

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

运行这段代码,我们会发现输出是正确的,没有再打印出多余的空格。

可能我们又会有疑问了,如果文本文件大于1K,这段代码肯定就行不通了,怎么办呢?

很简单,加个循环就可以啦:

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

这样修改之后我们就可以读取任意的文件,并将其内容输出到控制台了。

write()方法

write()方法有两种常用的重载方法:

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

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

这段代码就是一个边读边写的过程,运行之后我们发现E盘下已经有了abc.txt文件并且内容和hello.txt一致。

使用字节流读写文件

到目前为止我们一直操作的都是文本文件,不过我们计算机中存储的文件可不止有文本文件,还有很多其他类型的,比如图片,视频,等等。

如果要对非文本类型的文件进行操作,应该怎么做呢?这个时候字符流还能不能派上用场呢?

答案是否定的,字符流只适用于操作字符类型的文件,不能操作非字符类型的。

所以这个时候应该用什么来操作呢?

相信你已经想到了:字节流。

是的我们需要使用字节流来操作非字符类文件。

接下来,我们使用字节流来复制一个图片文件,代码:

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

运行即可看到E盘下生成了一个名为new.jpg的文件,且内容和user.jpg一致

可以发现上述代码和之前的字符流很像,确实原理都是类似的。

可能学到这,你会有很多疑问:

  1. 字节流既然可以用来读取非字符构成的文件,那可以读取字符类型的文件吗? 答案是可以的,字节流可以操作所有类型的文件,因为计算机中的数据都是以字节的方式存储的;

  2. 既然字节流可以用来操作所有的文件,那还要字符流干啥咧? 因为字符流操作字符类型的数据和文件要比字节流快很多。

扩展

使用BufferedReader读取字符文件的速度要比我们之前使用的字节流和FileReader快很多,示例代码:

  1. BufferedReader bf = new BufferedReader(new FileReader("D://hello.txt"));
  2. BufferedWriter writer = new BufferedWriter(new FileWriter("D://abc.txt"));
  3. String str = "";
  4. while( (str = bf.readLine()) != null){
  5. writer.write(str);
  6. }
  7. bf.close();
  8. 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){ //将数据读入到b中并返回读取到的数据长度
			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 *********/		
	}
}

猜你喜欢

转载自blog.csdn.net/zhou2622/article/details/128376388
今日推荐