尽管可以通过不同的方式组合I/O流泪,但可能也就只用到其中的几种组合。下面的例子可以作为典型的I/O流用法的基本参考,这些示例中异常处理简化为简单的抛出。

1、缓冲输入文件

        如果想要打开一个文件用于字符输入,可以使用以String或File对象作为文件名的FileInputReader,为了提高速度,对那个文件进行缓冲,可将产生的引用传给一个BufferedReader构造器。当readLine()返回null时,就达到了文件的末尾。
  1. import java.io.BufferedReader;  
  2. import java.io.FileReader;  
  3. import java.io.IOException;  
  4.   
  5.   
  6. public class BufferedInputFile {  
  7.   
  8.     public static String read(String filename) throws IOException {  
  9.         BufferedReader in = new BufferedReader(new FileReader(filename));  
  10.         String s;  
  11.         StringBuilder sb = new StringBuilder();  
  12.         while ((s = in.readLine()) != null) {  
  13.             sb.append(s+"\n");  
  14.         }  
  15.         in.close();  
  16.         return sb.toString();  
  17.     }  
  18.       
  19.     public static void main(String[] args) throws IOException {  
  20.         System.out.print(read("BufferedInputFile.java"));  
  21.     }  
  22. }  
        字符串sb用来累积文件的全部内容(包括必须添加的换行符,因为readLine()已将它们删除),最后调用close()关闭文件。

2、从内存输入

  1. import java.io.*;  
  2.   
  3. public class MemoryInput {  
  4.     public static void main(String[] args) throws IOException {  
  5.         StringReader in = new StringReader(read("MemoryInput.java"));  
  6.         int c;  
  7.         while ((c = in.read()) != -1)  
  8.             System.out.print((char) c);  
  9.     }  
  10.   
  11.     public static String read(String filename) throws IOException {  
  12.         BufferedReader in = new BufferedReader(new FileReader(filename));  
  13.         String s;  
  14.         StringBuilder sb = new StringBuilder();  
  15.         while ((s = in.readLine()) != null) {  
  16.             sb.append(s + "\n");  
  17.         }  
  18.         in.close();  
  19.         return sb.toString();  
  20.     }  
  21. }  
注意read()是以int形式返回一下字节,因此必须类型转换为char才能正确打印。

3、格式化的内存输入

        要读取格式化数据,可以使用DataInputStream,它是一个面向字节的I/O类,因此必须使用InputStream类而不是Reader类。当然,可以用InputStream以字节形式读取任何数据(例如一个文件),不过这里使用的是字符串。
  1. import java.io.*;  
  2.   
  3. public class FormattedMemoryInput {  
  4.     public static String read(String filename) throws IOException {  
  5.         BufferedReader in = new BufferedReader(new FileReader(filename));  
  6.         String s;  
  7.         StringBuilder sb = new StringBuilder();  
  8.         while ((s = in.readLine()) != null) {  
  9.             sb.append(s + "\n");  
  10.         }  
  11.         in.close();  
  12.         return sb.toString();  
  13.     }  
  14.     public static void main(String[] args) throws IOException{  
  15.         try {  
  16.             DataInputStream in = new DataInputStream(new ByteArrayInputStream(read("FormattedMemoryInput.java").getBytes()));  
  17.             while (true) {  
  18.                 System.out.print((char)in.readByte());  
  19.             }  
  20.         } catch (EOFException e) {  
  21.               System.err.println("End of stream");  
  22.         }  
  23.     }  
  24.   
  25. }  
        如果从DataInputStream用readByte()一次一个字节地读取字符,那么任何字节的值都是合法的结果,因此返回值不能用来检测输入是否结束。相反可以使用available()方法查看还有多少个可供存取的字符。下面的例子演示了怎样一次一个字节地读取文件:
  1. import java.io.*;  
  2.   
  3. public class FormattedMemoryInput {  
  4.     public static String read(String filename) throws IOException {  
  5.         BufferedReader in = new BufferedReader(new FileReader(filename));  
  6.         String s;  
  7.         StringBuilder sb = new StringBuilder();  
  8.         while ((s = in.readLine()) != null) {  
  9.             sb.append(s + "\n");  
  10.         }  
  11.         in.close();  
  12.         return sb.toString();  
  13.     }  
  14.     public static void main(String[] args) throws IOException{  
  15.         try {  
  16.             DataInputStream in = new DataInputStream(new ByteArrayInputStream(read("FormattedMemoryInput.java").getBytes()));  
  17.             while (in.available() != 0) {  
  18.                 System.out.print((char)in.readByte());  
  19.             }  
  20.         } catch (EOFException e) {  
  21.               System.err.println("End of stream");  
  22.         }  
  23.     }  
  24.   
  25. }  
        注意,available()的工作方式会随着所读取的媒介的类型的不同而有所不同;字面意思就是“在没有阻塞的情况下所能读取的字节数”。对应文件,这意味着整个文件,但是对于不同类型的流,可能就不是这样的,因此要谨慎使用。
        也可以通过异常捕获来检测输入的末尾。但是,使用异常进行流控制,被认为是对异常特性的错误使用。

4、基本的文件输出

        FileWriter对象可以向文件写入数据。首先,创建一个与指定文件连接的FileWriter,实际上通常会用BufferedWriter将其包装起来用以缓冲输出,本例中为了提供格式化机制,它被装饰成PrintWriter。按照这种方式创建的数据文件可作为普通文本文件读取。
  1. import java.io.*;  
  2.   
  3.   
  4. public class BasicFileOutput {  
  5.     public static String read(String filename) throws IOException {  
  6.         BufferedReader in = new BufferedReader(new FileReader(filename));  
  7.         String s;  
  8.         StringBuilder sb = new StringBuilder();  
  9.         while ((s = in.readLine()) != null) {  
  10.             sb.append(s + "\n");  
  11.         }  
  12.         in.close();  
  13.         return sb.toString();  
  14.     }  
  15.     static String file = "BasicFileOutput.out";  
  16.     public static void main(String[] args) throws IOException {  
  17.         BufferedReader in = new BufferedReader(new StringReader(read("BasicFileOutput.java")));  
  18.         PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file)));  
  19.         int lineCount = 1;  
  20.         String s;  
  21.         while ((s = in.readLine()) != null) {  
  22.             out.println(lineCount++ + ": "+s);  
  23.         }  
  24.         out.close();  
  25.         System.out.println(read(file));  
  26.     }  
  27.   
  28. }  
        Java SE5在PrintWriter中添加了一个辅助构造器,使得不必每次希望创建文本文件并向其中写入时,都去执行所有的装饰工作,如下例所示:
  1. import java.io.*;  
  2.   
  3. public class FileOutputShortcut {  
  4.     public static String read(String filename) throws IOException {  
  5.         BufferedReader in = new BufferedReader(new FileReader(filename));  
  6.         String s;  
  7.         StringBuilder sb = new StringBuilder();  
  8.         while ((s = in.readLine()) != null) {  
  9.             sb.append(s + "\n");  
  10.         }  
  11.         in.close();  
  12.         return sb.toString();  
  13.     }  
  14.   
  15.     static String file = "FileOutputShortcut.out";  
  16.   
  17.     public static void main(String[] args) throws IOException {  
  18.         BufferedReader in = new BufferedReader(new StringReader(read("FileOutputShortcut.java")));  
  19.         // Here's the shortcut:  
  20.         PrintWriter out = new PrintWriter(file);  
  21.         int lineCount = 1;  
  22.         String s;  
  23.         while ((s = in.readLine()) != null)  
  24.             out.println(lineCount++ + ": " + s);  
  25.         out.close();  
  26.         // Show the stored file:  
  27.         System.out.println(BufferedInputFile.read(file));  
  28.     }  
  29. }  

5、存储和恢复数据

        PrintWriter可以对数据进行格式化,以便人们阅读。但是为了输出可供另一个“流”恢复的数据,需要用DataOutputStream写入数据,并用DataInputStream恢复数据。注意DataOutputStream和DataInputStream是面向字节的,因此要使用InputStream和OutputStream。
  1. import java.io.*;  
  2.   
  3. public class StoringAndRecoveringData {  
  4.   
  5.     public static void main(String[] args) throws IOException {  
  6.         DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("Data.txt")));  
  7.         out.writeDouble(3.1415926);  
  8.         out.writeUTF("That was pi");  
  9.         out.writeDouble(1.41413);  
  10.         out.writeUTF("Square root of 2");  
  11.         out.close();  
  12.         DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("Data.txt")));  
  13.         System.out.println(in.readDouble());  
  14.         System.out.println(in.readUTF());  
  15.         System.out.println(in.readDouble());  
  16.         System.out.println(in.readUTF());  
  17.     }  
  18.   
  19. }  

6、读写随机访问文件

        使用RandomAccessFile,类似于组合使用了DataInputStream和DataOutputStream(因为它实现了相同接口)。利用seek()可以在文件中到处移动,并修改文件中的某个值。在使用RandomAccessFile时,必须知道文件排版,这样才能正确地操作它。RandomAccessFile拥有读取基本类型和UTF-8字符串的各种具体方法。下面是示例:
  1. import java.io.*;  
  2.   
  3. public class UsingRandomAccessFile {  
  4.     static String file = "rtest.dat";  
  5.     static void display() throws IOException{  
  6.         RandomAccessFile rf = new RandomAccessFile(file, "r");  
  7.         for (int i = 0; i < 7; i++) {  
  8.             System.out.println("Value "+ i +": "+rf.readDouble());  
  9.         }  
  10.         System.out.println(rf.readUTF());  
  11.         rf.close();  
  12.     }  
  13.     public static void main(String[] args) throws IOException {  
  14.         RandomAccessFile rf = new RandomAccessFile(file, "rw");  
  15.         for (int i = 0; i < 7; i++) {  
  16.             rf.writeDouble(i*1.414);  
  17.         }  
  18.         rf.writeUTF("The end of the file");  
  19.         rf.close();  
  20.         display();  
  21.         rf = new RandomAccessFile(file, "rw");  
  22.         rf.seek(5*8);  
  23.         rf.writeDouble(47.0001);  
  24.         rf.close();  
  25.         display();  
  26.     }  
  27.   
  28. }  
因为double是8字节长,所以为了用seek()查找第5个双精度值,只需用5*8来产生查找位置。

7、文件读写的实用工具

  1. import java.io.*;  
  2. import java.util.ArrayList;  
  3. import java.util.Arrays;  
  4. import java.util.Collections;  
  5. import java.util.HashMap;  
  6. import java.util.List;  
  7. import java.util.Map;  
  8. import java.util.TreeSet;  
  9.   
  10.   
  11. public class TextFile extends ArrayList<String> {  
  12.   
  13.     /** 
  14.      * Read a file as a single string   
  15.      * @param fileName 
  16.      * @return 
  17.      * @throws IOException  
  18.      */  
  19.     public static String read(String fileName) throws IOException {  
  20.         StringBuilder sb = new StringBuilder();  
  21.         BufferedReader in = new BufferedReader(new FileReader(new File(fileName).getAbsoluteFile()));  
  22.         try {  
  23.             String s;  
  24.             while ((s = in.readLine()) != null) {  
  25.                 sb.append(s);  
  26.                 sb.append("\n");  
  27.             }  
  28.         } finally {  
  29.             in.close();  
  30.         }  
  31.         return sb.toString();  
  32.     }  
  33.     /** 
  34.      * Write a single file  
  35.      * @param fileName 
  36.      * @param text 
  37.      * @throws IOException 
  38.      */  
  39.     public static void write(String fileName,String text) throws IOException {  
  40.         PrintWriter out = new PrintWriter(new File(fileName).getAbsoluteFile());  
  41.         try{  
  42.             out.print(text);  
  43.         } finally{  
  44.             out.close();  
  45.         }  
  46.     }  
  47.     /** 
  48.      * Read a file ,split by any regular expression 
  49.      * @param fileName 
  50.      * @param splitter 
  51.      * @throws IOException 
  52.      */  
  53.     public TextFile(String fileName,String splitter) throws IOException{  
  54.         super(Arrays.asList(read(fileName).split(splitter)));  
  55.         if (get(0).equals("")) {  
  56.             remove(0);  
  57.         }  
  58.     }  
  59.       
  60.     public TextFile(String fileName) throws IOException{  
  61.         this(fileName, "\n");  
  62.     }  
  63.       
  64.     public void write(String fileName) throws IOException {  
  65.         PrintWriter out = new PrintWriter(new File(fileName).getAbsoluteFile());  
  66.         try{  
  67.             for (String item:this) {  
  68.                 out.println(item);  
  69.             }  
  70.         } finally{  
  71.             out.close();  
  72.         }  
  73.     }  
  74.       
  75.     /** 
  76.      *  
  77.      * @param args 
  78.      * @throws IOException  
  79.      */  
  80.     public static void main(String[] args) throws IOException {  
  81.         String fileName = "TextFile.java";  
  82.         String file = read(fileName);  
  83.         write("test.txt", file);  
  84.         TextFile text = new TextFile("test.txt");  
  85.         text.write("test2.txt");  
  86.         TreeSet<String> words = new TreeSet<String>(new TextFile(fileName, "\\W+"));  
  87.         System.out.println(words.headSet("a"));  
  88.           
  89.         //下面代码可以统计文档里各个字母出现的次数  
  90.         TextFile text2 = new TextFile(fileName,"\\W+");  
  91.         Map<Character, Integer> charsStat = new HashMap<Character, Integer>();  
  92.         for (String word:text2) {  
  93.             for (int i = 0; i < word.length(); i++) {  
  94.                 Character ch = word.charAt(i);  
  95.                 Integer freq = charsStat.get(ch);  
  96.                 charsStat.put(ch, freq == null ? 1:freq+1);  
  97.             }  
  98.         }  
  99.         List<Character> keys = Arrays.asList(charsStat.keySet().toArray(new Character[0]));  
  100.         Collections.sort(keys);  
  101.         for (Character key:keys) {  
  102.             System.out.println(key +" =>"+charsStat.get(key));  
  103.         }  
  104.     }  
  105.   
  106. }  
读取二进制文件
  1. import java.io.*;  
  2.   
  3. public class BinaryFile {  
  4.   public static byte[] read(File bFile) throws IOException{  
  5.     BufferedInputStream bf = new BufferedInputStream(  
  6.       new FileInputStream(bFile));  
  7.     try {  
  8.       byte[] data = new byte[bf.available()];  
  9.       bf.read(data);  
  10.       return data;  
  11.     } finally {  
  12.       bf.close();  
  13.     }  
  14.   }  
  15.   public static byte[]  
  16.   read(String bFile) throws IOException {  
  17.     return read(new File(bFile).getAbsoluteFile());  
  18.   }  
  19. }  


 

posted on 2017-11-06 22:51  Sharpest  阅读(262)  评论(0编辑  收藏  举报