AVA中IO流-字节流与字符流比较与转换

本文详细对比了字节流与字符流的特性,包括它们的抽象基类、使用场景、缓存技术和方法。同时,介绍了流的使用技巧,包括如何根据数据类型选择合适的流对象。此外,文章还阐述了字节流与字符流的转换方法,以及实例代码演示了转换流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


一、字节流和字符流的比较
项目
字节流( 主要用来处理字节或二进制对象)
字符流( 一个字符占两个字节),主要用来处理字符或字符串
抽象基类
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 的情况下输出内容
二、流的使用技巧
  1. 流对象有很多,何时使用哪个流对象可通过以下方式判断
  • 明确源和目的
          源:InputStream、Reader
          目的: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);

三、字节流与字符流的转换

       在整个IO包中,实际上就是分为 字节 流和字符流,但是除了这两个流之外,还存在了一组字节流-字符流的转换类。
      一般在操作输入输出内容就需要使用 字节 或字符流,但是有些时候需要将字符流变成字节流的形式,或者将字节流变为字符流的形式,所以 ,就需要另外一组转换流的操作类。
  • OutputStreamWriter:
    • Writer的子类
    • 将输出的字符流变成字节流,即:将一个字符流的输出对象变成字节流的输出对象。
    • OutputStreamWriter的构造方法:
                     public OutputStreamWriter(OutputStream out)
  • 如果以操作文件为例,则内存中的字符流数据需要通过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的说明:
  • 从JDK文档中可以知道FileOutputStream是OutputStream的直接子类。FileInputStream也是InputStream的直接子类。
  • 但是在字符流文件的两个操作类却有一些特殊,FileWriter并不直接是Writer的子类,而是OutputStreamWriter的子类,而FileReader也不直接是Reader的子类,而是InputStreamReader的子类,那么从这两个类的继承关系就可以清楚的发现,不管是使用字节流还是字符流实际上最终都是以字节的形式操作输入输出流的。也就是说,传输或者从文件中读取数据的时候,文件里真正保存的数据永远是字节
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值