0
点赞
收藏
分享

微信扫一扫

Java IO流系列② -- 流的分类与节点流


目录

  • ​​IO流原理​​
  • ​​流的分类​​
  • ​​节点流和处理流​​
  • ​​节点流(或文件流)​​
  • ​​使用FileReader读入数据的基本操作(方式一:适合小数量的读入)​​
  • ​​使用FileReader读入数据的基本操作(方式二:使用read的重载方法)​​
  • ​​使用FileWriter写出数据的操作​​
  • ​​使用FileReader和FileWriter实现文本文件的复制​​
  • ​​使用FileInputStream和FileOutputStream读写非文本文件​​
  • ​​指定路径下文件的复制(通用方法)​​
  • ​​一个小注意点​​
  • ​​总结​​

IO流原理

I/O是Input/Output的缩写, I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。

Java IO流系列② -- 流的分类与节点流_文本文件


Java程序中,对于数据的输入/输出操作以“流(stream)” 的方式进行。

java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。

流的分类

  • 按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)
  • 按数据流的流向不同分为:输入流,输出流
  • 按流的角色的不同分为:节点流,处理流(也就是节点流外面包着的那层流)

Java IO流系列② -- 流的分类与节点流_数据_02


这所有的流均有四个抽象的基类:(按照两种分法)

(抽象基类)

字节流

字符流

输入流

InputStream

Reader

输出流

OutputStream

Writer

Java IO流系列② -- 流的分类与节点流_后端_03

节点流和处理流

节点流:直接从数据源或目的地读写数据

Java IO流系列② -- 流的分类与节点流_数据_04


处理流:不直接连接到数据源或目的地,而是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。

Java IO流系列② -- 流的分类与节点流_开发语言_05

节点流(或文件流)

使用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写出数据的操作

主要方法

Java IO流系列② -- 流的分类与节点流_后端_06

说明:
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,…),使用字节流处理
  • 字节流可以处理文本文件或非文本文件的复制,但不能读取或写入文本文件。

那么同理:能不能用字符流去复制非文本文件呢?

可以复制,但是复制完以后,不能保证图片还能正常显示!
因为字符流是读取字节后,缓存,然后去码表查找匹配,若是匹配不到就会到位置码表位置寻找类似的,此时返回的数据就可能不正确。因此生成的新图片的编码和老图片的编码是不一致的,从而导致图片不能正常显示。
所以不要用字符流拷贝媒体文件。


举报

相关推荐

0 条评论