Java_IO字符流(18)

字符流
字符流

CharArrayReader 和 CharArrayWriter

类似 ByteArrayInputStream 和 ByteArrayOutputStream ,处理的单位从字节改为了字符

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Test {
  public static void main(String[] args) {
    try {
      char[] charArry = new char[] {'a','b','c','d','e'};
      CharArrayReader car = new CharArrayReader(charArry);
      //CharArrayReader的mark方法没有marklimit限制的功能,传参无所谓
      car.mark(0);
      //读一个字符
      System.out.println(car.read()); //97
      //跳过1个字符
      car.skip(1);
      //读3个字符保存到buf
      char[] buf = new char[5];
      car.read(buf, 0, 3);
      System.out.println(String.valueOf(buf)); //cde
      //重置到mark标记的位置
      car.reset();
      car.read(buf, 0, 5);
      System.out.println(String.valueOf(buf)); //abcde
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

CharArrayWriter 字符数组输出流,写入的数据保存在其内部的字符数组缓冲区,缓冲区默认大小 32 个字符,可以自动扩容,可通过 toCharArray 和 toString 方法获取数据

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Test {
  public static void main(String[] args) {
    try {
      CharArrayWriter caw = new CharArrayWriter();
      //写入字符
      caw.write('A');
      //写入字符串
      caw.write("BC");
      //写入字符数组
      char[] charArry = new char[] {'a','b','c'};
      caw.write(charArry, 0, 3);
      System.out.println(caw); //ABCabc
      //append连续写入
      caw.append('0').append("123456789")
        .append(String.valueOf(charArry), 0, 3);
      System.out.println(caw); //ABCabc0123456789abc
      //获取长度
      System.out.println(caw.size()); //19
      //转换成char[]数组
      char[] buf = caw.toCharArray();
      System.out.println(String.valueOf(buf)); //ABCabc0123456789abc
      //写入另一个输出流中
      CharArrayWriter caw2 = new CharArrayWriter();
      caw.writeTo(caw2);
      System.out.println(caw2); //ABCabc0123456789abc
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

PipedReader 和 PipedWriter

类似 PipedInputStream 和 PipedOutputStream,同理,处理的单位从字节改为了字符

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
//发送线程
class Sender extends Thread {
  private PipedWriter out = new PipedWriter ();
  public PipedWriter  getPipedWriter() {
    return out;
  }
  @Override
  public void run() {
    //writeShortMessage();
    writeLongMessage();
  }
  //向管道输出流写入短数据
  private void writeShortMessage() {
    String strInfo = "short message" ;
    try {
      out.write(strInfo.toCharArray());
      out.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
  //向管道输出流写入长数据
  private void writeLongMessage() {
    StringBuilder sb = new StringBuilder();
    //1020个字节
    for (int i = 0; i < 102; i++) {
      sb.append("0123456789");
    }
    //26个字节
    sb.append("abcdefghijklmnopqrstuvwxyz");
    //str总长度为1046个字节
    String str = sb.toString();
    try {
      //写入管道输出流1046个字节
      out.write(str.toCharArray());
      out.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}
//接收线程
class Receiver extends Thread {
  private PipedReader in = new PipedReader();
  public PipedReader getPipedReader() {
    return in;
  }
  @Override
  public void run() {
    //readMessageOnce() ;
    readMessageContinued();
  }

  //从管道输入流中读取一次数据
  public void readMessageOnce() {
    char[] buf = new char[1024];
    try {
      int len = in.read(buf);
      System.out.println(new String(buf,0,len));
      in.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
  //从管道输入流读取数据,大于1024个字节时就停止读取
  public void readMessageContinued() {
    while(true) {
      char[] buf = new char[1024];
      try {
        int len = in.read(buf);
        System.out.println(new String(buf,0,len));
        //读满1024则继续读,小于1024则跳出循环
        if (len < 1024) break;
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    try {
      in.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}
public class Test {
  public static void main(String[] args) {
    Sender t1 = new Sender();
    Receiver t2 = new Receiver();
    PipedWriter out = t1.getPipedWriter();
    PipedReader in = t2.getPipedReader();
    try {
      //管道连接,两种连接方式等效
      //out.connect(in);
      in.connect(out);
      //使线程开始执行
      t1.start();
      t2.start();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

InputStreamReader 和 OutputStreamWriter

通过字节流读写中文

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public class Test {
  public static void main(String[] args) {
    try {
      FileOutputStream fos = new FileOutputStream("file.txt");
      //对于中文字符需要转换成字节数组
      fos.write("张三".getBytes());
      fos.close();
      FileInputStream fis = new FileInputStream("file.txt");
      //UTF-8编码长度是变化的,不能确定一个字符占多少字节
      //直接读字节然后拼接可能会出现乱码
      byte[] arr = new byte[6];
      fis.read(arr, 5 ,1);
      fis.read(arr, 0 ,5);
      System.out.println(new String(arr)); //��三�
    } catch(IOException e) {
      e.printStackTrace();
    }
  }
}

通过 InputStreamReader 和 OutputStreamWriter 将字节流转化为字符流,并指定编码方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Test {
  public static void main(String[] args) {
    try {
      File file = new File("file.txt");
      OutputStreamWriter out = new OutputStreamWriter(
        new FileOutputStream(file), "UTF-8");
      out.write("张三李四");
      out.close();
      InputStreamReader in = new InputStreamReader(
        new FileInputStream(file), "UTF-8");
      //读一个字符
      char c = (char) in.read(); //张
      System.out.println(c);
      //跳过1个字符
      in.skip(1);
      char[] buf = new char[2];
      in.read(buf, 0, buf.length);
      System.out.println(new String(buf)); //李四
      in.close();
    } catch(IOException e) {
      e.printStackTrace();
    }
  }
}

读写文件可以直接使用封装好的 FileReader 和 FileWriter

FileReader 和 FileWriter
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Test {
  public static void main(String[] args) {
    try {
      File file = new File("file.txt");
      //OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file));
      FileWriter out = new FileWriter(file);
      out.write("张三李四");
      out.close();
      //InputStreamReader in = new InputStreamReader(new FileInputStream(file));
      FileReader in = new FileReader(file);
      //读一个字符
      char c = (char) in.read();
      System.out.println(c); //张
      //跳过1个字符
      in.skip(1);
      char[] buf = new char[2];
      in.read(buf, 0, buf.length);
      System.out.println(new String(buf)); //李四
      in.close();
    } catch(IOException e) {
      e.printStackTrace();
    }
  }
}

注意,FileReader 虽然继承了 InputStreamReader,但没有实现可设置字符编码的构造函数,即FileReader 只能根据系统默认编码来解码,最好是保证了 Java 源码和读写的文件编码一致时才使用 FileReader 和 FileWriter

BufferedReader 和 BufferedWriter

类似 BufferedInputStream 和 BufferedOutputStream

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Test {
  public static void main(String[] args) {
    try {
      //file的内容为张三李四王五
      File file = new File("file.txt");
      //设置缓冲区初始大小为4
      BufferedReader in = new BufferedReader(new FileReader(file), 4);
      char[] buf = new char[5];
      //标记当前位置,即第1个元素a,并设置marklimit为1,不超过缓冲区
      //理论上之后只能再读1个字符,超过1个mark将失效
      in.mark(1);
      //读2个字符,即到第3个元素李
      in.read(buf, 0, 2);
      //因为没有超过缓冲区,即使超过了marklimit的限制mark也不会失效
      in.reset(); //重置到mark标记的位置a处

      in.mark(5); //设置marklimit为5,超过缓冲区一个字符
      //读5个字符,超出了buffer但不大于marklimit,则buffer自动扩容
      //4扩容2倍为8大于了marklimit的5,所以只扩容到5
      in.read(buf, 0, 5);
      in.reset();
      in.reset(); //只要mark没有失效则可以多次reset
      in.read(buf, 0, 5);
      //读完5个再读一个,使得超出缓冲区
      in.read();
      //共读了6个字符,超出了buffer且大于marklimit,则mark失效,清空buffer从头覆盖填充
      in.reset(); //mark失效,reset将会报IO异常Mark invalid
      in.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public class Test {
  public static void main(String[] args) {
    try {
      char[] charArr = {'张', '三', '李', '四', '王', '五'};
      File file = new File("file.txt");
      //设置缓冲区初始大小为4
      BufferedWriter bwr = new BufferedWriter(new FileWriter(file), 4);
      //将charArr前2个字符写入输出流
      bwr.write(charArr, 0, 2);
      //手动刷新缓冲区
      bwr.flush();
      //写入4个字符装满缓冲区
      bwr.write(charArr, 0, 4);
      //一次写入6个字符超过缓冲区
      bwr.write(charArr, 0, 6);
      bwr.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

BufferedWriter 的清空缓冲区跟 BufferedOutputStream 的不太一样,被 NIO 重写了,待研究

PrintWriter

类似 PrintStream

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Test {
  public static void main(String[] args) {
    final char[] arr = {'a', 'b', 'c', 'd', 'e'};
    try {
      //File file = new File("file.txt");
      // 创建文件对应FileOutputStream
      //PrintWriter out = new PrintWriter(new FileOutputStream(file));
      //PrintWriter out = new PrintWriter(file);
      PrintWriter out = new PrintWriter("file.txt");
      //0x41对应ASCII码的字母'A'
      out.write(0x41);
      out.print(0x41); //等价于out.write(String.valueOf(0x41));
      //追加写入
      out.append('B').append("CDE");
      String str = "张三";
      int num = 111;
      out.printf("%s : %d\n", str, num);
      out.println("张三李四"); //println方法会自动刷新缓冲区
      out.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}
//写入文件的内容为
//A65BCDE张三 : 111
//张三李四

以上内容是玉山整理的笔记,如有错误还请指出