字符是我们能读懂的一些文字和符号,但在计算机中存储的却是我们看不懂的byte 字节,那这就存在关于字符编码解码的问题。所以在学习Io流的字符流前我们先了解些关于编码问题。

一、字符集与字符编码

1、什么要有字符集

  我们在计算机屏幕上看到的是实体化的文字,而在计算机存储介质中存放的实际是二进制的比特流。那 么在这两者之间的转换规则就需要一个统一的标准,否则就会出现乱码了现象;小伙伴QQ上传过来的文件,在我们本地打开又乱码了。 于是为了实现转换标准,各种字符集标准就出现了。

2、什么是字符集

  简单的说字符集就规定了某个文字对应的二进制数字存放方式(编码)和某串二进制数值代表了哪个文字(解 码)的转换关系。

3、什么是字符编码

  字符编码:计算机只能存储0,1之类2进制数字,怎么样让它表示那么多各种各样的字符呢?就需要对各种字符指定一个数值的编码代号,这就是字符编码。如:a这个字符,在ascii字符集编码表中对应的编号是97,而“中”在gb2312字符集中对应的编号是:16进制是D6D0 10进制是54992 。通过编号就可以找到计算机对应字符。不用将那么复杂的字符保存在计算机中,只需要保存它代号就好。字符集只是指定了一个集合中有哪些字符,而字符编码,是为这个集合中所有字符定义个编号,这就是字符集与编码区别所在。

计算机中只保存字符在某字符集中对应的字符编号值,计算机只需要维持一份字符集清单,当读到这种编号值(编码),就在对应字符清单中找出该字符显示出来即可。字符大小颜色都是程序按照字符样式绘制而成的。如图:

 4、乱码

  如果一个字符按照一个字符集存储在计算机中(编码),而使用另一种字符集读取该字符(解码)那就会出现乱码现象。应为计算机中存储使用的字码表与读取使用的字码表不匹配。

二、java中字符的编码与解码

    计算机中存储和传输的基本单位是字节,而我们看到的信息是字符(人能看懂的)。

   编码:编码就是真实字符与二进制串的对应关系,真实字符转换成二进制串。编码是信息从一种形式或格式转换为另一种形式的过程也称为计算机编程语言的代码简称编码。用预先规定的方法将文字、数字或其它对象编成数码,或将信息、数据转换成规定的电脉冲信号。

java中的编码:

在byte[] buffer=string.getBytes();中,如果没有给.getBytes();指定字符集,那么在编码过程中,就会按照系统默认的编码格式进行编码。

String str="中";
byte [] b_gbk=str.getBytes("GBK");
byte [] b_utf=str.getBytes("UTF-8");
byte [] b_unic=str.getBytes("UTF-16");
byte [] b_Iso=str.getBytes("ISO8859-1");

解码:解码就是二进制串与真实字符的对应关系,二进制串转换成真实字符。将信息从已经编码的形式恢复到编码前原状的过程。也就是用特定方法把数码还原成它所代表的内容或将电脉冲信号、光信号、无线电波等转换成它所代表的信息、数据等的过程。

java中的解码:

 //str按照 GBK编码 后 ,再按照GBK解码
String str_1=new String(str.getBytes("GBK"), "GBK");
String str_2=new String(str.getBytes("UTF-8"), "UTF-8");
String str_3=new String(str.getBytes("UTF-32"), "UTF-32");
String str_4=new String(str.getBytes("ISO8859-1"), "ISO8859-1");

 三、字符流

字符流:字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串。字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的。字符流操作的是缓冲区(当我们对文件进行读写操作时如果不调用close() 或 flush()方法时不能看到数据的变化)。

(一)、字符输入流

将磁盘(文件)中的数据读入内存中

Reader 是所有的输入字符流的父类,它是一个抽象类。

public abstract class Reader implements Readable, Closeable {
protected Object lock;
protected Reader() {
this.lock = this;
}
protected Reader(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
//试图将字符读入指定的字符缓冲区。缓冲区可照原样用作字符的存储库:所做的唯一改变是 put 操作的结果。不对缓冲区执行翻转或重绕操作。
public int read(java.nio.CharBuffer target) throws IOException {}
//读取单个字符。在字符可用、发生 I/O 错误或者已到达流的末尾前,此方法一直阻塞。 用于支持高效的单字符输入的子类应重写此方法。
public int read() throws IOException { }
//将字符读入数组。在某个输入可用、发生 I/O 错误或者已到达流的末尾前,此方法一直阻塞。
public int read(char cbuf[]) throws IOException {}
// 将字符读入数组的某一部分。在某个输入可用、发生 I/O 错误或者到达流的末尾前,此方法一直阻塞。
abstract public int read(char cbuf[], int off, int len) throws IOException;
//跳过字符。在某个字符可用、发生 I/O 错误或者已到达流的末尾前,此方法一直阻塞。
public long skip(long n) throws IOException {}
//判断是否准备读取此流。
public boolean ready() throws IOException { }
//判断此流是否支持 mark() 操作。默认实现始终返回 false。子类应重写此方法。
public boolean markSupported() {}
//标记流中的当前位置。对 reset() 的后续调用将尝试将该流重新定位到此点。并不是所有的字符输入流都支持 mark() 操作。
public void mark(int readAheadLimit) throws IOException { }
//重置该流。如果已标记该流,则尝试在该标记处重新定位该流。如果已标记该流,则以适用于特定流的某种方式尝试重置该流,
//例如,通过将该流重新定位到其起始点。并不是所有的字符输入流都支持 reset() 操作,有些支持 reset() 而不支持 mark()。
public void reset() throws IOException { }
//关闭该流并释放与之关联的所有资源。在关闭该流后,再调用 read()、ready()、mark()、reset() 或 skip() 将抛出 IOException。关闭以前关闭的流无效。
abstract public void close() throws IOException;
}

InputStreamReader:将字节输入流转换为字符输入流。是字节流通向字符流的桥梁,可以指定字节流转换为字符流的字符集。够造方法如下:

//InputStreamReader(InputStream in)  创建一个使用默认字符集的 InputStreamReader。
// InputStreamReader(InputStream in, String charsetName) 创建使用指定字符集的 InputStreamReader。

InputStreamReader 读取文件内容的三种方式

    //public int read() throws IOException
//读取单个字符。在字符可用、发生 I/O 错误或者已到达流的末尾前,此方法一直阻塞。
public static void readOneStr() throws IOException{
InputStreamReader isr=new InputStreamReader(new FileInputStream("E:\\test\\javaIo\\1.txt"));
int ch=0;
while((ch=isr.read())!=-1){
System.out.print((char)ch);
}
isr.close();
}
//public int read(char[] cbuf) throws IOException
//将字符读入数组。在某个输入可用、发生 I/O 错误或者已到达流的末尾前,此方法一直阻塞。
public static void readOneStrArr() throws IOException{
InputStreamReader isr=new InputStreamReader(new FileInputStream("E:\\test\\javaIo\\1.txt"));
char [] ch=new char[1024];
int len=0;
while((len=isr.read(ch))!=-1){
System.out.print(new String(ch,0,len));
}
isr.close();
}
//public int read(char[] cbuf) throws IOException
//将字符读入数组的某一部分。在某个输入可用、发生 I/O 错误或者到达流的末尾前,此方法一直阻塞。
public static void readOneStrArrLen() throws IOException{
InputStreamReader isr=new InputStreamReader(new FileInputStream("E:\\test\\javaIo\\1.txt"));
char [] ch=new char[1024];
int len=0;
while((len=isr.read(ch,0,ch.length))!=-1){
System.out.print(new String(ch,0,len));
}
isr.close();
}

FileReader:该类从InputStreamReader类继承而来,可以关联源文件。

1、构造方法

FileReader fr = new FileReader(String fileName);//使用带有指定文件的String参数的构造方法。创建该输入流对象。并关联源文件。

该类读取文件方式与InputStreamReader基本一样,使用该类代码较简洁建议使用 ,例如:

public static void main(String[] args) throws IOException {
FileReader fr=new FileReader("E:\\test\\javaIo\\1.txt");
char[] ch=new char[1024];
int len=0;
while((len=fr.read(ch))!=-1){
System.out.println(new String(ch,0,len));
}
fr.close();
}

BufferedReader(缓冲流):字节输入缓冲流,从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。BufferedReader 由Reader类扩展而来,提供通用的缓冲方式文本读取,而且提供了很实用的readLine。

该类读取文本的方法就是父类Reader提供的read()系列方法。在这里演示他自己特有的方法readLine()

    //public String readLine()throws IOException读取一个文本行。通过下列字符之一即可认为某行已终止:换行 ('\n')、回车 ('\r') 或回车后直接跟着换行。
public static void readLineTest() throws IOException{
BufferedReader br=new BufferedReader(new FileReader("E:\\test\\javaIo\\1.txt"));
String str=null;
while((str=br.readLine())!=null){
System.out.println(str);
}
br.close();
}

LineNumberReader(关于行号缓冲流):它是BufferedReader的子类,LineNumberReader比BufferedReader多了个功能,就是可以获取当前行号 getLineNumber()与设置起始行号 setLineNumber(int lineNumber)。默认情况下,行编号从 0 开始。该行号随数据读取在每个行结束符处递增,并且可以通过调用 setLineNumber(int) 更改行号。但要注意的是,setLineNumber(int) 不会实际更改流中的当前位置;它只更改将由 getLineNumber() 返回的值。

public static void main(String[] args) throws IOException {
LineNumberReader lnr=new LineNumberReader(new FileReader("E:\\test\\javaIo\\2.txt"));
//public void setLineNumber(int lineNumber)设置当前行号。 如果不设置该值 行号默认从0开始
lnr.setLineNumber(10);
String str=null;
while((str=lnr.readLine())!=null){
//public int getLineNumber()获得当前行号。
System.out.println(lnr.getLineNumber()+":"+str);
}
lnr.close();
}

(二)、字符输出流

将内存中的数据按照字符形式写入磁盘(文件)中

Writer:是所有的输出字符流的父类,它是一个抽象类。该抽象类的方法如下:

public abstract class Writer implements Appendable, Closeable, Flushable {
private char[] writeBuffer;
private final int writeBufferSize = 1024;
protected Object lock;
protected Writer() {
this.lock = this;
}
protected Writer(Object lock) { }
// 写入单个字符。要写入的字符包含在给定整数值的 16 个低位中,16 高位被忽略。 用于支持高效单字符输出的子类应重写此方法。
public void write(int c) throws IOException { }
//写入字符数组。
public void write(char cbuf[]) throws IOException { }
//写入字符数组的某一部分。
abstract public void write(char cbuf[], int off, int len) throws IOException;
//写入字符串
public void write(String str) throws IOException { }
//写入字符串的某一部分。
public void write(String str, int off, int len) throws IOException { }
//将指定字符序列添加到此 writer。
public Writer append(CharSequence csq) throws IOException { }
//将指定字符序列的子序列添加到此 writer.Appendable。
public Writer append(CharSequence csq, int start, int end) throws IOException {
CharSequence cs = (csq == null ? "null" : csq);
write(cs.subSequence(start, end).toString());
return this;
}
//将指定字符添加到此 writer
public Writer append(char c) throws IOException {
write(c);
return this;
}
//刷新该流的缓冲。如果该流已保存缓冲区中各种 write() 方法的所有字符,则立即将它们写入预期目标。
//然后,如果该目标是另一个字符或字节流,则将其刷新。因此,一次 flush() 调用将刷新 Writer 和 OutputStream 链中的所有缓冲区。
abstract public void flush() throws IOException;
//关闭此流,但要先刷新它。在关闭该流之后,再调用 write() 或 flush() 将导致抛出 IOException。关闭以前关闭的流无效
abstract public void close() throws IOException;
}

OutputStreamWriter:将字节输出流转为字符输出流,是字符流通向字节流的桥梁,可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。常用够造方法如下:

 //public OutputStreamWriter(OutputStream out, String charsetName); 可以设置编码格式
//public OutputStreamWriter(OutputStream out)创建使用默认字符编码的 OutputStreamWriter。

OutputStreamWriter将内存中的数据写入文件的5中方式如下:

    //public void write(int c)throws IOException
//写入单个字符。要写入的字符包含在给定整数值的 16 个低位中,16 高位被忽略。
public static void writerOneChar() throws IOException{
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("E:\\test\\javaIo\\1.txt"));
osw.write(97);//char ch=(char)97;
osw.write('c');
osw.flush();
osw.close();
}
//public void write(char[] cbuf)throws IOException 写入字符数组。
public static void writerCharArr() throws IOException{
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("E:\\test\\javaIo\\1.txt"));
char [] ch=new char[]{'我','爱','中','国'};
osw.write(ch);
osw.flush();
osw.close();
}
//public abstract void write(char[] cbuf,int off,int len)throws IOException 写入字符数组的某一部分。
public static void writerCharArrLen() throws IOException{
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("E:\\test\\javaIo\\1.txt"));
char [] ch=new char[]{'我','爱','中','国'};
osw.write(ch,0,ch.length-1);
osw.flush();
osw.close();
}
//public void write(String str) throws IOException 写入字符串。
public static void writerOneStr() throws IOException{
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("E:\\test\\javaIo\\1.txt"));
osw.write("中国");
osw.flush();
osw.close();
}
//public void write(String str,int off, int len)throws IOException; 写入字符串的某一部分。
public static void writerOneStrArrLen() throws IOException{
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("E:\\test\\javaIo\\1.txt"));
String str="我爱中国";
osw.write(str,0,str.length()-2);
osw.flush();
osw.close();
}

FileWriter:类从OutputStreamWriter类继承而来。该类按字符向流中写入数据,可以关联源文件。主要够造函数:

FileWriter fw = new FileWriter(String fileName);//创建字符输出流类对象和已存在的文件相关联。文件不存在的话,并创建。 如:FileWriter fw = new FileWriter("C:\\demo.txt");
FileWriter fw = new FileWriter(String fileName,boolean append);//创建字符输出流类对象和已存在的文件相关联,并设置该该流对文件的操作是否为续写。
// 如:FileWriter fw = new FileWriter("C:\\demo.txt",ture); //表示在fw对文件再次写入时,会在该文件的结尾续写,并不会覆盖掉。

该类写文件方式与OutputStreamWriter基本一样,例如:

public static void test() throws IOException{
FileWriter fw=new FileWriter("E:\\test\\javaIo\\4.txt");
String str="爱我中华";
fw.write(str);
fw.flush();
fw.close();
}

BufferedWriter(缓冲流):字节输出缓冲流,将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。 可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。 该类提供了 newLine() 方法,它使用平台自己的行分隔符概念,此概念由系统属性 line.separator 定义。该类写入文本的方法就是父类Writer提供的write()系列方法,在这里我们演示他特有的newLine( )方法。

    public static void newLineTest() throws IOException{
BufferedWriter bw=new BufferedWriter(new FileWriter("E:\\test\\javaIo\\2.txt"));
bw.write("爱我");
bw.newLine();
bw.write("中华");
bw.flush();
bw.close();
}
//结果:(加入了换行符)
  爱我
  中华

四、文本文件的copy

1、使用转换流copy文件:

/**
* 在这里使用了指定编码方式的对象,一般我们使用平台默认编码方式的够造函数创建对象
* @throws IOException
*/
public static void fileCopy() throws IOException{
InputStreamReader isr=new InputStreamReader(new FileInputStream("E:\\test\\javaIo\\1.txt"),"utf-8");
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("E:\\test\\javaIo\\4.txt"),"utf-8");
char [] ch=new char[1024];
int len=0;
while((len=isr.read(ch))!=-1){
osw.write(ch,0,len);
osw.flush();
}
osw.close();
isr.close();
}

2、使用关联源文件的字符流copy文件:

public static void fileCopyFile() throws IOException{
FileReader fr=new FileReader("E:\\test\\javaIo\\1.txt");
FileWriter fw=new FileWriter("E:\\test\\javaIo\\2.txt");
char [] ch=new char[1024];
int len=0;
while((len=fr.read(ch))!=-1){
fw.write(ch, 0, len);
fw.flush();
}
fw.close();
fr.close();
}

3、字节缓冲流+转换流实现文件的copy

public static void fileCopy() throws IOException{
BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("E:\\test\\javaIo\\1.txt")));
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("E:\\test\\javaIo\\2.txt")));
char [] ch=new char[1024];
int len=0;
while((len=br.read(ch))!=-1){
bw.write(ch, 0, len);
bw.flush();
}
bw.close();
br.close();
}

4、字节缓冲流+源文件字符流实现文件copy

public static void bufferedReaderTest1() throws IOException{
BufferedReader br=new BufferedReader(new FileReader("E:\\test\\javaIo\\1.txt"));
BufferedWriter bw=new BufferedWriter(new FileWriter("E:\\test\\javaIo\\2.txt"));
char [] ch=new char[1024];
int len=0;
while((len=br.read(ch))!=-1){
bw.write(ch, 0, len);
bw.flush();
}
bw.close();
br.close();
}

5、使用缓冲流特定的行方法(readLine(),newLine() )实现文件的copy

//BufferedReader   public String readLine() throws IOException
//读取一个文本行。通过下列字符之一即可认为某行已终止:换行 ('\n')、回车 ('\r') 或回车后直接跟着换行。
// BufferedWriter bw.newLine();//写入一个行分隔符。行分隔符字符串由系统属性 line.separator 定义,并且不一定是单个新行 ('\n') 符。
public static void copyLine() throws IOException{
BufferedReader br=new BufferedReader(new FileReader("E:\\test\\javaIo\\1.txt"));
BufferedWriter bw=new BufferedWriter(new FileWriter("E:\\test\\javaIo\\2.txt"));
String str=null;
while((str=br.readLine())!=null){
bw.write(str);
bw.newLine();//写入一个行分隔符。行分隔符字符串由系统属性 line.separator 定义,并且不一定是单个新行 ('\n') 符。
bw.flush();
}
bw.close();
br.close();
}

java IO流 之 字符流的更多相关文章

  1. JAVA IO 字节流与字符流

    文章出自:听云博客 题主将以三个章节的篇幅来讲解JAVA IO的内容 . 第一节JAVA IO包的框架体系和源码分析,第二节,序列化反序列化和IO的设计模块,第三节异步IO. 本文是第一节.     ...

  2. Java IO 字节流与字符流 (五)

    Java的IO流分为字符流(Reader,Writer)和字节流(InputStream,OutputStream),字节流顾名思义字节流就是将文件的内容读取到字节数组,然后再输出到另一个文件中.而字 ...

  3. java IO(三):字符流

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

  4. Java IO 字节流与字符流 (三)

    概述 IO流用来处理设备之间的数据传输 Java对数据的操作时通过流的方式 Java用于操作流的对象都在IO包中 流按操作的数据分为:字节流和字符流 流按流向不同分为:输入流和输出流 IO流常用基类 ...

  5. Java IO 字节流与字符流 (二)

    1. 什么是流 Java中的流是对字节序列的抽象,我们可以想象有一个水管,只不过现在流动在水管中的不再是水,而是字节序列.和水流一样,Java中的流也具有一个“流动的方向”,通常可以从中读入一个字节序 ...

  6. Java——IO类,字符流写数据

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

  7. Java——IO类,字符流读数据

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

  8. 缓冲字符流 java.io.BufferedWriter ,java.io.BufferedReader,缓冲字符输出流:PrintWriter

    package seday07; import java.io.IOException;import java.io.PrintWriter; /*** @author xingsir * 缓冲字符流 ...

  9. java io流(字符流) 文件打开、读取文件、关闭文件

    java io流(字符流) 文件打开 读取文件 关闭文件 //打开文件 //读取文件内容 //关闭文件 import java.io.*; public class Index{ public sta ...

随机推荐

  1. jQuery实战

    1.获取标签在文档中的位置 var left = $('.selected').offset().left; var top = $('.selected').offset().top; 2.获取选中 ...

  2. js转换数据库中DateTime字段类型

    在程序中,从数据库中读取到的日期时间类型数据一般是这种格式:"/Date(1355109408000+0800)/" 要经过js函数处理变为格式:'2012-12-10 11:05 ...

  3. winform下的简易播放器

    编写这个播放器,遇到很多问题,比如目前只实现了wav音频文件的播放,而对于这个图中中间所标注的按钮 不能实现让其暂停的功能,同时当点击的时候,让其文本变为"▷",对于这部分功能不知 ...

  4. js转盘抽奖

    这个是很简易的转盘,只用了html,css,js 通过css产生一个转盘上的指针,用js动态改变css中的transparent改变指针的角度.再添加一个背景图片类似于奖项的转盘 <!DOCTY ...

  5. Curator 异步获取结果

    原声的ZooKeeper 的CRUD API有同步和异步之分,对于异步API,需要传递AsyncCallback回调.对于getData,getChildren,exists这三个API,还可以设置W ...

  6. SPRING SECURITY JAVA配置:Web Security

    在前一篇,我已经介绍了Spring Security Java配置,也概括的介绍了一下这个项目方方面面.在这篇文章中,我们来看一看一个简单的基于web security配置的例子.之后我们再来作更多的 ...

  7. HTML5 使用application cache 接口实现离线数据缓存

    1.配置缓存文件 cache manifest MIME TYPE:text/cache-manifest文件名称:name.appcache作用:用于配置需要缓存的文件 2.使用方法 在服务器上添加 ...

  8. “LC.exe”错误

    错误“LC.exe”已退出,代码为 -1. 可能的原因是: 这个第三方组件是个商业组件,他在组件的主使用类定义了 LicenseProvider(typeof(LicFileLicenseProvid ...

  9. Cannot create file "C:\Users\Administrator\AppData\Local\Temp\EditorLineEnds.ttr"

    这个问题的产生根据网上搜集的资料是因为微软的新补丁KB2970228和KB2982791限制了字体文件的使用机制, 而EditorLineEnds.ttr是delphi字体临时文件, 这就导致了del ...

  10. canvas 学习

    <!DOCTYPE html><html lang="en"><head> <meta charset="utf-8" ...