字节流
简单介绍:
1>字节流和字符流的使用是非常相似的,但是字节流是直接操作文件的,而字符流
用到了缓冲区,通过缓冲区再操作文件。所以字节流不用刷新,直接写入文件,而
字符流的关闭流之前进行了一次强制刷新,如果不关闭流的情况下,数据是存在缓
冲区的并没有写入文件,需要刷新一下把数据刷入目标文件;
2>字节流主要用于操作二进制数据,它是按字节来操作的;
3>字节流的两个抽象基类:InputStream OutputStream
字节流可以直接对媒体数据进行操作
练习:拷贝一个媒体文件。
1>创建字节流输入流对象,并与媒体文件相关联,此媒体文件必须存在;
2>创建字节流输出流对象,并指定目标文件,存储写入的媒体数据;
3>通过循环读写,完成数据的存取;
4>关闭流资源。
示例:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class StreamDemo {
public static void main(String[] args) {
FileOutputStream fos = null;
FileInputStream fis = null;
try {
// 创建字节流输入流和输出流对象
fos = new FileOutputStream("copy.gif");
fis = new FileInputStream("123.gif");
int len = 0;
// 定义字节数组,存储读取的字节
byte[] arr = new byte[1024];
// 循环读写流,len为每次读入字节数组的字节个数
while ((len = fis.read(arr)) != -1) {
fos.write(arr, 0, len);
}
} catch (IOException e) {
throw new RuntimeException("复制图片失败");
} finally {
// 关闭所有的流资源
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
System.out.println("关闭流失败");
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
System.out.println("关闭流失败");
}
}
}
}
}
字节流缓冲区
简单介绍:
1>字节流缓冲区主要使用的是BufferedInputStream和BufferedOutputStream;
2>字节流缓冲区实现的主要原理是在对象里封装了一个固定长度的字节数组,先把
文件中的数据读取数组长度的字节缓存到字节数组中,当BufferedInputStream对象
调用read方法的时候是从缓存的数组中读取一个字节,当读取到字节数组中最后一个
字节时,会重复性的再从文件中往字节数组中读取相应长度的字节,然后再一个字节
一个字节的往程序中read,直到读取完文件中的数据。
练习:使用字节流缓冲区复制一个媒体文件。
示例:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyByBufferedStream {
public static void main(String[] args) {
// 通过字节流的缓冲区完成复制
BufferedOutputStream bos = null;
BufferedInputStream bis = null;
try {
// 创建字节流的缓冲区对象对传入的字节流对象的功能进行增强
bis = new BufferedInputStream(new FileInputStream("demo.mp3"));
bos = new BufferedOutputStream(new FileOutputStream("copy.mp3"));
int ch = -1;
// 从输入流中读取一个字节就往输出流中存入一个字节
while ((ch = bis.read()) != -1) {
bos.write(ch);
}
} catch (FileNotFoundException e) {
System.out.println("文件操作失败");
} catch (IOException e) {
System.out.println("文件操作失败");
} finally {
// 关闭输入输出流
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
System.out.println("关闭流资源失败");
}
}
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
System.out.println("关闭流资源失败");
}
}
}
}
}
由于字节流缓冲区已经封装了一个字节数组来缓存数据,所以这里我们就不需要再
自己创建一个字节数组了,从内存读写数据的效率要比从硬盘读写数据高的多,使用
内存作为缓存就提高了文件读写的效率。
转换流
练习:通过键盘录入数据,当录入一行数据后,就将该行数据进行打印,如果录入的
数据是quit时,停止录入。
1>读取键盘录入,使用System.in,它对应的是标准的输入设备:键盘,是标准的输入
流;打印,使用System.out,它对应的是标准的输出设备:控制台,是标准的输出流;
2>System.in返回的是InputStream类型,其read方法在未读到数据前,一直处于阻塞状
态。
示例:
import java.io.IOException;
import java.io.InputStream;
public class SystemInDemo {
public static void main(String[] args) {
// 创建输入流对象,System.in是标准的输入流
InputStream in = System.in;
// 创建一个StringBuilder作为缓冲区
StringBuilder sb = new StringBuilder();
int ch;
try {
while (true) {
ch = in.read();
// 当读到行终止符的时候,把缓冲区的数据赋给s
if (ch == '\r') {
continue;
}
if (ch == '\n') {
String s = sb.toString();
// 如果输入的是quit,退出循环
if ("quit".equals(s)) {
break;
}
// 每次打印一行数据到控制台
System.out.println(s);
// 清空缓冲区中的数据
sb.delete(0, sb.length());
} else {
// 将读到的字节添加到缓冲区
sb.append((char)ch);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流资源
try {
in.close();
} catch (IOException e) {
System.out.println("关闭流资源失败");
}
}
}
}
可以看到上面的方法比较复杂,而BufferedReader提供了一次读一行的方法readLine,
但是BufferedReader接收的对象是字符流类型的,而System.in返回的是一个字节流
类型的对象,那么这时我们就需要用到转换流InputStreamReader,它是字节流通向
字符流的桥梁。
练习:使用转换流完成上一个练习。
示例:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
public class TransStreamDemo {
public static void main(String[] args) {
// 获取键盘录入对象
InputStream in = System.in;
// 将字节流对象转换成字符流对象,使用转换流InputStreamReader
InputStreamReader isr = new InputStreamReader(in);
// 为了提高效率,将字符流进行缓冲区技术高效操作
BufferedReader br = new BufferedReader(isr);
// 输出流
OutputStream os = System.out;
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
String line = null;
try {
// 一次读取一行
while ((line = br.readLine()) != null) {
if ("quit".equals(line)) {
break;
}
// 每次打印一行数据到控制台
// System.out.println(line);
bw.write(line);
bw.newLine();
bw.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流资源
try {
bw.close();
} catch (IOException e) {
System.out.println("关闭流资源失败");
}
}
}
}
转换流是字节流和字符流之间的桥梁,当想要使用指定的字符集读取或写入数据时
必须要用到转换流中重载的一个构造方法去指定,如果不指定则使用平台默认的字
符集。