一、字节流和字符流的比较
项目
|
字节流(
主要用来处理字节或二进制对象)
|
字符流(
一个字符占两个字节),主要用来处理字符或字符串
|
抽象基类 |
InputStream
OutputStream
|
Reader
Writer
|
缓存技术 |
BufferedInputStream
(read)
BufferedOutputStream
|
BufferedReader
(readLine()读取一行)
BufferedWriter
|
方法
|
Reader类的read()方法返回类型为int :作为整数读取的字符(占两个字节共16位),范围在
0 到 65535
之间 (0x00-0xffff),如果已到达流的末尾,则返回 -1
|
inputStream的read()虽然也返回int,但由于此类是面向字节流的,一个字节占8个位,所以返回
0 到 255
范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。因此对于不能用0-255来表示的值就得用字符流来读取!比如说汉字(纯文本文件用字符流)。
|
使用场景 |
音频文件、图片、歌曲等
| 纯文本文件 |
其他 |
字节流在操作的时候本身是不会用到缓冲区(内存)的,是与文件本身直接操作的,而字符流在操作的时候是使用到缓冲区的
|
字节流在操作文件时,即使不关闭资源(
close
方法),文件也能输出,但是如果字符流不使用
close
方法的话,则不会输出任何内容,说明字符流用的是缓冲区,并且可以使用
flush
方法强制进行刷新缓冲区,这时才能在不
close
的情况下输出内容
|
二、流的使用技巧
- 流对象有很多,何时使用哪个流对象可通过以下方式判断
- 明确源和目的
目的:OutputStream、Writer
- 操作的数据是不是纯文本
否:字节流
- 当体系结束后,再明确具体使用哪个对象
源设备:内存 硬盘 键盘
目的设备:内存 硬盘 控制台
举例:将一个文本文件复制到另一个文本文件
源:
读取文件,所以需要InputStream、Reader,是纯文本文件所以需要Reader
文件的设备是硬盘,从硬盘上读取一个文件确定用FileReader对象
伪代码:
FileReader fr = new FileReader("c:\\1.txt");
考虑提高性能,使用缓存技术
BufferedReader bufr = new BufferedReader(fr);
目的:
写文件,需要OutputStream、Writer,纯文本文件所以需要Writer
文件要写到硬盘上故用FileWriter对象
伪代码
FileWriter fw = new FileWriter("c:\\2.txt");
BufferedWriter bufw = new BufferedWriter(fw);
三、字节流与字符流的转换
一般在操作输入输出内容就需要使用
字节
或字符流,但是有些时候需要将字符流变成字节流的形式,或者将字节流变为字符流的形式,所以
,就需要另外一组转换流的操作类。
写入数据-->内存中的字符数据-->字符流-->OutputStreamWriter-->字节流-->网络传输(或文件保存)
- OutputStreamWriter:
- Writer的子类
- 将输出的字符流变成字节流,即:将一个字符流的输出对象变成字节流的输出对象。
- OutputStreamWriter的构造方法:
- 如果以操作文件为例,则内存中的字符流数据需要通过OutputStreamWriter边成字节流才能保存到文件中。过程如下:
- 实例:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
public class OutputStreamWriterDemo {
public static void main(String[] args) throws IOException {
//字节流对象转成字符流
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
OutputStream out = System.out;
//字符流对象转成字节流对象
OutputStreamWriter osw = new OutputStreamWriter(out);
//缓冲区
BufferedWriter bufw = new BufferedWriter(osw);
String line = null;
while((line = bufr.readLine())!=null){
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
//换行 不用\r\n换行,是因为不兼容linux
bufw.newLine();
//字符流使用了缓冲区,所以必须flush,才能输出
bufw.flush();
}
//关闭流
bufr.close();
}
}
实例二
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
public class TestOutputStreamWriter {
public static void main(String[] args) throws Exception { // 所有的异常抛出
File f = new File("c:" + File.separator + "test.txt");
Writer out = null;
out = new OutputStreamWriter(new FileOutputStream(f));// 字节流变为字符流
out.write("hello world"); // 使用字符流输出
out.close();
}
}
- InputStreamReader
- Reader的子类。
- 将输入的字节流变成字符流,即:将一个字节流的输入对象变成字符流的输入对象。
- 如果以操作文件为例,读取时需要将读入的字节流对象通过InputStreamReader变成字符流,过程如下:
读取数据<--内存中的字符数据<--字符流<--InputStreamReader<--字节流<--网络传输(或文件保存)
实例一:
需求:当使用键盘录入一行数据之后,就将该行数据进行打印。
如果录入的数据时over,那么停止录入。
import java.io.IOException;
import java.io.InputStream;
public class SystemInDemo {
public static void main(String[] args) throws IOException {
InputStream in = System.in;//从键盘输入数据
StringBuilder sb = new StringBuilder();
while(true){
int ch = in.read();//读取一个字节
if(ch=='\r'){
continue;
}
if(ch=='\n'){
String s = sb.toString();
if("over".equals(s))
break;
System.out.println(s.toUpperCase());
//如果不加下面这一行,就会出现把键盘输入字符的累加
sb.delete(0, sb.length());
}
else
sb.append((char)ch);
}
}
}
通过上面的例子,在键盘录入一行数据并打印其大写,其实就是读取一行数据的原理,也就是readLine方法。
所以就想能不能直接使用readLine方法来完成键盘录入的一行数据的读取?
分析:
- readLine方法是字符流BufferedReader类中的方法,
- 键盘录入的read方法是字节流InputStream的方法。
故如果将字节流转换成字符流再使用字符流缓冲区的readLine方法?答案就是使用InputStreamReader类
代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class TransStreamDeml {
public static void main(String[] args) throws IOException {
//获取键盘录入对象,为字节流
InputStream in = System.in;
//将字节流对象转换成字符流对象,使用转换流InputStreamReader
InputStreamReader isr = new InputStreamReader(in);
//为了提高效率,将字符串进行缓冲区技术高效操作,使用BufferedReader
BufferedReader bufr = new BufferedReader(isr);
String line = null;
while((line = bufr.readLine())!=null){
if("over".equals(line))
break;
System.out.println(line.toUpperCase());
}
//关闭流
bufr.close();
}
}
输出结果:
luqh
LUQH
aaa
AAA
over
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.Reader;
public class TestInputStreamReader {
public static void main(String[] args) throws Exception {
// 所有的异常抛出
File f = new File("c:" + File.separator + "test.txt");
Reader reader = null;
// 将字节流变为字符流
reader = new InputStreamReader(new FileInputStream(f));
char c[] = new char[1024];
int len = reader.read(c);
reader.close();
System.out.println(new String(c, 0, len));
}
}
注意:
FileWriter和FileReader的说明: