黑马程序员——对IO流的总结

------- android培训java培训、期待与您交流! ----------

对IO流的总结

操作数据分为两种:字节流和字符流。

1.      字符流抽象类基类

①.public abstract class Writer

extends Object

implements Appendable, Closeable, Flushable

写入字符流的抽象类。子类必须实现的方法仅有 write(char[], int, int)、flush() 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。

②. public abstract class Reader

extends Object

implements Readable, Closeable

用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。

2.      基于字符流抽象基类的实现:

①.  Reader的直接子类:

public class BufferedReader

extends Reader

从字符输入流中读取文本,缓冲各个字符,从而提供字符、数组和行的高效读取。

可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。

通常,Reader 所作的每个读取请求都会导致对基础字符或字节流进行相应的读取请求。因此,建议用 BufferedReader 包装所有其 read() 操作可能开销很高的 Reader(如 FileReader 和 InputStreamReader)。例如,

 BufferedReader in

  = new BufferedReader(new FileReader("foo.in"));

 

将缓冲指定文件的输入。如果没有缓冲,则每次调用 read() 或 readLine() 都会导致从文件中读取字节,并将其转换为字符后返回,而这是极其低效的。

可以对使用 DataInputStream 进行按原文输入的程序进行本地化,方法是用合适的 BufferedReader 替换每个 DataInputStream。

②. public class BufferedWriter

extends Writer

将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。

该类提供了 newLine() 方法,它使用平台自己的行分隔符概念,此概念由系统属性 line.separator 定义。并非所有平台都使用新行符 ('\n') 来终止各行。因此调用此方法来终止每个输出行要优于直接写入新行符。

通常 Writer 将其输出立即发送到基础字符或字节流。除非要求提示输出,否则建议用 BufferedWriter 包装所有其 write() 操作可能开销很高的 Writer(如 FileWriters 和 OutputStreamWriters)。例如,

 PrintWriter out

  = new PrintWriter(new BufferedWriter(newFileWriter("foo.out")));

 

将缓冲 PrintWriter 对文件的输出。如果没有缓冲,则每次调用 print() 方法会导致将字符转换为字节,然后立即写入到文件,而这是极其低效的。

③. public class FileWriter

extends OutputStreamWriter

用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。要自己指定这些值,可以先在 FileOutputStream 上构造一个 OutputStreamWriter。

文件是否可用或是否可以被创建取决于基础平台。特别是某些平台一次只允许一个 FileWriter(或其他文件写入对象)打开文件进行写入。在这种情况下,如果所涉及的文件已经打开,则此类中的构造方法将失败。

FileWriter 用于写入字符流。要写入原始字节流,请考虑使用 FileOutputStream。

FileWriter与缓冲BufferedWriter直接相关。

Example:

import java.io.*;

public class IoDemo {

    public static void main(String[] args) throws IOException

    {

       FileWriter f = new FileWriter("1.txt");      

       f.write("abcde");

       f.close();

    }

}

程序简单分析:

FileWriter是用来写入字符文件的便捷类。FileWriter f = newFileWriter("1.txt")会在当前文件路径下产生文件1.txt。然后调用FileWriter类中Write方法向其写入字符串。

③.public class FileReader

extends InputStreamReader

用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要自己指定这些值,可以先在 FileInputStream 上构造一个 InputStreamReader。

FileReader 用于读取字符流。要读取原始字节流,请考虑使用 FileInputStream

FileReader与BufferedReader直接相关。

Example:

import java.io.*;

public class IoDemo {

public static voidmain(String[] args) throws IOException

{

        FileReader f = newFileReader("1.txt");

       

        int s ;

        while((s=f.read())!=-1)

        {

               System.out.println((char)s);        

        }

       

        f.close();

}

 

}

对程序简要分析:

FileReader f = newFileReader("1.txt"):读取磁盘文件1.txt。

注意:几个read方法的细节区分:

如果read方法读取单个字节,那么该方法返回的是字节的ASC码值。

如果read方法读取的不是单个字符,而是字符串,或者数组,返回就是读取的字节个数。

把一个文件复制到另一个文件:

Example1

直接复制:

import java.io.*;

public classIoDemo {

public static voidmain(String[] args) throwsIOException

{

        FileReaderf = newFileReader("1.txt");

        FileWriteru = newFileWriter("2.txt");

       

      

        while((s=f.read())!=-1)

        {

               System.out.println((char)s);

               u.write(s);

        }

        f.close();

        u.close();

}

 

}

分析:这个程序说明是:把1.txt文件中类容写入2.txt。通过read方法实现这一功能。而read无参数方法每次只能读取一个字符,然后没读一个字符,就把字符写入2.txt

而有参read方法的实现必须定义临时容器,来装入字符。然后再把临时容器中的字符装入2.txt

形如:char[] c = new char[20];

        while((s=f.read(c))!=-1)

        {

               System.out.println(c);

               u.write(c);

        }

具体实现:

import java.io.*;

public classIoDemo {

public static voidmain(String[] args) throwsIOException

{

        FileReaderf = newFileReader("1.txt");

        FileWriteru = newFileWriter("2.txt");

        int s;

        char[] c = new char[20];

        while((s=f.read(c))!=-1)

        {

               System.out.println(c);

               u.write(c);

        }

        f.close();

        u.close();

}

 

}

 

Example2

使用缓冲器复制:

import java.io.*;

public classIoDemo {

public static voidmain(String[] args) throwsIOException

{

        FileReaderf = newFileReader("1.txt");

        FileWriteru = newFileWriter("2.txt");

        BufferedWriterbuf = newBufferedWriter(u);

        BufferedReaderbff = newBufferedReader(f);

        int line;

        while((line=f.read())!=-1)

        {

               System.out.println((char)line);

               u.write(line);

        }

        f.close();

        u.close();

}

 

}

程序简单分析:

FileReader f = new FileReader("1.txt");与语句 BufferedReader bff = new BufferedReader(f);对应,在程序执行语句:read方法后,先把字符读到缓冲器BufferedReader中。后面语句建立于文本的关联。

⑵.FileWriter u = new FileWriter("2.txt");与语句 BufferedWriter buf = new BufferedWriter(u);关联。

在执行write方法后,先把字符逐个从磁盘读出来全部放在缓冲中,读完后,在刷新,把缓冲中的数据放在指定文件中。

3.      字节流

字节流抽象基类:

⑴.public abstract class InputStream

extendsObject

implementsCloseable

此抽象类是表示字节输入流的所有类的超类。

需要定义 InputStream 的子类的应用程序必须始终提供返回下一个输入字节的方法。

①.public class FileInputStream

extendsInputStream

FileInputStream 从文件系统中的某个文件中获取输入字节。哪些文件可用取决于主机环境。

FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader。

此类是InputStream基类直接子类。用于创建与文件系统文件相关联对象,用于读取文件数据。

 

⑵. public abstract class OutputStream

extendsObject

implementsCloseable, Flushable

此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器。

需要定义 OutputStream 子类的应用程序必须始终提供至少一种可写入一个输出字节的方法。

①. public class FileOutputStream

extendsOutputStream

 

文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流。文件是否可用或能否可以被创建取决于基础平台。特别是某些平台一次只允许一个 FileOutputStream(或其他文件写入对象)打开文件进行写入。在这种情况下,如果所涉及的文件已经打开,则此类中的构造方法将失败。

FileOutputStream 用于写入诸如图像数据之类的原始字节的流。

要写入字符流,请考虑使用 FileWriter。

其中FileInputStream和FileOutputStream是基于字节流的,常用于读写二进制文件。
读写字符文件建议使用基于字符的FileReader和FileWriter,省去了字节与字符之间的转换。
但这两个类的构造函数默认使用系统的编码方式,如果文件内容与系统编码方式不一致,可能会出现乱码。
在这种情况下,建议使用FileReader和FileWriter的父类:InputStreamReader/OutputStreamWriter,
它们也是基于字符的,但在构造函数中可以指定编码类型:InputStreamReader(InputStream 
in, Charset cs) 和OutputStreamWriter(OutputStreamout, Charset cs)。 

 

Example1:

创建一个MP3文件。

 import java.io.*;

public classIoDemo {

       publicstatic void main(String[] args) throwsIOException

       {

              FileOutputStream f = newFileOutputStream("k.mp3");

              f.write(3);

              f.close();

       }

 

}

②.复制MP3文件TamasWellsvalderfields.mp3

import java.io.*;

public classIoDemo {

       publicstatic void main(String[] args) throwsIOException

       {

              FileInputStream l = newFileInputStream("TamasWellsvalderfields.mp3");

              FileOutputStream f = newFileOutputStream("k.mp3");

              int line;

              while((line=l.read())!=-1)

              {

                     f.write(line);

              }

             

              l.close();

              f.close();

       }

 

}

程序简单分析:

FileInputStreaml = newFileInputStream("TamasWellsvalderfields.mp3");语句与mp3文件先关联。然后读取字节然后把它转存入k.mp3文件。

⑶.下面说一说转换问题:

即如何把字符转换为字节流,把字节流转换为字符流。以及其意义。

①.public class OutputStreamWriter

extends Writer

OutputStreamWriter是字符流通向字节流的桥梁:使用指定的 charset 将要向其写入的字符编码为字节。它使用的字符集可以由名称指定或显式给定,否则可能接受平台默认的字符集。

每次调用write() 方法都会针对给定的字符(或字符集)调用编码转换器。在写入基础输出流之前,得到的这些字节会在缓冲区累积。可以指定此缓冲区的大小,不过,默认的缓冲区对多数用途来说已足够大。注意,传递到此 write() 方法的字符是未缓冲的。

为了达到最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中以避免频繁调用转换器。例如:

 Writer out

   = newBufferedWriter(new OutputStreamWriter(System.out));

 

当你构造一个InputStreamReaderOutputStreamWriter时,转换规则定义了16Unicode和其它平台的特定表示之间的转换。
InputStreamReader
从一个数据源读取字节,并自动将其转换成Unicode字符。
如果你特别声明,InputStreamReade会将字节流转换成其它种类的字符流。
OutputStreamWriter
将字符的Unicode编码写到输出流,如果你的使用的不是Unicode字符,OutputStreamWriter会将你的字符编码转换成Unicode编码。

对于我们常用的GBK中,英文是占用1个字节,中文是2

  对于UTF-8,英文是1个,中文是3

  对于Unicode,英文中文都是2

Java的流操作分为字节流和字符流两种

 

使用其它字符转换
如果你需要从一个非本地(例如,从连接到一个不同类型的机器的网络连接读取)的字符编码读取输入,
你可以象下面这个程序那样,使用显式的字符编码构造

 

ir=new  InputStreamReader(System.in,  “8859_1″);


注:如果你通过网络连接读取字符,就应该使用这种形式。
否则,你的程序会总是试图将所读取的字符当作本地表示来进行转换,而这并不总是正确的。ISO 
8859-1
是映射到ASCIILatin-1编码模式。

 

②.public class InputStreamReader

extendsReader

InputStreamReader是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,否则可能接受平台默认的字符集。

每次调用InputStreamReader 中的一个read() 方法都会导致从基础输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从基础流读取更多的字节,使其超过满足当前读取操作所需的字节。

为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。例如:

 BufferedReader in

   = newBufferedReader(new InputStreamReader(System.in));

System.in

  从用户控制台读取数据字节。

 

③. public class BufferedInputStream

extendsFilterInputStream

作为另一种输入流,BufferedInputStream 为添加了功能,即缓冲输入和支持 mark 和 reset 方法的能力。创建 BufferedInputStream 时即创建了一个内部缓冲区数组。读取或跳过流中的各字节时,必要时可根据所包含的输入流再次填充该内部缓冲区,一次填充多个字节。mark 操作记录输入流中的某个点,reset 操作导致在从所包含的输入流中获取新的字节前,再次读取自最后一次 mark 操作以来所读取的所有字节。

InputStream还有一个子类:过滤器流java.io.FilterInputStream。过滤器流即能把基本流包裹起来,提供更多方便的用法。

FilterInputStream类的构造方法为FilterInputStream(InputStream),在指定的输入流之上,创建一个输入流过滤器。

FilterInputStream的常用的子类如下:

  过滤器输入流

  流的用途

BufferedInputStream

  缓冲区对数据的访问,以提高效率

DataInputStream

  从输入流中读取基本数据类型,如intfloatdouble或者甚至一行文本

LineNumberInputStream

  在翻译行结束符的基础上,维护一个计数器,该计数器表明正在读取的是哪一行。

PushbackInputStream

  允许把数据字节向后推到流的首部

OutputStream()

OutputStream的结构基本和InputStream是一样的。

 

④. public class BufferedOutputStream

extendsFilterOutputStream

该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入基础输出流中,而不必为每次字节写入调用基础系统。

Example1:

 

 

import java.io.*;

 

class  IODemo

{

       publicstatic void main(String[] args) throwsIOException

       {

              //获取键盘录入对象。

              //InputStream in = System.in;

 

              //将字节流对象转成字符流对象,使用转换流。InputStreamReader

              //InputStreamReader isr =new InputStreamReader(in);

 

              //为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader

 

              //BufferedReader bufr = newBufferedReader(isr);

 

 

              //键盘的最常见写法。

              BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

 

 

 

 

 

             

//            OutputStream out = System.out;

//            OutputStreamWriter osw = newOutputStreamWriter(out);

//            BufferedWriter bufw = newBufferedWriter(osw);

              BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));

 

 

 

 

              String line = null;

 

              while((line=bufr.readLine())!=null)

              {

                     if("over".equals(line))

                            break;

                     bufw.write(line.toUpperCase());

                     bufw.newLine();

                     bufw.flush();

              }

 

              bufr.close();

 

       }

}

程序说明:

BufferedReaderbufr = new BufferedReader(new InputStreamReader(System.in));

BufferedWriterbufw = new BufferedWriter(new OutputStreamWriter(System.out));

这两句语句使用了联合的的方式。那么为什么使用BufferedWriter和BufferedReader来装转换后的字节流呢??

我们的理解:BufferedWriter和BufferedReader不是和Filewriter和FileReader相关联的嘛?怎么能装人字节流??

说明:当你构造一个InputStreamReaderOutputStreamWriter时,转换规则定义了16Unicode和其它平台的特定表示之间的转换。
InputStreamReader
从一个数据源读取字节,并自动将其转换成Unicode字符。
如果你特别声明,InputStreamReade会将字节流转换成其它种类的字符流。
OutputStreamWriter
将字符的Unicode编码写到输出流,如果你的使用的不是Unicode字符,OutputStreamWriter会将你的字符编码转换成Unicode编码。

通过上面这句话:我们发现他们是把字节流转换为Unicode字符,而BufferedWriter和BufferedReader中存储的不是正好是Unicode编码值吗?

故而字符不用去转换,如果你非要转换也未尝不可。而读取的字节文件时必须要把其转换为计算机编码文件。

而我们的字节流缓冲里面存储字节流文件,用于提高效率。

最后做一个总结:

归根结底:讨论的是Unicode编码问题。

每次调用write() 方法都会针对给定的字符(或字符集)调用编码转换器。在写入基础输出流之前,得到的这些字节会在缓冲区累积。调用OutputStreamWriter中的方法write时会自动调用编码转换器。

如何把握字节文件与字符文件的区别:

例如图片文件:把它转换为字符文件,那么计算机认为他还是图片吗?显然不是,它变成了字符。

那么这些字符如何再变成图片呢?

答案就是再把它转换为字节流。

------- android培训java培训、期待与您交流! ----------

详情请查看:http://edu.csdn.net/heima

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值