目录
第1关:什么是IO流
相关知识
什么是字节
什么是字符
什么是IO流
第2关:字节流-输入输出
相关知识
输入流
输出流
最佳实践
编程要求
第3关:字符流 - 输入输出
相关知识
Writer
Reader
编程要求
第4关:复制文件
相关知识
read()方法
write()方法
使用字节流读写文件
扩展
编程要求
第1关:什么是IO流
相关知识
什么是字节
字节是指一小组相邻的二进制数码。通常是8
位作为一个字节。它是构成信息的一个小单位,并作为一个整体来参加操作,比字小,是构成字的单位。
字节(Byte
) 是一种计量单位,表示数据量的多少,它是计算机信息技术用于计量存储容量的一种计量单位.
什么是字符
我们想象一下,给你一串二进制码,要你来分辨它是什么含义,是代表数字还是字母还是汉字,你能有效的分辨吗?
显然不能,一般来说,我们是比较难以理解一串二进制码代表的含义的,而且一串二进制码是代表什么含义也无法很直观的表示出来。
我们比较好识别的是文字,字母和符号。
所以就有了字符,字符是指计算机中使用的文字和符号,比如1、2、3、A、B、C、~!·#¥%……—*()——+
、等等。
字符在计算机中可以看做:字节+编码表
我们知道,计算机是只识别二进制的,但是我们日常操作电脑,需要输入文字,字母,数字这些,我们不可能先去记住一串二进制数字,比如说A
这个字母的二进制是什么,因为这样太麻烦,也记不住,所以编码表,就诞生了,编码表的作用就是在我们进行输入的时候,将我们输入的字符转换成计算机能识别的二进制,在我们阅读数据的时候,将二进制转换成我们人能识别的文字字母和数字。
最先普及的就要数ASCLL
码表了,ASCLL
码表是美国信息交换标准代码,是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。
看到这你肯定会有疑问,这ASCLL
码表只有英语和西欧语呀,那汉语呢,其他语言呢?自从ASCLL
码表推出之后,很多国家也都推出了本国语言的编码表。像中国就有GB2312
,GBK
等等。
现在我们一起设想一个场景,当我们编辑一个文本文件,输入了很多字符,这些字符都用ASCLL
码表编码,然后我们查看这个文本文件的时候,是使用的GBK
码表解码,会出现什么问题吗?
相信你已经有答案了,这会出现软件开发中非常常见的问题:乱码。
当我们对字节进行编码的时候使用的是一种编码表,而解码的时候使用的是另一种编码表的时候,就会出现乱码的问题了,是因为每一个编码表,它的字符对应二进制的字节是不一致的。但是互联网是一个互联互通的平台,所以如果每个国家都使用自己的一套编码器,就会出现许多问题。
在1992
年的时候,推出了UTF-8
编码规范,是一种针对Unicode
的可变长度字符编码,又称万国码,UTF-8
用1到6
个字节编码Unicode
字符。用在网页上可以统一页面显示中文简体繁体及其它语言(如英文,日文,韩文)。
UTF-8
也是我们目前在应用开发中使用的最多的编码格式。
Java中默认采用的是Unicode编码格式(具体来说是UTF-16编码)。
什么是IO流
IO
流中的IO
是Input
,Output
,输入和输出的意思,是用来处理设备与设备之间的数据传输的,不仅能处理内部设备(比如CPU
、GPU
、内存),还能处理外部设备(比如手机和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中对于流的操作是非常消耗资源的,如果我们使用流对一个资源进行操作了之后却没有释放它的资源,这就会造成系统资源的浪费,如果积累了很多这种空置的资源,最后可能会导致系统崩溃。
上述代码的最佳实践为:
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"); //指定字符格式
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
个字符,直接使用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
;文章来源:https://www.toymoban.com/news/detail-769236.html -
复制
src/step4/input/
目录下的input.jpg
文件到src/step4/output/
目录下,新文件命名为output.jpg
。文章来源地址https://www.toymoban.com/news/detail-769236.html
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 *********/
}
}
到了这里,关于Educoder/头歌JAVA——JAVA高级特性:IO流的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!