*/

.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #333;
background: #f8f8f8;
}

.hljs-comment,
.hljs-template_comment,
.diff .hljs-header,
.hljs-javadoc {
color: #998;
font-style: italic;
}

.hljs-keyword,
.css .rule .hljs-keyword,
.hljs-winutils,
.javascript .hljs-title,
.nginx .hljs-title,
.hljs-subst,
.hljs-request,
.hljs-status {
color: #333;
font-weight: bold;
}

.hljs-number,
.hljs-hexcolor,
.ruby .hljs-constant {
color: #099;
}

.hljs-string,
.hljs-tag .hljs-value,
.hljs-phpdoc,
.tex .hljs-formula {
color: #d14;
}

.hljs-title,
.hljs-id,
.coffeescript .hljs-params,
.scss .hljs-preprocessor {
color: #900;
font-weight: bold;
}

.javascript .hljs-title,
.lisp .hljs-title,
.clojure .hljs-title,
.hljs-subst {
font-weight: normal;
}

.hljs-class .hljs-title,
.haskell .hljs-type,
.vhdl .hljs-literal,
.tex .hljs-command {
color: #458;
font-weight: bold;
}

.hljs-tag,
.hljs-tag .hljs-title,
.hljs-rules .hljs-property,
.django .hljs-tag .hljs-keyword {
color: #000080;
font-weight: normal;
}

.hljs-attribute,
.hljs-variable,
.lisp .hljs-body {
color: #008080;
}

.hljs-regexp {
color: #009926;
}

.hljs-symbol,
.ruby .hljs-symbol .hljs-string,
.lisp .hljs-keyword,
.tex .hljs-special,
.hljs-prompt {
color: #990073;
}

.hljs-built_in,
.lisp .hljs-title,
.clojure .hljs-built_in {
color: #0086b3;
}

.hljs-preprocessor,
.hljs-pragma,
.hljs-pi,
.hljs-doctype,
.hljs-shebang,
.hljs-cdata {
color: #999;
font-weight: bold;
}

.hljs-deletion {
background: #fdd;
}

.hljs-addition {
background: #dfd;
}

.diff .hljs-change {
background: #0086b3;
}

.hljs-chunk {
color: #aaa;
}

#container {
padding: 15px;
}
pre {
border: 1px solid #ccc;
border-radius: 4px;
display: block;
background-color: #f8f8f8;
}
pre code {
white-space: pre-wrap;
}
.hljs,
code {
font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;
}
:not(pre) > code {
padding: 2px 4px;
font-size: 90%;
color: #c7254e;
background-color: #f9f2f4;
white-space: nowrap;
border-radius: 4px;
}
-->

字符流按字符个数输入、输出数据。

1.Reader类和FileReader类

Reader类是字符输入流的超类,FileReader类是读取字符的便捷类,此处的便捷是相对于其父类(另一个字符输入流)InputStreamReader而言的。

read()每单字符读取:

import java.io.*;

public class FileR {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("D:/temp/hello.txt"); int ch = 0;
while((ch=fr.read())!=-1) {
System.out.println((char)ch);
} fr.close();
}
}

read(char[] c)读取字符缓冲到字符数组:

import java.io.*;

public class FileR {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("D:/temp/hello.txt"); int len = 0;
char[] buf = new char[1024];
while ((len=fr.read(buf))!=-1) {
System.out.println(new String(buf,0,len)); //字符数组转换为字符串输出
} fr.close();
}
}

2.Writer类和FileWriter类

Writer类是字符输出流的超类,FileWriter类是输出字符的便捷类,此处的便捷是相对于其父类(另一个字符输出流)InputStreamWriter而言的。

import java.io.*;

public class FileW {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("d:/temp/hellow.txt"); fw.write("a你好,谢谢,再见!");
fw.flush(); //尽量每write一次就flush一次
fw.close();
}
}

flush()和close()的注意点:

(1).close()自带flush(),它在关闭流之前会自动先flush()一次。
(2).flush()后流还能继续使用,而close()后流就被关闭不可再被使用。
(3).为了防止数据丢失,应尽量每write一次就flush一次。但最后一次可不用flush(),因为close()自带flush()。

3.InputStreamReader类和OutputStreamWriter类

FileReader和FileWriter分别是InputStreamReader和OutputStreamWriter的便捷类,便捷类的意思是前两个类可以简化后两个类,同时又能达到相同的目的。实际上,FileReader和FileWriter是InputStreamReader和OutputStreamWriter的子类,等价于它们的默认形式。

InputStreamReader、OutputStreamWriter可以看作是字节流和字符流之间的桥梁。前者将字符按照字符集转换为字节(二进制格式)并读取字符,这称为编码(例如:a->97(01100001));后者将字节(二进制格式)按照字符集转换为字符并写入字符,这称为解码(例如:97(01100001)->a)

InputStreamReader、OutputStreamWriter的默认字符集采用的是操作系统的字符集,对于简体中文的Windows系统,默认采用的是GBK字符集。

以下是OutputStreamWriter以utf-8编码格式写入字符的示例:

import java.io.*;

public class OutputStreamW {
public static void main(String[] args) throws IOException {
WriteCN();
} public static void WriteCN() throws IOException {
OutputStreamWriter osw =
new OutputStreamWriter(new FileOutputStream("d:/temp/hellow.txt"),"utf-8");
//new OutputStreamWriter(new FileOutputStream("d:/temp/hellow.txt"));//采用默认gbk字符集写入
osw.write("a你好,谢谢,再见!!!");
osw.flush();
osw.close();
}
}

以下是InputStreamReader读取上述文件d:\temp\hellow.txt中字符的示例,因为hellow.txt中的字符编码为UTF-8,因此读取时必须也也utf-8读取。假如以默认的gbk字符集读取,由于每次读取2个字节,将会把utf-8字符(中文字符占用3个字节)切分开导致乱码:

import java.io.*;

public class InputStreamR {
public static void main(String[] args) throws IOException {
ReadCN();
} public static void ReadCN() throws IOException {
InputStreamReader isr =
new InputStreamReader(new FileInputStream("d:/temp/hellow.txt"),"utf-8");
// new InputStreamReader(new FileInputStream("d:/temp/hellow.txt"));//默认字符集,乱码 /* int ch = 0;
while ((ch=isr.read())!=-1) {
System.out.println((char)ch);
} */ int len = 0;
char[] buf = new char[1024];
while ((len=isr.read(buf))!=-1) {
System.out.println(new String(buf,0,len));
}
isr.close();
}
}

4.字节流、字符流的关系(编码、解码、编码表(字符集))

首先说明编码、解码和编码表(字符集)的关系。

编码:将字符根据编码表转换为二进制的0/1数字。
解码:将二进制根据编码表转换为字符。
编码表:

  1.ascii码表:使用一个字节中的7位二进制就能表示字母、数字、英文标点等字符。
  2.iso8859-1码表:(也即latin-1),使用一个字节中的8位二进制,其内包含了ascii码表中的字符,此外还扩展了欧洲一些语言的字符。
  3.GB2312:中国自编的编码表,2个字节,两个字节都是负数,收录了6700多个汉字。兼容ascii。
   GBK:K代表扩展的意思,是GB2312的扩展,占用2字节,大部分两个字节都是负数,但少数几个字符的第二个字节是正数,其内包含了GB2312的码表,收录了2万多个汉字。
   GB18030:新的编码表,变长(可能1、2、4字节),其内包含了GB2312和GBK的码表,收录了7万多个汉字。
  4.Unicode:收录了全世界几乎所有的字符,但无论什么字符都占用2个字节,不足两个字节的0占位。
  5.UTF-8:解决了unicode的缺点,它使用变长1-4字节来表示一个字符(空间能省则省),其中ascii部分仍占用1个字节(仍兼容ascii)。和Unicode不同的是,UTF-8中的中文字符占用3个字节。

因此,需要知道的是:

  • (1)所有字符集都兼容ascii码表;
  • (2)一般考虑字符集时,需要考虑的码表大致分:ascii、latin-1、GBK、utf-8。
  • (3)不同码表之间,因为编码、解码规则不一样,会导致文本乱码问题。
  • (4)GBK不会和ascii冲突。因为GBK即使有正数的字节,也一定是在第二个字节。因为解码时,如果读取的第一个字节为正数,则一定是ascii字符,如果读取的第一个字节为负数,则一定是中文字符,此时会继续读取下一个字节。
  • (5)以上都是文本的编码、解码。除了文本,还有媒体类数据,它们都有各自的编码、解码规则。实际使用过程中,采用什么方式编码、解码,取决于打开文件的程序,例如不能用记事本类程序打开媒体类(图片、音频、视频等)文件,不能用视频播放器打开文本文件。

再来说明字符流和字节流的关系,也就是实现字符流的原理。

对于字符串"abcde",使用字节流能够很轻松地读取、写入,但对于字符串"a你好,谢谢,再见!"这样的中文字符(假设它们是gbk编码的),无论是采用字节流的单字节读取还是以字节数组读取多个字节的方式都很难实现读取、写入。例如,一次读取2个字节,则第一次读取的两个字节为a和"你"的前一个字节,a的ascii码为97,"你"的前一个字节也是一个数值,假如为196,gbk对196也有对应的编码,假设对应的字符为"浣",于是第一次的两个字节经过解码,得到"a浣",而非"a你",这已经乱码了。而且很多时候,编码表中有某些数值并没有对应的字符,这时看到的就是乱七八糟的符号。

如果采用字符流读取、写入字符,则会先将其转换为字节数组,再对字节数组中的字节进行编码、解码。也就是说,字符流的底层还是字节流。而且根据不同的编码表(字符集),转换为字节存储到字节数组中时,数值和占用字节数也是不一样的。

以InputStreamReader和OutputStreamWriter这两个字符流按照utf-8字符集解析"你好"两个字符为例。

5.InputStreamReader/OutputStreamWriter和FileReader/FileWriter的区别

FileReader/FileWriter类是InputStreamReader/OutputStreamWriter类的子类,它们都能处理字符。区别是前者是后者的便捷类,是后者的默认形式。

也就是说,当InputStreamReader/OutputStreamWriter采用默认字符集时,它们和FileReader/FileWriter是等价的。即以下三条代码是等价的。

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));   //默认字符集
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"gbk"); //指定为默认字符集
FileReader fr = new FileReader("a.txt"); //使用便捷类FileReader

所以,如果采用的是默认字符集,最佳方式是采用FileReader/FileWriter,但如果需要指定字符集,则必须使用InputStreamReader/OutputStreamWriter。

6.字符流复制文本类文件

import java.io.*;

public class CopyFileByChar {
public static void main(String[] args) throws IOException {
copy("d:/temp/big.log","d:/temp/big_bak.log");
} public static void copy(String src,String dest) throws IOException {
//字符集必须设置正确
InputStreamReader isr = new InputStreamReader(new FileInputStream(src),"gbk");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(dest),"gbk"); int len = 0;
char[] buf = new char[1024];
while((len=isr.read(buf))!=-1) {
osw.write(buf,0,len);
osw.flush();
} osw.close();
isr.close();
}
}

7.操作行:BufferedReader类BufferedWriter类

它们是缓冲类字符流,分别用于创建带有输入、输出缓冲区的输入、输出字符流。

其实和字符数组的作用差不多,只不过设计为缓冲类后可以使用类的一些方法,最常用的是操作行的方法:

  • BufferedReader的readLine()方法:读取一行数据。只要遇到换行符(\n)、回车符(\r)都认为一行结束。当读取到流末尾时返回null。
  • BufferedWriter的newLine()方法:写入一个换行符。

例如,下面是用这两个类来复制文本文件d:\temp\big.log。

import java.io.*;

public class CopyByBuffer {
public static void main(String[] args) throws IOException {
copy("d:/temp/big.log","d:/temp/big_bak.log");
} public static void copy(String src,String dest) throws IOException { // src buffer & dest buffer
InputStreamReader isr = new InputStreamReader(new FileInputStream(src),"gbk");
BufferedReader bufr = new BufferedReader(isr); OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(dest),"gbk");
BufferedWriter bufw = new BufferedWriter(osw); String line = null;
while((line=bufr.readLine())!=null) {
bufw.write(line); //此write()方法继承自Writer的write(String str),而非重写后的write()
bufw.newLine();
bufw.flush();
} bufw.close();
bufr.close();
}
}

对于大文件来说,这BufferedReader类操作数据其实比字符数组的速度要慢,因为每次缓冲一行,一行才不到1k而已(除非行很长),而char[]通常都设置为好几k,一次就能读很多行。

注:若您觉得这篇文章还不错请点击右下角推荐,您的支持能激发作者更大的写作热情,非常感谢!

java IO(三):字符流的更多相关文章

  1. Java IO: 其他字符流(下)

    作者: Jakob Jenkov 译者: 李璟(jlee381344197@gmail.com) 本小节会简要概括Java IO中的PushbackReader,LineNumberReader,St ...

  2. Java IO编程——字符流与字节流

    在java.io包里面File类是唯一 一个与文件本身有关的程序处理类,但是File只能够操作文件本身而不能够操作文件的内容,或者说在实际的开发之中IO操作的核心意义在于:输入与输出操作.而对于程序而 ...

  3. Java IO之字符流和文件

    前面的博文介绍了字节流,那字符流又是什么流?从字面意思上看,字节流是面向字节的流,字符流是针对unicode编码的字符流,字符的单位一般比字节大,字节可以处理任何数据类型,通常在处理文本文件内容时,字 ...

  4. [Java IO]03_字符流

    Java程序中,一个字符等于两个字节. Reader 和 Writer 两个就是专门用于操作字符流的类. Writer Writer是一个字符流的抽象类.  它的定义如下: public abstra ...

  5. java IO之 字符流 (字符流 = 字节流 + 编码表) 装饰器模式

    字符流 计算机并不区分二进制文件与文本文件.所有的文件都是以二进制形式来存储的,因此, 从本质上说,所有的文件都是二进制文件.所以字符流是建立在字节流之上的,它能够提供字符 层次的编码和解码.列如,在 ...

  6. Java——IO类 字符流概述

    body, table{font-family: 微软雅黑} table{border-collapse: collapse; border: solid gray; border-width: 2p ...

  7. Java IO系统--字符流

    字符流:尽管字节流提供了处理任何类型输入/输出操作的足够功能,它们补鞥呢直接操作Unicode字符.字符流层次结构的顶层是Reader和Writer抽象类.类似于InputStream和OutputS ...

  8. Java IO(四--字符流基本使用

    在上一节,介绍了字节流的基本使用,本节介绍一下字符流的使用 Reader: public abstract class Reader implements Readable, Closeable { ...

  9. Java IO之字符流

    public static void main(String[] args) { FileWriter fw = null; try { fw = new FileWriter("/User ...

  10. java字节流和字符流,以及java文件操作

    A.首先说字节流:1.字节流在操作的时候不会用到缓冲区(也就是内存)2.字节流可用于任何类型的对象,包括二进制对象3.字节流处理单元为1个字节,操作字节和字节数组.InputStream是所有字节输入 ...

随机推荐

  1. Java之CountDownLatch ---控制线程执行顺序

    一,类介绍 这是java.util.concurrent包里的一个同步辅助类,它有两个主要的常用方法  countDown()方法以及await()方法.在完成一组正在其他线程中执行的操作之前,它允许 ...

  2. Android技术之-------电脑获取手机截图

    入吾QQ群183435019(学习 交流+唠嗑) 其实这个相当简单 应该会点ADB命令的人都会吧 一 下载一个ADB 如果你是学Android编程的,,Android SDK应该有吧,在Android ...

  3. 升级node与npm

    升级node 原文地址:https://lierabbit.cn/articles/3 一.安装 n 工具,这个工具的名称很短,方便输入 npm install -g n 二.升级node至长期版或者 ...

  4. Zabbix实战-简易教程(6)--Server端高可用

    3.4 server前端高可用    至此,单台Zabbix server环境已经搭建完成,为了达到高可用效果,我们需要通过2台服务器之间通过HA软件进行探测,一旦检测到主的server挂掉后,从的s ...

  5. linux(四)之元字符

    一直觉得linux是一个非常高深的东西,但是慢慢学过来其实就是一堆一堆的命令执行,让一个程序运行的结果. 只有你有毅力去学习,并且系统的去学习我相信没有什么恶意难道自己的.接下来我们一下来感受一下li ...

  6. CTF---Web入门第十三题 拐弯抹角

    拐弯抹角分值:10 来源: cwk32 难度:易 参与人数:5765人 Get Flag:2089人 答题人数:2143人 解题通过率:97% 如何欺骗服务器,才能拿到Flag? 格式:CTF{} 解 ...

  7. BZOJ 1002: [FJOI2007]轮状病毒【生成树的计数与基尔霍夫矩阵简单讲解+高精度】

    1002: [FJOI2007]轮状病毒 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 5577  Solved: 3031[Submit][Statu ...

  8. AtCoder Grand Contest 016

    在雅礼和衡水的dalao们打了一场atcoder 然而窝好菜啊…… A - Shrinking 题意:定义一次操作为将长度为n的字符串变成长度n-1的字符串,且变化后第i个字母为变化前第i 或 i+1 ...

  9. PHP编码规范及建议

    <h3 align="center">PHP编码规范及建议</h3>### 编码规范- PHP代码文件必须以 <?php 标签开始.```<?p ...

  10. 织梦dede在首页调用留言本

    织梦dedecms在首页调用留言本 . {dede:loop table=dede_guestbook sort=dtime row=10 titlelen=36 typeid=40 if=ische ...