2013-11-28 203 views
3

我正在爲我自己的程序工作,該程序顯示了在文本文件中讀取所有不同的方法。我用過FileWriter和BufferedWriter。Java - 緩衝區讀取

這裏我的問題是爲什麼FileWriter變量需要包裝在BufferedWriter中。我在代碼中看到了很多,並且在某些情況下,比如整數封裝的int。這對我來說很有意義,但是在BufferedWriter中包裝FileWriter會獲得什麼。

**FileWriter fWriter = new FileWriter(fileName); 
    BufferedWriter bW = new BufferedWriter(fWriter);** 

我發現下面的代碼在這個網站,我通過了意見和答案閱讀,並發現它有所幫助全

我認爲這部分是混亂的是,有很多的不同緩衝讀取文件。讀取文件的最佳方法是什麼,以及爲什麼它們必須包裝在其他對象中。它可以方法支持嗎?它沖洗緩衝區?它會增加速度嗎? (可能不是)將緩衝區中的文件包裝起來有什麼好處。

FileWriter fWriter = new FileWriter(fileName); 
    BufferedWriter bW = new BufferedWriter(fWriter); 

在上面的代碼中,fWriter是用文件名創建的。那麼fWriter變量被「包裝」到BufferedWriter bW變量中。將FileWriter包裝到BufferedWriter中的目的是什麼?

--------------------------------------------------------- 
    -  FileWriter fw = new FileWriter (file);   - 
    -  BufferedWriter bw = new BufferedWriter (fw); - 
    -  PrintWriter outFile = new PrintWriter (bw); - 
    --------------------------------------------------------- 

下面是我的完整文件程序。我只是對緩衝的包裝器有一個疑問,但是我認爲如果有人想編譯它並運行,那麼他們應該沒有任何問題。

import java.io.BufferedReader; 
import java.io.BufferedWriter; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.FileReader; 
import java.io.FileWriter; 
import java.io.IOException; 
import java.nio.charset.Charset; 
import java.nio.charset.StandardCharsets; 
import java.nio.file.Files; 
import java.nio.file.Path; 
import java.nio.file.Paths; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 
import java.util.Locale; 
import java.util.Scanner; 

public class DDHExampleTextFileReader { 
    List<String> lines = new ArrayList<String>(); 
    final static String FILE_NAME = "G:testFile.txt"; 
    final static String OUTPUT_FILE_NAME = "G:output.txt"; 
    final static Charset ENCODING = StandardCharsets.UTF_8; 
    private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; 

    public DDHExampleTextFileReader() { 
     //Zero argument constructor 
    } 

    private void fileReadOne() { 
     String fileName = "G:testFile.txt"; // The name of the file to open. 
     String line = null; // This will reference one line at a time 

     try { 
      // FileReader reads text files in the default encoding. 
      // FileReader is meant for reading streams of characters. 
      // For reading streams of raw bytes, consider using a FileInputStream. 
      FileReader fileReader = new FileReader(fileName); 
      // Always wrap FileReader in BufferedReader. 
      BufferedReader bufferedReader = new BufferedReader(fileReader); 

       while((line = bufferedReader.readLine()) != null) { 
        System.out.println(line); 
       } 

      bufferedReader.close();    // Always close files. 
     } 
     catch(FileNotFoundException ex) { 
      System.out.println(
       "Unable to open file '" + 
       fileName + "'");     
     } 
     catch(IOException ex) { 
      System.out.println("Error reading file '" + fileName + "'");  
      ex.printStackTrace(); 
      // Or we could just do this: 
      // ex.printStackTrace(); 
     } 
    } 

    private void fileReadTwo() { 
     // The name of the file to open. 
     String fileName = "G:testFile.txt"; 

     try { 
      // Use this for reading the data. 
      byte[] buffer = new byte[1000]; 

      FileInputStream inputStream = 
       new FileInputStream(fileName); 

      // read fills buffer with data and returns 
      // the number of bytes read (which of course 
      // may be less than the buffer size, but 
      // it will never be more). 
      int total = 0; 
      int nRead = 0; 
      while((nRead = inputStream.read(buffer)) != -1) { 
       // Convert to String so we can display it. 
       // Of course you wouldn't want to do this with 
       // a 'real' binary file. 
       System.out.println(new String(buffer)); 
       total += nRead; 
      } 

      // Always close files. 
      inputStream.close();   

      System.out.println("Read " + total + " bytes"); 
     } 
     catch(FileNotFoundException ex) { 
      System.out.println(
       "Unable to open file '" + 
       fileName + "'");     
     } 
     catch(IOException ex) { 
      System.out.println(
       "Error reading file '" 
       + fileName + "'");     
      // Or we could just do this: 
      // ex.printStackTrace(); 
     } 
    } 

    private void fileReadThree() { 
     String content = null; 
      File file = new File("G:testFile.txt"); //for ex foo.txt 
      FileReader reader = null; 
      try { 
       reader = new FileReader(file); 
       char[] chars = new char[(int) file.length()]; 
       reader.read(chars); 
       content = new String(chars); 
       System.out.println(content); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } finally { 
       try { 
       reader.close(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
      } 
    } 

    private void fileReadFour() { 
     File f = new File("G:testFile.txt"); 
      String text = ""; 
      int read, N = 1024 * 1024; 
      char[] buffer = new char[N]; 

      try { 
       FileReader fr = new FileReader(f); 
       BufferedReader br = new BufferedReader(fr); 

       while(true) { 
        read = br.read(buffer, 0, N); 
        text += new String(buffer, 0, read); 

        if(read < N) { 
         break; 
        } 
       } 
      } catch(Exception ex) { 
       ex.printStackTrace(); 
      } 
      System.out.println(text); 
     } 

    //Doesn't keep file formatting 
    private void fileReadfive() { 
      Scanner s = null; 
      try { 
       try { 
        s = new Scanner(new BufferedReader(new FileReader("G:testFile.txt"))); 
       } catch (FileNotFoundException e) { 
        e.printStackTrace(); 
       } 
        while (s.hasNext()) { 
         System.out.println(s.next()); 
        } 
      } finally { 
       if (s != null) { 
        s.close(); 
       } 
      } 
    } 

    private void fileReadSumsTheFileOfNumbersScanner() { 
     Scanner s = null; 
     double sum = 0; 

     try { 
      try { 
       s = new Scanner(new BufferedReader(new FileReader("G:n.txt"))); 
      } catch (FileNotFoundException e) { 
       e.printStackTrace(); 
      } 
      s.useLocale(Locale.US); 

      while (s.hasNext()) { 
       if (s.hasNextDouble()) { 
        sum += s.nextDouble(); 
       } else { 
        s.next(); 
       } 
      } 
     } finally { 
      s.close(); 
     } 
     System.out.println(sum); 
    } 

    private void fileWriterOneTextFile() { 
     String fileName = "G:testTemp.txt"; 
     try { 
      // Assume default encoding. 
      /* 
      Whether or not a file is available or may be created depends upon the underlying platform. Some platforms, in particular, 
      allow a file to be opened for writing by only one FileWriter (or other file-writing object) at a time. In such 
      situations the constructors in this class will fail if the file involved is already open. 
      FileWriter is meant for writing streams of characters. For writing streams of raw bytes, consider using a 
      FileOutputStream. 
      */ 
      FileWriter fWriter = new FileWriter(fileName); 
      // Always wrap FileWriter in BufferedWriter. 
      /* 
      The buffer size may be specified, or the default size may be accepted. The default is large enough for most purposes. 
      A newLine() method is provided, which uses the platform's own notion of line separator as defined by the system 
      property line.separator. Not all platforms use the newline character ('\n') to terminate lines. Calling this method 
      to terminate each output line is therefore preferred to writing a newline character directly. 
      In general, a Writer sends its output immediately to the underlying character or byte stream. Unless prompt output 
      is required, it is advisable to wrap a BufferedWriter around any Writer whose write() operations may be costly, such as 
      FileWriters and OutputStreamWriters. For example, 
       PrintWriter out 
        = new PrintWriter(new BufferedWriter(new FileWriter("foo.out"))); 
      will buffer the PrintWriter's output to the file. Without buffering, each invocation of a print() method would cause 
      characters to be converted into bytes that would then be written immediately to the file, which can be very inefficient. 
      */ 
      BufferedWriter bW = new BufferedWriter(fWriter); 
      // Note that write() does not automatically 
      // append a newline character. 
      bW.write("This is a test string that will be written to the file!!!!"); 
      bW.write("This more text that will be written to the file!!!!"); 
      bW.newLine(); 
      bW.write("After the newLine bufferedWriter method."); 
      bW.write(" A B C D E   F  G"); 
      bW.newLine(); 
      bW.write("Hauf"); 
      bW.close(); 
     } catch(IOException ex) { 
      System.out.println("Error writing to file '" + fileName + "'"); 
      ex.printStackTrace(); 
     } 
    } 

    List<String> readSmallTextFile(String aFileName) throws IOException { 
      Path path = Paths.get(aFileName); 
      return Files.readAllLines(path, ENCODING); 
      } 

      void writeSmallTextFile(List<String> aLines, String aFileName) throws IOException { 
      Path path = Paths.get(aFileName); 
      Files.write(path, aLines, ENCODING); 
      } 

      //For larger files 
      void readLargerTextFile(String aFileName) throws IOException { 
      Path path = Paths.get(aFileName); 
      try (Scanner scanner = new Scanner(path, ENCODING.name())){ 
       while (scanner.hasNextLine()){ 
       //process each line in some way 
       log(scanner.nextLine()); 
       }  
      } 
      } 

      void readLargerTextFileAlternate(String aFileName) throws IOException { 
      Path path = Paths.get(aFileName); 
      try (BufferedReader reader = Files.newBufferedReader(path, ENCODING)){ 
       String line = null; 
       while ((line = reader.readLine()) != null) { 
       //process each line in some way 
       log(line); 
       }  
      } 
      } 

      void writeLargerTextFile(String aFileName, List<String> aLines) throws IOException { 
      Path path = Paths.get(aFileName); 
      try (BufferedWriter writer = Files.newBufferedWriter(path, ENCODING)){ 
       for(String line : aLines){ 
       writer.write(line); 
       writer.newLine(); 
       } 
      } 
      } 

      private static void log(Object aMsg){ 
      System.out.println(String.valueOf(aMsg)); 
      } 

    public static void main(String[] args) throws IOException { 
     DDHExampleTextFileReader doug = new DDHExampleTextFileReader(); 
     List<String> lines = doug.readSmallTextFile(FILE_NAME); 
     //doug.fileReadOne(); 
     //doug.fileReadTwo(); 
     //doug.fileReadThree(); 
     //doug.fileReadFour(); 
     //doug.fileReadfive(); 
     //doug.fileReadSumsTheFileOfNumbersScanner(); 
     doug.fileWriterOneTextFile(); 
     log(lines); 
      lines.add("This is a line added in code."); 
      doug.writeSmallTextFile(lines, FILE_NAME); 

      doug.readLargerTextFile(FILE_NAME); 
      lines = Arrays.asList("Down to the Waterline", "Water of Love"); 
      doug.writeLargerTextFile(OUTPUT_FILE_NAME, lines); 



     System.out.println(String.valueOf("\n\n\n-----End of Main Method!!!------")); 
    } 
} 


/* 
public static void copy(Reader input, OutputStream output, String encoding) 
        throws IOException { 
       if (encoding == null) { 
        copy(input, output); 
       } else { 
        OutputStreamWriter out = new OutputStreamWriter(output, encoding); 
        copy(input, out); 
        // XXX Unless anyone is planning on rewriting OutputStreamWriter, 
        // we have to flush here. 
        out.flush(); 
       } 
    } 

    public static void copy(Reader input, OutputStream output) 
        throws IOException { 
       OutputStreamWriter out = new OutputStreamWriter(output); 
       copy(input, out); 
       // XXX Unless anyone is planning on rewriting OutputStreamWriter, we 
       // have to flush here. 
       out.flush(); 
    } 

    public static int copy(Reader input, Writer output) throws IOException { 
        // long count = copyLarge(input, output); 
        //copy large 
        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; 
        long count = 0; 
        int n = 0; 
        while (-1 != (n = input.read())) { 
         output.write(0); 
         count += n; 
        } 

        //end copy large 
        if (count > Integer.MAX_VALUE) { 
         return -1; 
        } 
        return (int) count; 
    } 

    public static long copyLarge(InputStream i, OutputStream o) throws IOException { 
      byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; 
      long count = 0; 
      int n = 0; 
      while (-1 != (n = i.read(buffer))) { 
       o.write(buffer, 0, n); 
       count += n; 
      } 
     return count; 
    } 

    public static String toString(InputStream input) throws IOException { 
        StringWriter sw = new StringWriter(); 
        copy(input, sw); 
        return sw.toString(); 
    } 

    public static void copy(InputStream input, Writer output) throws IOException { 
       InputStreamReader in = new InputStreamReader(input); 
      copy(in, output); 
    } 


    public static void copy(InputStream input, Writer output, String encoding) throws IOException { 
       if (encoding == null) { 
        copy(input, output); 
       } else { 
        InputStreamReader in = new InputStreamReader(input, encoding); 
        copy(in, output); 
       } 
    } 

回答

3

如您所知,緩衝區是用於存儲正在處理的數據的臨時內存位置。在使用BufferedWriter和BufferedReader的情況下,可以最大限度減少寫入或讀取硬盤驅動器的次數。

想想超市裏會發生什麼。你拿一輛手推車,在貨架上擺滿商品,在貨架上擺滿貨物。這個想法是一次去結賬櫃檯。假設你不用手推車而是每次購買一件商品?你需要很長時間才能買到雜貨。

當你問BufferedWriter將一些字節寫入一個文件,它實際上只是將其存儲在緩衝區中。當緩衝區已滿時,或者您將其刷新時,緩衝區中的所有內容都將通過對文件系統的單次寫入來寫入。

Java的IO框架使用Decorator design pattern。這意味着您可以在運行時構建適合您需求的作者或讀者。因此,如果您需要緩衝讀取器,請將任何讀取器放入緩衝讀取器中。如果您需要其他功能,請使用適當的包裝來簡單添加所需的功能。

輸入或輸出的核心發生與被叫的InputStream或OutputStream的類。讓我們以InputStream爲例。 InputStream只讀取字節。 read()方法讀取單個字節或讀取(byte [] b)可以讀取字節數組。對於非常低級的輸入,這是一個有用的類。但是,每次調用read()時,都必須從硬盤獲取單個字節,這可能非常緩慢。因此,在需要從文件中讀取許多字節的情況下,可以將InputStream包裝在BufferedStream中,並獲得緩衝區的好處。

使用InputStreamReader類是從字節字符橋接的InputStream的包裝。 InputStreamReader的read()方法讀取一個字符。 FileReader類是InputStreamReader的一個包裝器,它增加了從文件讀取的功能。

所以,當你經歷的java.io你看到每一個增加了一些功能的一組類,你可以包裝在功能取其層所需的各種對象。

4

我在這裏的問題是,爲何FileWriter的變量需要在BufferedWriter將包裹。

它不是 - 但是如果你這樣做,你可能會得到更好的性能,讓您避免經常會到磁盤。

此外,您正在使用BufferedWriter.newLine,它沒有爲FileWriter定義 - 只需手動編寫新行很容易。

有一兩件事,我建議是,你使用FileOutputStream包裹在一個OutputStreamWriter,而不是直接使用FileWriter - 你可以指定哪些方式編碼,你應該使用,而不是僅僅使用平臺默認的編碼。

我也建議避免PrintWriter因爲它吞下例外 - 不是一個好主意,國際海事組織。

+0

你能舉一個簡單的例子嗎? –

+1

@DougHauf:究竟是什麼? –

+0

包裝在OutputStreamWriter中的FileOutputStream?它只會讓我更好地理解它的外觀和工作方式。 –