Java IO流系列② -- 流的分类与节点流
【摘要】
目录
IO流原理流的分类节点流和处理流
节点流(或文件流)使用FileReader读入数据的基本操作(方式一:适合小数量的读入)使用FileReader读入数据的基本操作(方式二:使用read...
IO流原理
I/O是Input/Output的缩写, I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。
Java程序中,对于数据的输入/输出操作以“流(stream)” 的方式进行。
java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。
流的分类
- 按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)
- 按数据流的流向不同分为:输入流,输出流
- 按流的角色的不同分为:节点流,处理流(也就是节点流外面包着的那层流)
这所有的流均有四个抽象的基类:(按照两种分法)
(抽象基类) | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
节点流和处理流
节点流:直接从数据源或目的地读写数据
处理流:不直接连接到数据源或目的地,而是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。
节点流(或文件流)
使用FileReader读入数据的基本操作(方式一:适合小数量的读入)
步骤:
- 1.实例化File类的对象,指明要操作的文件
- 2.提供具体的流(也就是流的实例化)
- 3.数据的读入
- 4.流的关闭操作
三个注意点:
- read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1
- 异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally处理
- 读入的文件一定要存在,否则就会报FileNotFoundException。
主要方法:
int read()
读取单个字符。作为整数读取的字符,范围在 0 到 65535 之间 (0x00-0xffff)(2个字节的Unicode码),如果已到达流的末尾,则返回 -1
代码实现:
@Test
public void testFileReader(){
FileReader fr = null;
try {
//1.实例化File类的对象,指明要操作的文件
File file = new File("hello.txt");//相较于当前Module
//2.提供具体的流
fr = new FileReader(file);
//3.数据的读入
//read():返回读入的一个字符。如果达到文件末尾,返回-1
int data;
while((data = fr.read()) != -1){
System.out.print((char)data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流的关闭操作
try {
if(fr != null)fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
前三个步骤均在try中,最后一个在try中加入一个判断语句(if(fr != null))是因为有可能在读文件的时候就报异常,从而这个流的对象没有成功的创建出来,如果是这样的话那么close()方法也就无从说起了。
使用FileReader读入数据的基本操作(方式二:使用read的重载方法)
主要方法:
int read(byte[] b)
将字符读入数组。如果已到达流的末尾,则返回 -1。否则返回本次读取的字符数。
代码实现:
//对read()操作升级:使用read的重载方法
@Test
public void testFileReader1() {
FileReader fr = null;
try {
//1.File类的实例化
File file = new File("hello.txt");
//2.FileReader流的实例化
fr = new FileReader(file);
//3.读入的操作
//read(char[] cbuf):返回每次读入cbuf数组中的字符的个数。如果达到文件末尾,返回-1
char[] cbuf = new char[5];
int len;
while((len = fr.read(cbuf)) != -1){
// 方式一:
for(int i = 0;i < len;i++){
System.out.print(cbuf[i]);
}
// 方法二:
String str = new String(cbuf,0,len);
System.out.print(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fr != null){
//4.资源的关闭
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
注意:不管是方式一中的for循环还是方法二中的将char型数组转化为字符串,他的读取长度都不能为char型数组的长度,而应该是实际读取的字节数(也就是read的返回值len),否则当读入的内容填充不满一个数组时,打印出来的结果会发生错误。
使用FileWriter写出数据的操作
主要方法:
说明:
1. 输出操作,对应的File可以不存在的。并不会报异常
2. File对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。
File对应的硬盘中的文件如果存在:
如果流使用的构造器是:FileWriter(file,false) / FileWriter(file):对原有文件的覆盖
如果流使用的构造器是:FileWriter(file,true):不会对原有文件覆盖,而是在原有文件基础上追加内容
代码实现:
@Test
public void testFileWriter() {
FileWriter fw = null;
try {
//1.提供File类的对象,指明写出到的文件
File file = new File("hello1.txt");
//2.提供FileWriter的对象,用于数据的写出
fw = new FileWriter(file,false);
//3.写出的操作
fw.write("I have a dream!\n");
fw.write("you need to have a dream!");
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流资源的关闭
if(fw != null){
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
使用FileReader和FileWriter实现文本文件的复制
代码实现:
@Test
public void testFileReaderFileWriter() {
FileReader fr = null;
FileWriter fw = null;
try {
//1.创建File类的对象,指明读入和写出的文件
File srcFile = new File("hello.txt");
File destFile = new File("hello2.txt");
//2.创建输入流和输出流的对象
fr = new FileReader(srcFile);
fw = new FileWriter(destFile);
//3.数据的读入和写出操作
char[] cbuf = new char[5];
int len;//记录每次读入到cbuf数组中的字符的个数
while((len = fr.read(cbuf)) != -1){
//每次写出len个字符
fw.write(cbuf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭流资源
//方式一:
// try {
// if(fw != null)
// fw.close();
// } catch (IOException e) {
// e.printStackTrace();
// }finally{
// try {
// if(fr != null)
// fr.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
//方式二:
try {
if(fw != null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
使用FileInputStream和FileOutputStream读写非文本文件
代码实现:
/*
实现对图片的复制操作
*/
@Test
public void testFileInputOutputStream() {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
File srcFile = new File("爱情与友情.jpg");
File destFile = new File("爱情与友情2.jpg");
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
//复制的过程
byte[] buffer = new byte[5];
int len;
while((len = fis.read(buffer)) != -1){
fos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fos != null){
//
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
指定路径下文件的复制(通用方法)
public void copyFile(String srcPath,String destPath){
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//
File srcFile = new File(srcPath);
File destFile = new File(destPath);
//
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
//复制的过程
byte[] buffer = new byte[1024];
int len;
while((len = fis.read(buffer)) != -1){
fos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fos != null){
//
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
一个小注意点
在创建路径的时候,有两种情况:
- main()方法中
- 单元测试中(@Test)
如果你是在main方法中创建路径(相对路径),他是以整个工程为基础。而如果是在单元测试中,则它是以这个module为基础。
定义文件路径时,注意:可以用“/”或者“\”。
总结
- 对于文本文件(.txt,.java,.c,.cpp),使用字符流处理
- 对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,…),使用字节流处理
- 字节流可以处理文本文件或非文本文件的复制,但不能读取或写入文本文件。
那么同理:能不能用字符流去复制非文本文件呢?
可以复制,但是复制完以后,不能保证图片还能正常显示!
因为字符流是读取字节后,缓存,然后去码表查找匹配,若是匹配不到就会到位置码表位置寻找类似的,此时返回的数据就可能不正确。因此生成的新图片的编码和老图片的编码是不一致的,从而导致图片不能正常显示。
所以不要用字符流拷贝媒体文件。
文章来源: blog.csdn.net,作者:十八岁讨厌编程,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/zyb18507175502/article/details/122401041
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)