一、概述。

java对数据的操作是通过流的方式。
java用于操作流的对象都在IO包中。
流按照操作数据不同分为两种,字节流和字符流。
流按照流向分为输入流,输出流。

输入输出的“入”和“出”是相当于内存来说的。

字符流:字节流读取文字字节数据后,不直接操作,而是先查指定的编码表,获取对应的文字,再对这个文字进行操作。简单来说就是字节流+码表

在IO流中,字节流的顶层父类是Writer和Reader。

二、java.io.FileWriter类。

public class FileWriterextends OutputStreamWriter

Writer

  |--OutputStreamWriter

    |--FileWriter

该类是操作字符文件的流,用于将数据写入到文件中。

1.方法摘要

(1).构造方法。

有两个重要的构造方法:

FileWriter(File file)
          根据给定的 File 对象构造一个 FileWriter 对象。
FileWriter(File file,
boolean append)

          根据给定的 File 对象构造一个 FileWriter 对象。

后者相对于前者来说多了一个boolean型的参数,该参数的作用是决定写入文件的方式是追加方式还是覆写方式。

默认的构造方法(前者)构造的FileWriter流对象向文件中写入的时候会默认的将文件的内容清空然后再写入,如果使用后者并将true传入该构造方法,则写入的方式就变成了追加方式。

(2).write方法。

该类没有自己的write方法,全部从父类或者超类中继承而来的write方法。

从OutputStreamWriter中继承而来的方法:

void write(char[] cbuf, int off, int len)
          写入字符数组的某一部分。
 void write(int c)

          写入单个字符。
 void write(String str,
int off, int len)

          写入字符串的某一部分。

从Writer中继承而来的write方法:

 void write(char[] cbuf)
          写入字符数组。
 void write(String str)
          写入字符串。

(3).flush方法。

void flush()
          刷新该流的缓冲。

该方法是从OutputStreamWriter中继承而来的,作用是将流中的数据数据刷到文件中。文件关闭前会默认调用此方法。如果不调用此方法,则当缓冲区满了也会自动调用该方法。

(4).close方法。

 void close()
          关闭此流,但要先刷新它。

2.flush与close比较

使用flush方法和close方法均可以保存文件,使用这两者各有什么好处?

举一个形象的例子我们在使用记事本软件的时候,会常常使用“保存”按钮保存住当前内容到文件,如果没有保存,关闭文件的时候就会出现提示信息“是否要保存文件内容?”,然后再关闭文件。在这个例子中,“保存”相当于flush的功能,而关闭文件则相当于close的功能,经常点保存按钮的目的就是为了防止断电丢失和节约内存。

因此,使用flush的目的就是为了防止断电丢失和节约内存,因此在写程序的时候,尽量写入一句刷新一句;如果文件不关闭,最明显的影响就是“删不掉文件”。

3.FileWriter细节:换行和续写

在Windows字符文件中,文件的换行符是\r\n,在linux中则为\n,这样很有可能导致同一个java程序在linux中的运行结果和在windows中的运行结果不一致。解决方法是使用System类中的方法getProperty,得到当前系统中的行分隔符。具体用法:String line_sparator=System.getProperty("line.separator");

如果想要在已存在的文件末尾添加新内容,则需要使用第二种构造方法。

4.异常处理标准模板。

 package p02.FileWriterDemo.p01.ExceptionCaptureDemo;

 import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException; public class ExceptionHandleDemo { public static void main(String[] args) {
standarExceptionHandleDemo();
} private static void standarExceptionHandleDemo() {
FileWriter fw=null;
FileReader fr=null;
try
{
fr=new FileReader("c:\\source.txt");//可能会抛出FileNotFindException
fw=new FileWriter("c:\\aim.txt");//可能会抛出IOException
char buf[]=new char[1024];
int length=fr.read(buf);
fw.write(buf,0,length);
fw.flush();
}
catch(IOException e)
{
System.out.println("读写失败!");
}
finally
{
if(fr!=null)
{
try
{
fr.close();
} catch (IOException e)
{
//异常处理程序
}
}
if(fw!=null)
{
try
{
fw.close();
} catch (IOException e)
{
//异常处理程序
}
}
}
} }

二、FileReader类。

public class FileReaderextends InputStreamReader

Reader

  |--InputStreamReader

    |--FileReader

在IO流中,字符输入流的顶层父类是Reader类。

1.方法摘要。

(1)构造方法。

FileReader(File file)
          在给定从中读取数据的 File 的情况下创建一个新 FileReader
FileReader(FileDescriptor fd)

          在给定从中读取数据的 FileDescriptor 的情况下创建一个新
FileReader
FileReader(String fileName)

          在给定从中读取数据的文件名的情况下创建一个新 FileReader

构造方法必须传递一个参数,如果参数不正确,则会抛出FileNotFindException异常。

(2)read方法。

该流不具备自己特有的read方法,其读取方法全部继承自父类或者其超类。

从InputStreamReader中继承的方法:

 int read()
          读取单个字符。
 int read(char[] cbuf,
int offset, int length)

          将字符读入数组中的某一部分。

从Reader类中继承的方法:

 int read(char[] cbuf)
          将字符读入数组。
 int read(CharBuffer target)
          试图将字符读入指定的字符缓冲区。

经常使用的方法只有两个:read()与read(char[] cbuf);前者返回字符的编码值,后者返回字符的长度。

(3)close方法。略。

2.读取字符使用的两种方法。

方法1:使用read()读取一个字符。

 private static void function1() throws IOException {
FileReader fr=new FileReader("c:\\source.java");
int ch;
while((ch=fr.read())!=-1)
{
System.out.println((char)ch);
}
fr.close();
}

方法2:使用read(buf)读取到缓冲数组。

 private static void function2() throws IOException {
FileReader fr=new FileReader("c:\\source.java");
char buf[]=new char[1024];
int length=0;
while((length=fr.read(buf))!=-1)
{
System.out.print(new String(buf,0,length));
}
fr.close();
}

3.复制文本文件小练习。

第一种方法:一次读取一个字符。

 private static void withoutParameterFunction() {
FileReader fr=null;
FileWriter fw=null;
try
{
fr=new FileReader("c:/source.java");
fw=new FileWriter("c:/aim.java");
int ch;
while((ch=fr.read())!=-1)
{
fw.write(ch);
fw.flush();
}
}
catch(IOException e)
{
throw new RuntimeException("读写失败!");
}
finally
{
if(fr!=null)
{
try
{
fr.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
if(fw!=null)
{
try
{
fw.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
}

第二种方法:一次读取多个字符。

 private static void withParameterFunction() {
FileReader fr=null;
FileWriter fw=null;
try
{
fr=new FileReader("c:/source.java");
fw=new FileWriter("c:/aim.java");
char buf[]=new char[1024];
int len;
while((len=fr.read(buf))!=-1)
{
fw.write(buf, 0, len);
fw.flush();
}
}
catch(IOException e)
{
throw new RuntimeException("读写失败!");
}
finally
{
if(fr!=null)
{
try
{
fr.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
if(fw!=null)
{
try
{
fw.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
}

三、BufferedWriter缓冲流。

public class BufferedWriterextends Writer

Reader

  |--BufferedWriter

1.方法摘要。

(1)构造方法

BufferedWriter(Writer out)
          创建一个使用默认大小输出缓冲区的缓冲字符输出流。
BufferedWriter(Writer out,
int sz)

          创建一个使用给定大小输出缓冲区的新缓冲字符输出流。

可以看出,构造方法中必须传入一个Writer对象,该对象是被缓冲的对象,如果该对象不存在则缓冲流就没有了存在的意义。

该缓冲流使用了装饰设计模式,是对Writer类的功能增强。

(2)write方法。

该类中的write方法和FileWriter中的方法一致,不赘述。

但是应当注意,虽然方法相同,但是底层实现却完全不同。该类的write方法是将数据写入缓冲区中,而FileWriter的write方法是将数据写入文件(先写入流中)。

(3)flush方法和close方法。

void close()
          关闭此流,但要先刷新它。
 void flush()

          刷新该流的缓冲。

特别需要注意的是,close方法调用的是Writer的close方法,所以关闭流的时候一旦关闭了缓冲流就会关闭Writer的流,所以只需要关闭缓冲流就可以了。

(4)特有的方法:newLine。

public void newLine()throws IOException
写入一个行分隔符。行分隔符字符串由系统属性 line.separator 定义,并且不一定是单个新行 ('\n') 符。

该方法封装了System.getProperty("line.separator");的动作,使得程序员提高了工作效率。

四、BufferedReader类。

public class BufferedReaderextends Reader

Reader

  |--BufferedReader

该类是字符输入缓冲流,用于缓冲Reader类的流对象,以提高输入效率。

1.方法摘要。

(1)构造方法。

BufferedReader(Reader in)
          创建一个使用默认大小输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in,
int sz)

          创建一个使用指定大小输入缓冲区的缓冲字符输入流。

该构造方法和BufferedWriter类似,也有两个,其中一个可以指定缓冲区的大小。

(2)read方法。

该read方法和FileReader中的read方法相同,不赘述。但是应当注意,虽然方法名完全相同,但是底层的实现却完全不同,该流对象操作的对象是内存(从内存中读,所以速度更快),而FileReader操作的是文件。

(3)特有方法:readLine()

public String readLine()throws IOException
读取一个文本行。通过下列字符之一即可认为某行已终止:换行 ('\n')、回车 ('\r') 或回车后直接跟着换行。
返回:
包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
抛出:
IOException - 如果发生 I/O 错误

由于该流是针对字符的流,所以对于“行”有着特殊的方法,它是根据回车符来判断一行是否结束的(在文件中体现为“\r\n”),而不是根据肉眼观察到底有几行。

(4)close方法。

不赘述。

五、是用缓冲区的方式复制文本文件。

第一种方法:一次读取一个字符

 private static void CopyTextFileUseRead() {
BufferedReader br=null;
BufferedWriter bw=null;
FileReader fr=null;
FileWriter fw=null;
try
{
fr=new FileReader("c:/source.java");
fw=new FileWriter("c:/aim.java");
br=new BufferedReader(fr);
bw=new BufferedWriter(fw);
int ch;
while((ch=br.read())!=-1)
{
bw.write(ch);
bw.flush();
}
}
catch(IOException e)
{
throw new RuntimeException("读写失败!");
}
finally
{
if(fr!=null)
try
{
fr.close();
}
catch(IOException e)
{
}
if(fw!=null)
{
try
{
fw.close();
} catch (IOException e)
{
}
} }
}

第二种方法:使用readLine方法,一次读取“一行”

 private static void CopyTextFileUseReadLine() {
BufferedReader br=null;
BufferedWriter bw=null;
FileReader fr=null;
FileWriter fw=null;
try
{
fr=new FileReader("c:/source.java");
fw=new FileWriter("c:/aim.java");
br=new BufferedReader(fr);
bw=new BufferedWriter(fw);
String buf=null;
while((buf=br.readLine())!=null)
{
bw.write(buf);
bw.newLine();
bw.flush();
}
}
catch(IOException e)
{
throw new RuntimeException("读写失败!");
}
finally
{
if(fr!=null)
try
{
fr.close();
}
catch(IOException e)
{
}
if(fw!=null)
{
try
{
fw.close();
} catch (IOException e)
{
}
}
}
}

六、模拟BufferedReader类。

对于BufferedReader类,有三个个方法经常被使用:read、readLine、close,现在自定义类MyBufferedReader,模拟三个方法,以加深对BufferedReader的理解。

首先read与reanLine原理图:

MyBufferedReader类:

 class MyBufferedReader
{
private Reader r;
private int size=1024;//默认的缓冲区大小
private char buf[];//存放字符的缓冲数组
private int pos=0;//记录当前的指针
private int count=0;//记录数组的长度
public MyBufferedReader(Reader r)
{
this.r=r;
buf=new char[size];
}
public MyBufferedReader(Reader r,int size)
{
this.r=r;
this.size=size;
buf=new char[size];
}
public int read() throws IOException
{
if(count==0)
{
count=r.read(buf);
pos=0;
}
if(count<0)
return -1;
char ch=buf[pos];
pos++;
count--;
return ch;
}
public String readLine() throws IOException
{
StringBuilder sb=new StringBuilder();
int ch;
while((ch=read())!=-1)
{
if(ch=='\r')
continue;
if(ch=='\n')
return sb.toString();
sb.append((char)ch);
}
if(sb.length()!=0)//这里进行健壮性判断是必不可少的,否则很有可能丢失最后一行
return sb.toString();
return null;
}
public void close() throws IOException
{
r.close();
}
}

此类中,有一句应当特别注意:

在readLine方法中:

if(sb.length()!=0)//这里进行健壮性判断是必不可少的,否则很有可能丢失最后一行
return sb.toString();

这句不能丢,因为丢了这个判断很有可能会丢失最后一行(如果最后一行没有回车)。

通过模拟,可以发现,BufferedReader封装了一个缓冲数组,该缓冲数组缓存r中的数据,以提高程序对数据读取效率。该数组当然也可以自定义,之前已经演示,不赘述。

 六、BufferedReader和BufferedWriter类使用了装饰模式

所谓的装饰模式是针对某一类进行功能增强的类。在这里,BufferedReader类对Reader(及其子类)类进行了功能增强,BufferedWriter类对Writer类(及其子类)进行了功能增强。

使用装饰模式和使用继承都能达到增强某一类的功能的目的,但是使用装饰模式更加灵活。装饰模式是针对某一类进行功能增强,而如果使用继承设计模式,则只能针对某个特别的类进行功能增强。比如,如果使用继承达到功能增强的目的,则继承层次将会变成这样:

Reader

  |--InputStreamReader

    |--FileReader

      |--BufferedFileReader

    |--BufferedInputStreamReader

相对于原本的继承层次:

Reader

  |--InputStreamReader

    |--FileReader

  |--BufferedReader

来说,前者很明显多了一个缓冲流,但是绝不仅仅是多了一个,因为Reader的子类很多,如果针对每个具体的类进行功能增强,则整个继承体系将会变得非常臃肿。但是如果使用装饰模式进行功能增强,则可以几乎不需要改变原本的继承层次,只需要多出一个缓冲流即可。由此可见,使用装饰模式要灵活很多,因此,如果想要针对某一类进行功能增强,最好使用装饰模式而不是使用继承的方式

【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流 之 字符流

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

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

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

随机推荐

  1. Exploiting the Circulant Structure of Tracking-by-Detection with Kernels(二)

    之前给导师汇报时,主要是论文涉及公式的一些推导

  2. POJ 3641 快速幂+素数

    http://poj.org/problem?id=3641 练手用,结果念题不清,以为是奇偶数WA了一发 #include<iostream> #include<cstdio> ...

  3. linux下VMware安装出现的问题解决

    linux下VMware安装出现的问题解决 linux下VMware安装出现的问题解决 报错信息 问题1liboverlay-scrollbar.so和libunity-gtk-module.so加载 ...

  4. 13 HashTable抽象哈希表类——Live555源码阅读(一)基本组件类

    这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 本文由乌合之众 lym瞎编,欢迎转载 http://www.cnblogs.com/oloroso ...

  5. 前端之css、JavaScript和DOM

    css position 一般组合 relative+absolute,以relative为父元素,absolute依照relative进行定位. opcity: 0.5 透明度 z-index: 层 ...

  6. RPC(Remote Procedure Call Protocol)——远程过程调用协议 学习总结

        首先了解什么叫RPC,为什么要RPC,RPC是指远程过程调用,也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需 ...

  7. jsoup解析HTML

    Connection conn = Jsoup.connect(String url); conn.data("txtBill", key);// 设置关键字查询字段 Docume ...

  8. python 的dict的update 方法的一点诡秘的行为

    如下: >>> 'a%s'%a 'a{1: 0, 2: 0}' >>> for k,v in a.items(): a.update(k=v) >>&g ...

  9. IPC-----POSIX消息队列

    消息队列可以认为是一个链表.进程(线程)可以往里写消息,也可以从里面取出消息.一个进程可以往某个消息队列里写消息,然后终止,另一个进程随时可以从消息队列里取走这些消息.这里也说明了,消息队列具有随内核 ...

  10. centos vim配置高亮语法和格式化粘贴

    centos vim配置高亮语法和格式化粘贴 设置vim别名和高亮grep词语 echo -e "\nalias vi=vim\nalias grep='grep --color'\n&qu ...