字节流和字符流的介绍和使用
前提介绍:
位、字节、字符的区别
位(bit):是计算机 内部数据 储存的最小单位,11001100是一个八位二进制数。
字节(byte):是计算机中 数据处理 的基本单位,习惯上用大写 B 来表示,1B(byte,字节)= 8bit(位)
字符:是指计算机中使用的字母、数字、字和符号
-
ASCIIS码:
1个英文字母(不分大小写)= 1个字节的空间
1个中文汉字 = 2个字节的空间
1个ASCII码 = 一个字节 -
UTF-8编码:
1个英文字符 = 1个字节
英文标点 = 1个字节
1个中文(含繁体) = 3个字节
中文标点 = 3个字节 -
Unicode编码:
1个英文字符 = 2个字节
英文标点 = 2个字节
1个中文(含繁体) = 2个字节
中文标点 = 2个字节
1.字节流–传输过程中,传输数据的最基本单位是字节的流。
2.字符流–传输过程中,传输数据的最基本单位是字符的流。
3.字符编码方式不同:
有时候一个字符使用的字节数也不一样,比如ASCLL方式编码的字符,占一个字节;而UTF-8方式编码的字符,一个英文字符需要一个字节,一个中文需要三个字节。
字节数据是二进制形式的,要转成我们能识别的正常字符,需要选择正确的编码方式。我们生活中遇到的乱码问题就是字节数据没有选择正确的编码方式来显示成字符。
从本质上来讲,写数据(即输出)的时候,字节也好,字符也好,本质上都是没有标识符的,需要去指定编码方式。
但读数据的时候,如果我们需要去“看数据”,那么字节流的数据需要指定字符编码方式,这样我们才能看到我们能识别的字符;而字符流,因为已经选择好了字符编码方式,通常不需要再改了(除非定义的字符编码方式与数据原有的编码方式不一致!)
在传输方面上,由于计算机的传输本质都是字节,而一个字符由多个字节组成,转成字节之前先要去查表转成字节,所以传输时有时候会使用缓冲区。
-
字节流常用java类:字节流的类通常以stream结尾
1)字节输入流:
InputStream
FileInputStream
BufferedInputStreamInputStream作为一个抽象类,不能够创建对象,但可以作为“接口化编程”。
FileInputStream是用来读文件数据的流,所以它需要一个文件对象用来实例 化,这个文件可以是一个File对象,也可以是文件名路径字符串。
public void FileInputStreamTest()throws IOException{
/*
* 1.创建一个文件对象file
* 2.创建一个FileInputStream对象用来读取文件。
* 3.定义一个每次读取文件的大小。通常来说1024个字节比较合适。
* 4.当文件中数据已经读取完,inputStream.read(btyes))将返回-1.
*/
FileInputStream inputStream = null;
try {
File file = new File("E:\\test.txt");
inputStream = new FileInputStream(file);
byte[] btyes = new byte[1024];
int length;
while ((length = inputStream.read(btyes)) != -1) {
System.out.println("文本中的数据为:" + new String(btyes, 0, length));
}
}catch (Exception e){
System.out.println("读取文件错误:文件不存在获取文件格式不正确");
}finally {
if(inputStream != null){
inputStream.close();
}
}
}
缓存字节流BufferedInputStream:
BufferedInputStream相比于FileInputStream优化了系统调用,即通俗解释为:将数据保存了缓存区,但是减少磁盘IO并不是BufferedInputStream来做的,而是OS来做的。OS根据局部性原理,会预读部分的数据到内存缓存区(pagecache),这样下次IO如果读取数据在缓存命中了,就不需要等待磁盘的寻址,而是直接返回数据。
public void bufferInputStreamTest()throws IOException {
/*
* 1.创建一个文件对象file
* 2.创建一个FileInputStream对象用来读取文件。
* 3.bufferedInputStream创建时需要一个FileInputStream对象来作为文件读取源
* 3.定义一个每次读取文件的大小。通常来说1024个字节比较合适。
* 4.当文件中数据已经读取完,bufferedInputStream.read(btyes))将返回-1.
* 5.程序结束后,一定要关闭输入流
*/
BufferedInputStream bufferedInputStream = null;
FileInputStream inputStream = null;
try {
File file = new File("E:\\test1.txt");
inputStream = new FileInputStream(file);;
bufferedInputStream = new BufferedInputStream(inputStream);
byte[] btyes = new byte[1024];
int length;
while ((length = bufferedInputStream.read(btyes)) != -1) {
System.out.println("文本中的数据为:" + new String(btyes, 0, length));
}
}catch (Exception e){
System.out.println("读取文件错误:文件不存在获取文件格式不正确");
}finally {
if(inputStream != null){
inputStream.close();
}
if(bufferedInputStream != null){
bufferedInputStream.close();
}
}
}
字节输出流:字节流的类通常以stream结尾
2)字节输出流:
OutputStream
FileOutputStream
BufferedOutputStream
区别与用途:
- OutputStream是字节输出流的基类, OutputStream作为基类,给它的基类定义了几个通用的函数:
write(byte[] b):将b的长度个字节数据写到输出流中。
write(byte[] b,int off,int len):从b的off位置开始,获取len个字节数据,写到输出流中。
flush():刷新输出流,把数据马上写到输出流中。
close():关闭流,释放系统资源。
- FileOutputStream是用于写文件的输出流:
它除了可以使用基类定义的函数外,还实现了OutputStream的抽象函数write(int b):
write(int b):将b转成一个字节数据,写到输出流中。
public void FileOutputStreamTest()throws IOException{
/*
* 1.创建一个文件对象file,用于output的输出地址
* 2.创建一个FileOutputStream对象用来写文件数据。
* 3.写文件数据时,可以指定文件的编码方式。写文件完成后,一定要关闭输出流,释放资源。
*/
FileOutputStream outputStream = null;
try {
File file = new File("E:\\test2.txt");
outputStream = new FileOutputStream(file);
outputStream.write("88888888".getBytes("utf-8"));
}catch (Exception e){
System.out.println("写文件错误");
}finally {
if(outputStream != null){
outputStream.close();
}
}
}
- BufferedOutputStream像上面那个BufferedInputStream一样,都可以提高效率。
它除了可以使用基类定义的函数外,它还实现了OutputStream的抽象函数write(int b):
write(int b):将b转成一个字节数据,写到输出流中。
public void bufferOutputStreamTest()throws IOException{
/*
* 1.创建一个文件对象file
* 2.创建一个FileInputStream对象用来读取文件。
* 3.bufferedInputStream创建时需要一个FileInputStream对象来作为文件读取源
* 3.定义一个每次读取文件的大小。通常来说1024个字节比较合适。
* 4.当文件中数据已经读取完,bufferedInputStream.read(btyes))将返回-1.
* 5.程序结束后,一定要关闭输入流,必须先关闭文件输出流FileOutputStream,再关闭BufferedOutputStream。
*/
BufferedOutputStream bufferedOutputStream = null;
FileOutputStream outputStream = null;
try {
File file = new File("E:\\test1.txt");
outputStream = new FileOutputStream(file);;
bufferedOutputStream = new BufferedOutputStream(outputStream);
bufferedOutputStream.write("我是一个缓冲输出流".getBytes());
}catch (Exception e){
System.out.println("读取文件错误:文件不存在获取文件格式不正确");
}finally {
if(bufferedOutputStream != null){
bufferedOutputStream.close();
}
if(outputStream != null){
outputStream.close();
}
}
}
5 字符流常用java类:字符流的类通常以reader和writer结尾
1)字符输入流
Reader
InputStreamReader
FileReader
BufferedReader
Reader作为字符输入流的抽象基类,不能创建对象,但提供了以下方法:
read() :读取单个字符,返回结果是一个int,需要转成char;到达流的末尾时,返回-1
read(char[]cbuf):读取cbuf的长度个字符到cbuf这种,返回结果是读取的字符数,到达流的末尾时,返回-1
close() :关闭流,释放占用的系统资源。
InputStreamReader :
可以把InputStream中的字节数据流根据字符编码方式转成字符数据流。它除了可以使用基类定义的函数,它自己还实现了以下函数: read(char[] cbuf, int offset, int length):从cbuf 的 offset位置开始存储,读取length个字符到cbuf中,返回结果是实际读取的字符数,到达流的末尾时,返回-1
public void inputStreamReaderTest() throws IOException {
/*
* 1.创建一个文件对象file
* 2.创建一个FileInputStream对象用来读取文件。
* 3.定义一个每次读取文件的大小。通常来说1024个字节比较合适。
* 4.当文件中数据已经读取完,inputStreamReader.read()将返回-1.
*/
InputStreamReader inputStreamReader = null;
FileInputStream fileInputStream = null;
try {
File file = new File("E:\\test1.txt");
fileInputStream = new FileInputStream(file);
inputStreamReader = new InputStreamReader(fileInputStream);
char[] btyes = new char[1024];
int length;
while ((length = inputStreamReader.read(btyes , 0 , btyes.length)) != -1) {
System.out.println("文本中的数据为:" + new String(btyes, 0, btyes.length));
}
}catch (Exception e){
System.out.println("读取文件错误:文件不存在获取文件格式不正确");
}finally {
if(fileInputStream != null){
fileInputStream.close();
}
if(inputStreamReader != null){
inputStreamReader.close();
}
}
}
FileReader
内部实现了将数据源先转换为FileInputStream,然后再将FileInputStream中的字节数据转成根据字符编码方式转成字符数据流。
public void fileReaderTest()throws IOException{
FileReader fileReader = null;
try {
File file = new File("E:\\test1.txt");
fileReader = new FileReader(file);
char[] btyes = new char[1024];
int length;
while ((length = fileReader.read(btyes , 0 , btyes.length)) != -1) {
System.out.println("文本中的数据为:" + new String(btyes, 0, btyes.length));
}
}catch (Exception e){
System.out.println("读取文件错误:文件不存在获取文件格式不正确");
}finally {
if(fileReader != null) {
fileReader.close();
}
}
}
BufferedReader
可以把字符输入流进行封装,将数据进行缓冲,提高读取效率。它除了可以使用基类定义的函数,它自己还实现了以下函数:
read(char[]cbuf, int offset, int length):从cbuf 的 offset位置开始存储,读取length个字符到cbuf中,返回结果是实际读取的字符数,到达流的末尾时,返回-1
readLine():读取一个文本行,以行结束符作为末尾,返回结果是读取的字符串。如果已到达流末尾,则返回 null。
public void bufferedReaderTest()throws IOException{
/*
* 1.创建一个文件对象file
* 2.创建一个FileReader对象用来读取文件。
* 3.定义一个每次读取文件的大小。通常来说1024个字节比较合适。
* bufferedReader创建对象时需要一个FileReader对象作为数据输入源
* 4.当文件中数据已经读取完,bufferedReader.read(btyes))将返回-1.
*/
BufferedReader bufferedReader = null;
FileReader fileReader = null;
try {
File file = new File("E:\\test1.txt");
fileReader = new FileReader(file);
bufferedReader = new BufferedReader(fileReader);
char[] btyes = new char[1024];
int length;
while ((length = bufferedReader.read(btyes , 0 , btyes.length)) != -1) {
System.out.println("文本中的数据为:" + new String(btyes, 0, btyes.length));
}
/*
使用readLine()方法读取。
String line;
while ( (line = bufferedReader.readLine()) != null) {
System.out.println("文本中的数据为:" + line);
}
*/
}catch (Exception e){
System.out.println("读取文件错误:文件不存在获取文件格式不正确");
}finally {
if(bufferedReader != null) {
bufferedReader.close();
}
if(fileReader !=null){
fileReader.close();
}
}
}
2)字符输出流
Writer
OutputStreamWriter
FileWriter
BufferedWriter
Writer是字符输出流的抽象基类, ,它定义了以下几个函数
write(char[] cbuf) :往输出流写入一个字符数组。 write(int c) :往输出流写入一个字符。
write(String str) :往输出流写入一串字符串。
write(String str, int off, int len):往输出流写入字符串的一部分。 close() :关闭流,释放资源。 【这个还是抽象的,写出来是说明有这个关闭功能】
flush():刷新输出流,把数据马上写到输出流中。 【这个还是抽象的,写出来是说明有这个关闭功能】
OutputStreamWriter
可以使我们直接往流中写字符串数据,它里面会帮我们根据字符编码方式来把字符数据转成字节数据再写给输出流,它相当于一个中介\桥梁。
public void outputStreamWriterTest() throws IOException {
OutputStreamWriter outputStreamWriter = null;
FileOutputStream fileOutputStream = null;
try {
File file = new File("E:\\test1.txt");
fileOutputStream = new FileOutputStream(file);
outputStreamWriter = new OutputStreamWriter(fileOutputStream);
outputStreamWriter.write("我是一个字符输出流_你");
}catch (Exception e){
System.out.println("写文件错误");
}finally {
if( outputStreamWriter != null ){
outputStreamWriter.close();
}
if( fileOutputStream != null ){
fileOutputStream.close();
}
}
}
FileWriter
与OutputStreamWriter功能类似,我们可以直接往流中写字符串数据,FileWriter内部会根据字符编码方式来把字符数据转成字节数据再写给输出流。
public void fileWriterTest() throws IOException {
FileWriter fileWriter = null;
try {
File file = new File("E:\\test1.txt");
fileWriter = new FileWriter(file);
fileWriter.write("我是一个字符输出流_FileWriter");
}catch (Exception e){
System.out.println("写文件错误");
}finally {
if( fileWriter != null ){
fileWriter.close();
}
}
}
BufferedWriter
比FileWriter还高级一点,它利用了缓冲区来提高写的效率。它还多出了一个函数: newLine() :写入一个换行符。
public void bufferedWriterTest() throws IOException {
FileWriter fileWriter = null;
BufferedWriter bufferWriter = null;
try {
File file = new File("E:\\test1.txt");
fileWriter = new FileWriter(file);
bufferWriter = new BufferedWriter(fileWriter);
bufferWriter.write("我是一个字符输出流_BufferedWriter");
}catch (Exception e){
System.out.println("写文件错误");
}finally {
if(bufferWriter != null){
bufferWriter.close();
}
if( fileWriter != null ) {
fileWriter.close();
}
}
}