*/

.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. 使用xUnit为.net core程序进行单元测试(中)

    第一部分: http://www.cnblogs.com/cgzl/p/8283610.html 下面有一点点内容是重叠的.... String Assert 测试string是否相等: [Fact] ...

  2. C#学习笔记-迭代器模式

    什么是迭代器模式? 迭代器模式(Iterator):提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示. 何时使用迭代器模式? 当需要访问一个聚合对象,而且不管这些对象是什么都需要 ...

  3. 11、ABPZero系列教程之拼多多卖家工具 拼团提醒功能页面实现

    上一篇讲解了拼团提醒逻辑功能实现,现在继续实现页面功能. Core项目 打开AbpZeroTemplate-zh-CN.xml语言文件,在末尾添加如下代码: 文件路径:D:\abp version\a ...

  4. Jquery_基础(三) ajax与json

    什么是ajax? AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML). AJAX 不是新的编程语言,而是一种使用现有标准的新方法. ...

  5. H5+Ajax+WebApi实现文件下载(进度条,多文件)

    前言 踩过的坑 1.WebAPI跨域 2.Jquery ajax低版本不支持XHR 2功能 3.Jquery ajax不支持Deferred的process事件 4.IE下文件名乱码问题 功能实现 & ...

  6. mvc中传入字典的模型项的类型问题

    刚项目一直报这个错,找了一会发现忘了给他模型项了,我把这个小问题纪录下来,希望你们别犯这个小错

  7. 小乔注:java关键字static

    static是java中又一重要的关键字,在一定环境下使用,可以提高程序的运行性能,优化程序的结构.其主要应用有以下几方面: 1.static修饰的成员变量,称为类变量/静态变量,以实现所有对象对该成 ...

  8. wifi入侵思路

    一.得到wifi密码   系统:Kali Linux   工具:Aircrack-ng,EWSA   方法:   1.WEP加密:deauth攻击:得到足够报文直接破解.   2.WPA加密:deau ...

  9. python写zip破解器

    浏览桌面依然平静,!!!!等等..怎么有个压缩包 打开一看!!!156.txt???waht the fuck? 卧槽还有密码!!!!!! 但是我不知道╮(╯▽╰)╭该怎么办呢! 很简单,python ...

  10. metasploit魔鬼训练营(收集外围信息)

    现在我们时空穿越,来到魔鬼训练营的主角身上,现在我们要训练,对V公司进行渗透测试,回想起总监说的情报收集 1,外围搜集,指的是自己假装是一个正常用户来搜集情报 我们开启msf用auxiliary/sc ...