zoukankan      html  css  js  c++  java
  • Java I/O解读与使用实例

      林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka

                 摘要:本文主要讲解了Java I/O解读与使用实例。

     一、I/O基本概念    

              I/O全称是Input/Output,Java的I/O就是Java的输入与输出操作。与之相关的接口和类都放在java.io包里面,因而,在进行Java输入输出操作时,需要导入该包。利用Java的I/O大大地扩展了系统的输入与输出范畴,不仅可以从控制台输入输出,还可以从其他数据存储形式进行输入输出,例如本地文件、远程数据库等。Java的I/O在文件数据的读写、数据的网络发送与接收等很多场合发挥着重要作用。

           流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。对于文件内容的操作主要分为两大类分别是:字符流和字节流

    (1)字节流有两个抽象类:InputStream OutputStream其对应子类有FileInputStream和FileOutputStream实现文件读写。而BufferedInputStream和BufferedOutputStream提供缓冲区功能。


    (2)字符流有两个抽象类:Writer Reader其对应子类FileWriter和FileReader可实现文件的读写操作.BufferedWriter和BufferedReader能够提供缓冲区功能,用以提高效率。

    二、I/O流的分类

    根据处理数据类型的不同分为:字符流和字节流
    根据数据流向不同分为:输入流和输出流
    字符流和字节流
    字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。字节流和字符流的区别:
    (1)读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
    (2)处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
    (3)字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的;而字符流在操作的时候下后是会用到缓冲区的,是通过缓冲区来操作文件,我们将在下面验证这一点。
    结论:优先选用字节流。首先因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容。但是字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。
    输入流和输出流
    对输入流只能进行读操作,对输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的流。

    三、字节流读写操作

    3.1、按字节流读文件

    InputStream 

    此抽象类是表示字节输入流的所有类的超类。需要定义 InputStream 的子类的应用程序必须始终提供返回下一个输入字节的方法。 
    int available() 
    返回此输入流方法的下一个调用方可以不受阻塞地从此输入流读取(或跳过)的字节数。 
    void close() 
    关闭此输入流并释放与该流关联的所有系统资源。 
    void mark(int readlimit) 
    在此输入流中标记当前的位置。 
    boolean markSupported() 
    测试此输入流是否支持 mark 和 reset 方法。 
    abstract int read() 
    从输入流读取下一个数据字节。 
    int read(byte[] b) 
    从输入流中读取一定数量的字节并将其存储在缓冲区数组 b 中。 
    int read(byte[] b, int off, int len) 
    将输入流中最多 len 个数据字节读入字节数组。 
    void reset() 
    将此流重新定位到对此输入流最后调用 mark 方法时的位置。 
    long skip(long n) 
    跳过和放弃此输入流中的 n 个数据字节

    其类图如下:

    使用实例如下:

    [java] view plain copy
     
    1. package com.lin;  
    2.   
    3. import java.io.File;  
    4. import java.io.FileInputStream;  
    5. import java.io.FileNotFoundException;  
    6. import java.io.IOException;  
    7. import java.io.InputStream;  
    8.   
    9. /** 
    10.  * 功能概要:字节流读取文件 
    11.  *  
    12.  * @author linbingwen 
    13.  * @since 2015年9月5日 
    14.  */  
    15. public class Test1 {  
    16.   
    17.     /** 
    18.      * @author linbingwen 
    19.      * @since 2015年9月5日 
    20.      * @param args 
    21.      * @throws IOException 
    22.      */  
    23.     public static void main(String[] args) {  
    24.         String path = "D:" + File.separator + "test1.txt";  
    25.         readFile1(path);  
    26.         readFile2(path);  
    27.   
    28.     }  
    29.       
    30.     /** 
    31.      * 字节流读取文件:单个字符读取 
    32.      * @author linbingwen 
    33.      * @since  2015年9月5日  
    34.      * @param path 
    35.      */  
    36.     public static void readFile1(String path) {  
    37.         FileInputStream is = null;  
    38.         try {  
    39.             is = new FileInputStream(path);  
    40.             System.out.println("===============================单个字符读取begin===============================");  
    41.             int ch = 0;  
    42.             while ((ch = is.read()) != -1) {  
    43.                 System.out.print((char) ch);  
    44.             }  
    45.             System.out.println();  
    46.             System.out.println("===============================单个字符读取end===============================");        
    47.         } catch (IOException e) {  
    48.             e.printStackTrace();  
    49.         } finally {  
    50.             // 关闭输入流  
    51.             if (is != null) {  
    52.                 try {  
    53.                     is.close();  
    54.                 } catch (IOException e) {  
    55.                     e.printStackTrace();  
    56.                 }  
    57.             }  
    58.         }  
    59.     }  
    60.     /** 
    61.      * 字节流读取文件:数组循环读取 
    62.      * @author linbingwen 
    63.      * @since  2015年9月5日  
    64.      * @param path 
    65.      */  
    66.     public static void readFile2(String path) {  
    67.         FileInputStream is = null;  
    68.         try {  
    69.             // 创建文件输入流对象  
    70.             is = new FileInputStream(path);  
    71.             // 设定读取的字节数  
    72.             int n = 512;  
    73.             byte buffer[] = new byte[n];  
    74.             // 读取输入流  
    75.             System.out.println("===============================数组循环读取begin===============================");  
    76.             while ((is.read(buffer, 0, n) != -1) && (n > 0)) {  
    77.                 System.out.print(new String(buffer));  
    78.             }  
    79.             System.out.println();  
    80.             System.out.println("===============================数组循环读取end===============================");  
    81.         } catch (IOException ioe) {  
    82.             System.out.println(ioe);  
    83.         } catch (Exception e) {  
    84.             System.out.println(e);  
    85.         } finally {  
    86.             // 关闭输入流  
    87.             if (is != null) {  
    88.                 try {  
    89.                     is.close();  
    90.                 } catch (IOException e) {  
    91.                     e.printStackTrace();  
    92.                 }  
    93.             }  
    94.         }  
    95.     }  
    96.   
    97. }  


    test1.txt内容如下:

    程序运行结果:

    注意:对于中文字符,会出现乱码,中文字符要用字符流来读取

    如果把内容改成如下:

    输出结果如下:

    可以看到,中文确实变成乱码了,这就是按字节读取的坏处。

    3.2、按字节流写文件

    OutputStream 
    此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器。需要定义OutputStream 子类的应用程序必须始终提供至少一种可写入一个输出字节的方法。 
    void close() 
    关闭此输出流并释放与此流有关的所有系统资源。 
    void flush() 
    刷新此输出流并强制写出所有缓冲的输出字节。 
    void write(byte[] b) 
    将 b.length 个字节从指定的字节数组写入此输出流。 
    void write(byte[] b, int off, int len) 
    将指定字节数组中从偏移量 off 开始的 len 个字节写入此输出流。 
    abstract void write(int b) 
    将指定的字节写入此输出流。 
    进行I/O操作时可能会产生I/O例外,属于非运行时例外,应该在程序中处理。如:FileNotFoundException, EOFException, IOException等等,下面具体说明操作JAVA字节流的方法。 

    其类图如下:

    使用实例如下:

    [java] view plain copy
     
    1. package com.lin;  
    2.   
    3. import java.io.File;  
    4. import java.io.FileInputStream;  
    5. import java.io.FileOutputStream;  
    6.   
    7. /** 
    8.  * 功能概要: 
    9.  *  
    10.  * @author linbingwen 
    11.  * @since 2015年9月5日 
    12.  */  
    13. public class Test2 {  
    14.   
    15.     /** 
    16.      * @author linbingwen 
    17.      * @since 2015年9月5日 
    18.      * @param args 
    19.      */  
    20.     public static void main(String[] args) {  
    21.         String input = "D:" + File.separator + "hello.jpg";  
    22.         String output = "D:" + File.separator + "hello1.jpg";  
    23.         writeFile(input,output);  
    24.   
    25.     }  
    26.   
    27.     /** 
    28.      * 文件复制操作,可以是图片、文字 
    29.      *  
    30.      * @author linbingwen 
    31.      * @since 2015年9月5日 
    32.      * @param input 
    33.      * @param output 
    34.      */  
    35.     public static void writeFile(String input, String output) {  
    36.         FileInputStream fis = null;  
    37.         FileOutputStream fos = null;  
    38.         byte[] buffer = new byte[100];  
    39.         int temp = 0;  
    40.         try {  
    41.             fis = new FileInputStream(input);  
    42.             fos = new FileOutputStream(output);  
    43.             while (true) {  
    44.                 temp = fis.read(buffer, 0, buffer.length);  
    45.                 if (temp == -1) {  
    46.                     break;  
    47.                 }  
    48.                 fos.write(buffer, 0, temp);  
    49.             }  
    50.         } catch (Exception e) {  
    51.             System.out.println(e);  
    52.         } finally {  
    53.             try {  
    54.                 fis.close();  
    55.                 fos.close();  
    56.             } catch (Exception e2) {  
    57.                 System.out.println(e2);  
    58.             }  
    59.         }  
    60.   
    61.     }  
    62. }  

    运行结果:

    还可以进行MP3的写!

    四、字符流读写操作

    4.1、字符流读取操作

            java采用16位的Unicode来表示字符串和字符,对应的数据流就称为字符流。Reader和Writer为字符流设计。FileReader是InputStreamReader的子类,而InputStreamReader是Reader的子类;FileWriter是OutputStreamWriter的子类,而OutputStreamWriter则是Writer的子类。字符流和字节流的区别在于,字符流操作的对象是字符及字符数组,而字节流操作的对象则是字节及字节数组。
    字符输入流
    FileReader的常用构造包括以下几种。
    FileReader(String fileName):根据文件名创建FileReader对象。
    FileReader(File file):根据File对象创建FileReader对象。
    FileReader的常用方法包括以下几种。
    int read():读取单个字符。返回字符的整数值,如果已经到达文件尾,则返回-1.
    int read(char[] cbuf):将字符读入cbuf字符数组。返回读取到的字符数,如果已经到达文件尾,则返回-1.
    int read(char[] cbuf,int off,int len):将读取到的字符存放到cbuf字符数组从off标识的偏移位置开始处,最多读取len个字符。
    与字节流不同,BufferReader是Reader的直接子类,这一点和BufferInputStream是InputStream的二级子类有所不同。通过BufferReader.readLine()方法可以实现读取文本行、返回字符串,因为我们平时读取的文本文件大多是断行的,而且该方法能直接返回字符串,因此BufferReader使用得比FileReader更为广泛。
    BufferReader用有以下两种构造方法。
    BufferReader(Reader in):根据in代表的Reader对象创建BufferReader实例,缓冲区大小采用默认值。
    BufferReader(Reader in,int sz):根据in代表的Reader对象创建BufferReader实例,缓冲区大小采用指定sz值。
    BufferReader.readLine()方法遇到以下字符或者字符串认为当前行结束:‘ ’(换行符),' '(回车符),' '(回车换行)。返回值为该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回null。

    其类图如下:

    实例代码如下:

    [java] view plain copy
     
    1. package com.lin;  
    2. import java.io.BufferedReader;  
    3. import java.io.File;  
    4. import java.io.FileInputStream;  
    5. import java.io.FileNotFoundException;  
    6. import java.io.FileReader;  
    7. import java.io.IOException;  
    8. import java.io.InputStreamReader;  
    9.   
    10. /** 
    11.  * 功能概要:字符流读取操作 
    12.  *  
    13.  * @author linbingwen 
    14.  * @since 2015年9月5日 
    15.  */  
    16. public class Test3 {  
    17.   
    18.     /** 
    19.      * @author linbingwen 
    20.      * @since 2015年9月5日 
    21.      * @param args 
    22.      */  
    23.     public static void main(String[] args) {  
    24.         String path = "D:" + File.separator + "test3.txt";  
    25.         readFile1(path);  
    26.         readFile2(path);  
    27.         readFile3(path,"utf-8");  
    28.   
    29.     }  
    30.       
    31.     /** 
    32.      * 字符流读取文件方法一 
    33.      * @author linbingwen 
    34.      * @since  2015年9月5日  
    35.      * @param path 
    36.      */  
    37.     public static void readFile1(String path) {  
    38.         FileReader r = null;  
    39.         try {  
    40.             r = new FileReader(path);  
    41.             // 读入到字符数组的优化  
    42.             // 由于有时候文件太大,无法确定需要定义的数组大小  
    43.             // 因此一般定义数组长度为1024,采用循环的方式读入  
    44.             char[] buf = new char[1024];  
    45.             int temp = 0;  
    46.             System.out.println("========================== 字符流读取文件方法一==========================");  
    47.             while ((temp = r.read(buf)) != -1) {  
    48.                 System.out.print(new String(buf, 0, temp));  
    49.             }  
    50.             System.out.println();  
    51.         } catch (IOException e) {  
    52.             e.printStackTrace();  
    53.         } finally {  
    54.             if (r != null) {  
    55.                 try {  
    56.                     r.close();  
    57.                 } catch (IOException e) {  
    58.                     e.printStackTrace();  
    59.                 }  
    60.             }  
    61.         }  
    62.     }  
    63.   
    64.     /** 
    65.      * 字符流读取文件方法二 
    66.      * @author linbingwen 
    67.      * @since  2015年9月5日  
    68.      * @param path 
    69.      * @return 
    70.      */  
    71.     public static String readFile2(String path) {  
    72.         File file = new File(path);  
    73.         StringBuffer sb = new StringBuffer();  
    74.         if (file.isFile()) {  
    75.             BufferedReader bufferedReader = null;  
    76.             FileReader fileReader = null;  
    77.             try {  
    78.                 fileReader = new FileReader(file);  
    79.                 bufferedReader = new BufferedReader(fileReader);  
    80.                 String line = bufferedReader.readLine();  
    81.                 System.out.println("========================== 字符流读取文件方法二==========================");  
    82.                 while (line != null) {  
    83.                     System.out.println(line);  
    84.                     sb.append(line + " ");  
    85.                     line = bufferedReader.readLine();  
    86.                 }  
    87.             } catch (FileNotFoundException e) {  
    88.                 e.printStackTrace();  
    89.             } catch (IOException e) {  
    90.                 e.printStackTrace();  
    91.             } finally {  
    92.                 try {  
    93.                     fileReader.close();  
    94.                     bufferedReader.close();  
    95.                 } catch (IOException e) {  
    96.                     e.printStackTrace();  
    97.                 }  
    98.             }  
    99.   
    100.         }  
    101.         return sb.toString();  
    102.     }  
    103.       
    104.     /** 
    105.      * 字符流读取文件:可以指定文件编码格式 
    106.      * @author linbingwen 
    107.      * @since  2015年9月5日  
    108.      * @param path 
    109.      * @param charset 
    110.      * @return 
    111.      */  
    112.     public static String readFile3(String path,String charset) {  
    113.         File file = new File(path);  
    114.         StringBuffer sb = new StringBuffer();  
    115.         if (file.isFile()) {  
    116.             BufferedReader bufferedReader = null;  
    117.             InputStreamReader inputStreamReader = null;  
    118.             try {  
    119.                 inputStreamReader = new InputStreamReader(new FileInputStream(file), charset);  
    120.                 bufferedReader = new BufferedReader(inputStreamReader);  
    121.                 String line = bufferedReader.readLine();  
    122.                 System.out.println("========================== 字符流读取文件方法三==========================");  
    123.                 while (line != null) {  
    124.                     System.out.println(line);  
    125.                     sb.append(line + " ");  
    126.                     line = bufferedReader.readLine();  
    127.                 }  
    128.             } catch (FileNotFoundException e) {  
    129.                 e.printStackTrace();  
    130.             } catch (IOException e) {  
    131.                 e.printStackTrace();  
    132.             } finally {  
    133.                 try {  
    134.                     inputStreamReader.close();  
    135.                     bufferedReader.close();  
    136.                 } catch (IOException e) {  
    137.                     e.printStackTrace();  
    138.                 }  
    139.             }  
    140.   
    141.         }  
    142.         return sb.toString();  
    143.     }  
    144.   
    145.       
    146.   
    147. }  

    这是运行结果:

    其中,第三种方法如果指定编码后结果如下:
    [java] view plain copy
     
    1. readFile3(path,"GBK");  

    可以看到,中文变成乱码了。

    4.2、按字符写入

    字符输出流
    FileWriter的常用构造有以下几种。
    FileWriter(String fileName):根据文件名创建FileWriter对象。
    FileWriter(String fileName,boolean append):根据文件名创建FileWriter对象,append参数用来指定是否在原文件之后追加内容。
    FileWriter(File file):根据File对象创建FileWriter对象。
    FileWriter(File file,boolean append):根据File对象创建FileWriter对象,append参数用来指定是否在原文件之后追加内容。
    FileWriter的常用方法包括以下几种。
    void writer(int c):向文件中写入正整数c代表的单个字符。
    void writer(char[] cbuf):向文件中写入字符数组cbuf。
    void writer(char[] cbuf,int off, in len):向文件中写入字符数组cbuf从偏移位置off开始的len个字符。
    void writer(String str):向文件中写入字符串str,注意此方法不会在写入完毕之后自动换行。
    void writer(String str,int off,int len):向文件中写入字符串str的从位置off开始、长度为len的一部分子串。
    Writer append(char c):向文件中追加单个字符c。
    Writer append(CharSequence csq):向文件中追加csq代表的一个字符序列。CharSequence是从JDK1.4版本开始引入的一个接口,代表字符值的一个可读序列,此接口对许多不同种类的字符序列提供统一的只读访问。
    Writer append(CharSequence csq,int start,int end):向文件中追加csq字符序列的从位置start开始、end结束的一部分字符。
    void flush():刷新字符输出流缓冲区。
    void close():关闭字符输出流。
    和BufferReader相对应,启用缓冲区的BufferWriter也拥有一下两种形式的构造方法。
    BufferWriter(Writer out): 根据out代表的Writer对象创建BufferWriter实例,缓冲区大小采用默认值。
    BufferWriter(Writer out,int sz):根据out代表的Writer对象创建BufferWriter实例,缓冲区大小采用指定的sz值。
    我们知道,BufferReader类的readLine()方法能一次从输入流中读入一行,但对于BufferWriter类,却没有一次写一行的方法。若要向输出流中一次写一行,可用PrintWriter类(PrintWriter也是Writer的直接子类)将原来的流改造成新的打印流,PrintWriter类有一个方法println(String),能一次输出一行,即在待输出的字符串后自动补“ ”.
    其类图如下:
    实例代码如下:
    [java] view plain copy
     
    1. package com.lin;  
    2.   
    3. import java.io.BufferedWriter;  
    4. import java.io.File;  
    5. import java.io.FileWriter;  
    6. import java.io.IOException;  
    7.   
    8. /** 
    9.  * 功能概要: 
    10.  *  
    11.  * @author linbingwen 
    12.  * @since  2015年9月5日  
    13.  */  
    14. public class Test4 {  
    15.   
    16.     /** 
    17.      * @author linbingwen 
    18.      * @since  2015年9月5日  
    19.      * @param args     
    20.      */  
    21.     public static void main(String[] args) {  
    22.         String path = "D:" + File.separator + "test4.txt";  
    23.         String str= "Evankaka林炳文Evankaka林炳文Evankaka林炳文 ";  
    24.         writeFile(path,str);  
    25.         writeFile(path,str);  
    26.         writeFile(path,str);  
    27.     }  
    28.       
    29.     /** 
    30.      * 利用字符流写入文件 
    31.      * @author linbingwen 
    32.      * @since  2015年9月5日  
    33.      * @param path 
    34.      * @param content 
    35.      */  
    36.     public static void writeFile(String path,String content){  
    37.         //由于IO操作会抛出异常,因此在try语句块的外部定义FileWriter的引用  
    38.         FileWriter w = null;  
    39.         try {  
    40.             //以path为路径创建一个新的FileWriter对象  
    41.             //如果需要追加数据,而不是覆盖,则使用FileWriter(path,true)构造方法  
    42.             //w = new FileWriter(path,true);        
    43.             w = new FileWriter(path,true);             
    44.             //将字符串写入到流中, 表示换行  
    45.             w.write(content);  
    46.             //如果想马上看到写入效果,则需要调用w.flush()方法  
    47.             w.flush();  
    48.         } catch (IOException e) {  
    49.             e.printStackTrace();  
    50.         } finally {  
    51.             //如果前面发生异常,那么是无法产生w对象的  
    52.             //因此要做出判断,以免发生空指针异常  
    53.             if(w != null) {  
    54.                 try {  
    55.                     //关闭流资源,需要再次捕捉异常  
    56.                     w.close();  
    57.                 } catch (IOException e) {  
    58.                     e.printStackTrace();  
    59.                 }  
    60.             }  
    61.         }  
    62.     }  
    63.       
    64.   
    65.   
    66. }  

    写入的文件内容如下:
    参考文章:
    http://developer.51cto.com/art/201309/410902.htm
    http://www.ibm.com/developerworks/cn/java/j-lo-javaio/
     
    from: http://blog.csdn.net/evankaka/article/details/48225085
  • 相关阅读:
    一个高级的makefile文件
    poj3616题(动态规划),看了别人的提示,自己又写了一遍
    浅谈C++ IO标准库(1)
    https证书安装踩坑
    一个简单通知服务的开发和搭建
    WCF学习笔记
    线程(Thread)、线程池(ThreadPool)技术
    BackgroundWorker与线程使用
    使用ITextSharp生成PDF文件心得
    值类型与引用类型
  • 原文地址:https://www.cnblogs.com/GarfieldEr007/p/5746283.html
Copyright © 2011-2022 走看看