黑马程序员——java IO流中的字节流和字符流

 

 ---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------

1.       什么是IO流:

流是一个抽象的概念。当Java程序需要从数据源读取数据时,会开启一个到数据源的流。数据源可以是文件,内存或者网络等。同样,当程序需要输出数据到目的地时也一样会开启一个流,数据目的地也可以是文件、内存或者网络等。流的创建是为了更方便地处理数据的输入输出。

IO流根据处理数据类型的不同分为:字符流和字节流;根据数据流向不同分为:输入流和输出流

Java 的流式输入/输出建立在四个抽象类的基础上:InputStream, OutputStream,Reader和Writer。它们用来创建具体流式子类。尽管程序通过具体子类执行输入/输出操作,但顶层的类定义了所有流类的基本通用功能。

InputStream 和OutputStream 设计成字节流类。Reader 和Writer 为字符流设计。字节流类和字符流类形成分离的层次结构。一般说来,处理字符或字符串时应使用字符流类,处理字节或二进制对象时应用字节流类。

操作文件流时,不管是字节流还是字符流都可以按照以下的方式进行:

a)        使用File类找到一个文件;

b)       通过File类的对象去实例化字节流或字符流的子类;

c)        进行字节(字符)的读、写操作;

d)       关闭文件流;

2.       Java中的字节流:

字节流类以InputStream 和OutputStream为顶层。下面分别介绍这两种字节流:

a)        字节输入流InputStream:

InputStream 是所有的输入字节流的父类,它是一个抽象类。它的子类中ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。PipedInputStream 是从与其它线程共用的管道中读取数据。ObjectInputStream 和所有FilterInputStream 的子类都是装饰流。

它们的继承关系简要表示如下:

InputStream:是表示字节输入流的所有类的超类。

     |--- FileInputStream:从介质中获得输入字节。可用于读取诸如图像数据之类的原始字节流。

     |--- FilterInputStream:装饰流,包含其他一些输入流,它将这些流用作其基本数据源,它可以直接传输数据或提供一些额外的功能。

        |--- BufferedInputStream:该类实现缓冲的输入流。

     |--- ObjectInputStream:装饰流

     |--- PipedInputStream:从与其它线程共用的管道中读取数据。

b)       字节输出流OutputStream:

OutputStream 是所有的输出字节流的父类,它是一个抽象类。它的子类中ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。PipedOutputStream 是向与其它线程共用的管道中写入数据,ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰流。

它们的继承关系简要表示如下:

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

     |--- FileOutputStream:是用于将数据写入介质的输出流。

     |--- FilterOutputStream:此类是过滤输出流的所有类的超类。

        |--- BufferedOutputStream:该类实现缓冲的输出流。

        |--- PrintStream:

        |--- DataOutputStream:

     |--- ObjectOutputStream:

     |--- PipedOutputStream:向与其它线程共用的管道中写入数据。

3.       字节流中的FileInputStream 与 FileOutputStream:

FileInputStream 类创建一个能从文件读取字节的InputStream 类,它的两个常用的构造方法如下:

FileInputStream(String filePath):其中的filePath为文件的路径;

FileInputStream(File file)

FileInputStream 类中的read方法中有两个最常用:

read():可以一次读取一个字节;

read(byte[] b):可一次读取多个字节存入字节数组中。

FileOutputStream 创建了一个可以向文件写入字节的类OutputStream,它常用的构造方法如下:

FileOutputStream(String filePath):其中的filePath为文件的路径;

FileOutputStream(File file)

FileOutputStream(String filePath, booleanappend):append若为true,代表在原文件末尾追写数据,而不进行数据覆盖;

FileOutputStream中的write()方法,有两个最常用:

write(int b):可将指定字节写入文件输出流,注意,b的类型虽然是int(四个字节),但是write方法会截取最后八位,所以最终写入文件输出流的只是一个字节。

write(byte[] b, int off, int len):将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。

下面用FileInputStream 与 FileOutputStream流对一个jpg文件进行复制,代码示例如下:

importjava.io.*;

 

publicclass FileOutputStreamDemo {

       public static void main(String[] args){

              FileInputStream fis=null;  //创建输入流;

              FileOutputStream fos=null; //创建输出流;

              try {

                     fis = newFileInputStream("C:/Users/FC-JAVA/Desktop/tmp/1.jpg");

                     fos = newFileOutputStream("C:/Users/FC-JAVA/Desktop/tmp/copy.jpg");

                     byte[] bts = newbyte[1024];   //创建字节数组用于存储读取到的字节;

                     int len = 0;

                     while((len = fis.read(bts)) != -1) {

                            fos.write(bts, 0,len);

                     }

              } catch (Exception e) {

                     // TODO: handle exception

              }finally{

                     try {

                            fis.close();    //关闭输入流;

                     } catch (IOException e) {

                            // TODOAuto-generated catch block

                            e.printStackTrace();

                     }

                     try {

                            fos.close();   //关闭输出流;

                     } catch (IOException e) {

                            // TODOAuto-generated catch block

                            e.printStackTrace();

                     }                  

              }

       }

}

4.       Java中的字符流:

字符流类以Reader和Writer为顶层。下面分别介绍这两种字节流:

Reader:用于读取字符流的抽象类,其子类如下:

    |---BufferedReader:从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。 可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。

        |---LineNumberReader:跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。

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

       |---FileReader:用来读取字符文件的便捷类。

    |---CharArrayReader:

    |---StringReader:

Writer:写入字符流的抽象类。其子类如下:

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

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

        |---FileWriter:用来写入字符文件的便捷类。

    |---PrintWriter:

    |---CharArrayWriter:

|---StringWriter:

5.       字符流中的FileReader 与 FileWriter:

FileReader类创建了一个可以读取文件内容的Reader类。它最常用的构造方法如下:

FileReader(String filePath)

FileReader(File file)

每一个都能引发一个FileNotFoundException异常。这里,filePath是一个文件的完整路径,file是描述该文件的File 对象。

 

FileWriter 创建一个可以写文件的Writer 类。它最常用的构造方法如下:

FileWriter(String filePath)

FileWriter(String filePath, boolean append)

FileWriter(File fileObj)

它们可以引发IOException或SecurityException异常。这里,filePath是文件的绝对路径,fileObj是描述该文件的File对象。如果append为true,输出是附加到文件尾的。FileWriter类的创建不依赖于文件存在与否。在创建文件之前,FileWriter将在创建对象时打开它来作为输出。如果试图打开一个只读文件,将引发一个IOException异常。

使用FileWriter时需要注意一下几点:

a)        fw.write(“aba”):将字符串写入流中,并未写入txt文件;

b)       fw.flush():将流中的数据写入文件中;

c)        fw.close():在关闭文件前会把数据写入文件;

d)       若要使fw.write(“abc”)把“abc”写入文件,必须有flush或close;

下面用FileInputReader 与 FileWriter对一个txt文件进行复制,代码示例如下:

importjava.io.*;

 

publicclass FileCopyDemo {

       public static void main(String[] args){

              FileWriter fw=null;  //创建输入流;

              FileReader fr=null;  //创建输出流;

              try {

                     fw=newFileWriter("C:/Users/FC-JAVA/Desktop/tmp/copy.txt");

                     fr=newFileReader("C:/Users/FC-JAVA/Desktop/tmp/1.txt");

                     char[] chs=newchar[1024];  //创建字符数组用于存储读取到的字符;

                     int len=0;

                     while ((len=fr.read(chs))!=-1){

                            fw.write(chs,0,len);

                     }

              } catch (IOException e) {

                     // TODO Auto-generatedcatch block

                     e.printStackTrace();

              }finally{

                     if (fw!=null){

                            try {

                                   fw.close();   //关闭输出流;

                            } catch (IOExceptione) {

                                   // TODO Auto-generatedcatch block

                                   e.printStackTrace();

                            }

                     }

                     if (fr!=null){

                            try {

                                   fr.close();   //关闭输入流;

                            } catch (IOExceptione) {

                                   // TODOAuto-generated catch block

                                   e.printStackTrace();

                            }

                     }

              }

       }

}

6.       字节流与字符流效率的提高:

为了提高字节流与字符流的效率,于是有了缓冲区的加入。因为如果没有缓冲区,应用程序每次IO都要和设备进行通信,效率很低,因此为了提高效率,当写入设备时,先写入缓冲区,等到缓冲区有足够多的数据时,就整体写入设备,这样在读写大量数据时,效率就会得到明显的提高。

BufferedReader和BufferedWriter是给字符输入输出流提高效率用的,BufferedInputStream和BufferedOutputStream是给字节输入输出流提高效率用的。当要用这四个流以提高效率时,就必须先有相应的流对象。

BufferedReader提高了一次读取一行的方法readLine(),该方法方便对文本数据的读取;readLine()方法返回值类型为String,内容不包含行终止符,所以要注意需要换行的情况,通常要配合newline()方法使用;当readLine()方法返回null时,表示读到文件的末尾。

下面的代码用于演示字符缓冲流的应用,用于复制txt文件,代码如下:

importjava.io.BufferedReader;

importjava.io.BufferedWriter;

importjava.io.FileNotFoundException;

importjava.io.FileReader;

importjava.io.FileWriter;

importjava.io.IOException;

 

publicclass BufferedCopy {

 

       public static void main(String[] args) {

              BufferedReader bufr=null;  //创建字符输入缓冲流;

              BufferedWriter buwr=null;  //创建字符输出缓冲流;

              try {

                     bufr=new BufferedReader(newFileReader("C:/Users/FC-JAVA/Desktop/tmp/1.txt"));

                     buwr=new BufferedWriter(newFileWriter("C:/Users/FC-JAVA/Desktop/tmp/copy.txt"));

                     String line=null;

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

                            buwr.write(line);

                            buwr.newLine();

                            //buwr.flush();

                     }

              } catch (FileNotFoundException e){

                     // TODO Auto-generatedcatch block

                     e.printStackTrace();

              } catch (IOException e) {

                     // TODO Auto-generatedcatch block

                     e.printStackTrace();

              }finally{

                     if (bufr!=null){

                            try {

                                   bufr.close();   //关闭字符输入流;

                            } catch (IOExceptione) {

                                   // TODOAuto-generated catch block

                                   e.printStackTrace();

                            }

                     }

                     if (buwr!=null){

                            try {

                                   buwr.close();  //关闭字符输出流;

                            } catch (IOExceptione) {

                                   // TODOAuto-generated catch block

                                   e.printStackTrace();

                            }

                     }

              }

       }

}

7.       转换流:

转换流特有功能:转换流可以将字节转成字符,原因在于,将获取到的字节通过查编码表获取到指定对应字符。转换流的最强功能就是基于 字节流 + 编码表。

若要操作大量数据,还可以用的IO流的装饰类,典型写法如下:

BufferedReaderbur = new BufferedReader(new InputStreamReader(new FileInputStream(File file )));

BufferedWriterbuw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(File file )));

另附毕向东老师总结的流操作规律:

a)        明确源和目的。

数据源:就是需要读取,可以使用两个体系:InputStream、Reader;

数据汇:就是需要写入,可以使用两个体系:OutputStream、Writer;

b)       操作的数据是否是纯文本数据?

如果是:数据源:Reader

    数据汇:Writer

如果不是:数据源:InputStream

      数据汇:OutputStream

c)        虽然确定了一个体系,但是该体系中有太多的对象,到底用哪个呢?

明确操作的数据设备。

数据源对应的设备:硬盘(File),内存(数组),键盘(System.in)

数据汇对应的设备:硬盘(File),内存(数组),控制台(System.out)。

d)       需要在基本操作上附加其他功能吗?比如缓冲。

如果需要就进行装饰。

---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------

详细请查看:<a href="http://edu.csdn.net" target="blank">http://edu.csdn.net</a>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值