1. 程式人生 > >Java的檔案讀寫操作

Java的檔案讀寫操作

               

file(記憶體)----輸入流---->【程式】----輸出流---->file(記憶體)

當我們讀寫文字檔案的時候,採用Reader是非常方便的,比如FileReader,InputStreamReader和BufferedReader。其中最重要的類是InputStreamReader, 它是位元組轉換為字元的橋樑。你可以在構造器重指定編碼的方式,如果不指定的話將採用底層作業系統的預設編碼方式,例如GBK等。使用FileReader讀取檔案:

FileReader fr = new FileReader("ming.txt");  int ch = 0while((ch = fr.read())!=-1
)   {  
     System.out.print((char)ch);   
  } 

其中read()方法返回的是讀取得下個字元。當然你也可以使用read(char[] ch,int off,int length)這和處理二進位制檔案的時候類似。

事實上在FileReader中的方法都是從InputStreamReader中繼承過來的。read()方法是比較好費時間的,如果為了提高效率我們可以使用BufferedReader對Reader進行包裝,這樣可以提高讀取得速度,我們可以一行一行的讀取文字,使用readLine()方法。

BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("ming.txt")));String data = null;while((data = br.readLine())!=null){System.out.println(data); }

瞭解了FileReader操作使用FileWriter寫檔案就簡單了,這裡不贅述。

Eg.我的綜合例項

testFile:

import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStreamReader;public class testFile /**  * @param args  */ public static void
main(String[] args)
{  // TODO Auto-generated method stub  // file(記憶體)----輸入流---->【程式】----輸出流---->file(記憶體)  File file = new File("d:/temp", "addfile.txt");  try {   file.createNewFile(); // 建立檔案  } catch (IOException e) {   // TODO Auto-generated catch block   e.printStackTrace();  }  // 向檔案寫入內容(輸出流)  String str = "親愛的小南瓜!";  byte bt[] = new byte[1024];  bt = str.getBytes();  try {   FileOutputStream in = new FileOutputStream(file);   try {    in.write(bt, 0, bt.length);    in.close();    // boolean success=true;    // System.out.println("寫入檔案成功");   } catch (IOException e) {    // TODO Auto-generated catch block    e.printStackTrace();   }  } catch (FileNotFoundException e) {   // TODO Auto-generated catch block   e.printStackTrace();  }  try {   // 讀取檔案內容 (輸入流)   FileInputStream out = new FileInputStream(file);   InputStreamReader isr = new InputStreamReader(out);   int ch = 0;   while ((ch = isr.read()) != -1) {    System.out.print((char) ch);   }  } catch (Exception e) {   // TODO: handle exception  } }}

java中多種方式讀檔案

//------------------參考資料---------------------------------////1、按位元組讀取檔案內容//2、按字元讀取檔案內容//3、按行讀取檔案內容//4、隨機讀取檔案內容import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.FileReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.RandomAccessFile;import java.io.Reader;public class ReadFromFile /**  * 以位元組為單位讀取檔案,常用於讀二進位制檔案,如圖片、聲音、影像等檔案。  *   * @param fileName  *            檔案的名  */ public static void readFileByBytes(String fileName) {  File file = new File(fileName);  InputStream in = null;  try {   System.out.println("以位元組為單位讀取檔案內容,一次讀一個位元組:");   // 一次讀一個位元組   in = new FileInputStream(file);   int tempbyte;   while ((tempbyte = in.read()) != -1) {    System.out.write(tempbyte);   }   in.close();  } catch (IOException e) {   e.printStackTrace();   return;  }  try {   System.out.println("以位元組為單位讀取檔案內容,一次讀多個位元組:");   // 一次讀多個位元組   byte[] tempbytes = new byte[100];   int byteread = 0;   in = new FileInputStream(fileName);   ReadFromFile.showAvailableBytes(in);   // 讀入多個位元組到位元組陣列中,byteread為一次讀入的位元組數   while ((byteread = in.read(tempbytes)) != -1) {    System.out.write(tempbytes, 0, byteread);   }  } catch (Exception e1) {   e1.printStackTrace();  } finally {   if (in != null) {    try {     in.close();    } catch (IOException e1) {    }   }  } } /**  * 以字元為單位讀取檔案,常用於讀文字,數字等型別的檔案  *   * @param fileName  *            檔名  */ public static void readFileByChars(String fileName) {  File file = new File(fileName);  Reader reader = null;  try {   System.out.println("以字元為單位讀取檔案內容,一次讀一個位元組:");   // 一次讀一個字元   reader = new InputStreamReader(new FileInputStream(file));   int tempchar;   while ((tempchar = reader.read()) != -1) {    // 對於windows下,rn這兩個字元在一起時,表示一個換行。    // 但如果這兩個字元分開顯示時,會換兩次行。    // 因此,遮蔽掉r,或者遮蔽n。否則,將會多出很多空行。    if (((char) tempchar) != 'r') {     System.out.print((char) tempchar);    }   }   reader.close();  } catch (Exception e) {   e.printStackTrace();  }  try {   System.out.println("以字元為單位讀取檔案內容,一次讀多個位元組:");   // 一次讀多個字元   char[] tempchars = new char[30];   int charread = 0;   reader = new InputStreamReader(new FileInputStream(fileName));   // 讀入多個字元到字元陣列中,charread為一次讀取字元數   while ((charread = reader.read(tempchars)) != -1) {    // 同樣遮蔽掉r不顯示    if ((charread == tempchars.length)      && (tempchars[tempchars.length - 1] != 'r')) {     System.out.print(tempchars);    } else {     for (int i = 0; i < charread; i++) {      if (tempchars[i] == 'r') {       continue;      } else {       System.out.print(tempchars[i]);      }     }    }   }  } catch (Exception e1) {   e1.printStackTrace();  } finally {   if (reader != null) {    try {     reader.close();    } catch (IOException e1) {    }   }  } } /**  * 以行為單位讀取檔案,常用於讀面向行的格式化檔案  *   * @param fileName  *            檔名  */ public static void readFileByLines(String fileName) {  File file = new File(fileName);  BufferedReader reader = null;  try {   System.out.println("以行為單位讀取檔案內容,一次讀一整行:");   reader = new BufferedReader(new FileReader(file));   String tempString = null;   int line = 1;   // 一次讀入一行,直到讀入null為檔案結束   while ((tempString = reader.readLine()) != null) {    // 顯示行號    System.out.println("line " + line + ": " + tempString);    line++;   }   reader.close();  } catch (IOException e) {   e.printStackTrace();  } finally {   if (reader != null) {    try {     reader.close();    } catch (IOException e1) {    }   }  } } /**  * 隨機讀取檔案內容  *   * @param fileName  *            檔名  */ public static void readFileByRandomAccess(String fileName) {  RandomAccessFile randomFile = null;  try {   System.out.println("隨機讀取一段檔案內容:");   // 開啟一個隨機訪問檔案流,按只讀方式   randomFile = new RandomAccessFile(fileName, "r");   // 檔案長度,位元組數   long fileLength = randomFile.length();   // 讀檔案的起始位置   int beginIndex = (fileLength > 4) ? 4 : 0;   // 將讀檔案的開始位置移到beginIndex位置。   randomFile.seek(beginIndex);   byte[] bytes = new byte[10];   int byteread = 0;   // 一次讀10個位元組,如果檔案內容不足10個位元組,則讀剩下的位元組。   // 將一次讀取的位元組數賦給byteread   while ((byteread = randomFile.read(bytes)) != -1) {    System.out.write(bytes, 0, byteread);   }  } catch (IOException e) {   e.printStackTrace();  } finally {   if (randomFile != null) {    try {     randomFile.close();    } catch (IOException e1) {    }   }  } } /**  * 顯示輸入流中還剩的位元組數  *   * @param in  */ private static void showAvailableBytes(InputStream in) {  try {   System.out.println("當前位元組輸入流中的位元組數為:" + in.available());  } catch (IOException e) {   e.printStackTrace();  } } public static void main(String[] args) {  String fileName = "C:/temp/newTemp.txt";  ReadFromFile.readFileByBytes(fileName);  ReadFromFile.readFileByChars(fileName);  ReadFromFile.readFileByLines(fileName);  ReadFromFile.readFileByRandomAccess(fileName); }}
//二、將內容追加到檔案尾部import java.io.FileWriter;import java.io.IOException;import java.io.RandomAccessFile;/** * 將內容追加到檔案尾部 */public class AppendToFile /**  * A方法追加檔案:使用RandomAccessFile  *   * @param fileName  *            檔名  * @param content  *            追加的內容  */ public static void appendMethodA(String fileName, String content) {  try {   // 開啟一個隨機訪問檔案流,按讀寫方式   RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw");   // 檔案長度,位元組數   long fileLength = randomFile.length();   // 將寫檔案指標移到檔案尾。   randomFile.seek(fileLength);   randomFile.writeBytes(content);   randomFile.close();  } catch (IOException e) {   e.printStackTrace();  } } /**  * B方法追加檔案:使用FileWriter  *   * @param fileName  * @param content  */ public static void appendMethodB(String fileName, String content) {  try {   // 開啟一個寫檔案器,建構函式中的第二個引數true表示以追加形式寫檔案   FileWriter writer = new FileWriter(fileName, true);   writer.write(content);   writer.close();  } catch (IOException e) {   e.printStackTrace();  } } public static void main(String[] args) {  String fileName = "C:/temp/newTemp.txt";  String content = "new append!";  // 按方法A追加檔案  AppendToFile.appendMethodA(fileName, content);  AppendToFile.appendMethodA(fileName, "append end. n");  // 顯示檔案內容  ReadFromFile.readFileByLines(fileName);  // 按方法B追加檔案  AppendToFile.appendMethodB(fileName, content);  AppendToFile.appendMethodB(fileName, "append end. n");  // 顯示檔案內容  ReadFromFile.readFileByLines(fileName); }}
 

1、判斷檔案是否存在,不存在建立檔案

File file=new File(path+filename);     if(!file.exists())     {         try {             file.createNewFile();         } catch (IOException e) {             // TODO Auto-generated catch block             e.printStackTrace();         }     }  
 

2、判斷資料夾是否存在,不存在建立資料夾

    File file =new File(path+filename);     //如果資料夾不存在則建立     if  (!file .exists())       {           file .mkdir();     }   
import java.io.File;   import java.io.FileOutputStream;   import java.io.*;   public class FileTest {       public FileTest() {       }       public static void main(String[] args) {           FileOutputStream out = null;           FileOutputStream outSTr = null;           BufferedOutputStream Buff=null;           FileWriter fw = null;           int count=1000;//寫檔案行數           try {               out = new FileOutputStream(new File(“C:/add.txt”));               long begin = System.currentTimeMillis();               for (int i = 0; i < count; i++) {                   out.write(“測試java 檔案操作\r\n”.getBytes());               }               out.close();               long end = System.currentTimeMillis();               System.out.println(“FileOutputStream執行耗時:” + (end - begin) + ” 豪秒”);               outSTr = new FileOutputStream(new File(“C:/add0.txt”));                Buff=new BufferedOutputStream(outSTr);               long begin0 = System.currentTimeMillis();               for (int i = 0; i < count; i++) {                   Buff.write(“測試java 檔案操作\r\n”.getBytes());               }               Buff.flush();               Buff.close();               long end0 = System.currentTimeMillis();               System.out.println(“BufferedOutputStream執行耗時:” + (end0 - begin0) + ” 豪秒”);               fw = new FileWriter(“C:/add2.txt”);               long begin3 = System.currentTimeMillis();               for (int i = 0; i < count; i++) {                   fw.write(“測試java 檔案操作\r\n”);               }                           fw.close();               long end3 = System.currentTimeMillis();               System.out.println(“FileWriter執行耗時:” + (end3 - begin3) + ” 豪秒”);           } catch (Exception e) {               e.printStackTrace();           }           finally {               try {                   fw.close();                   Buff.close();                   outSTr.close();                   out.close();               } catch (Exception e) {                   e.printStackTrace();               }           }       }   }

String name = "AAAA.txt";String lujing = "1"+"/"+"2";//定義路徑File a = new File(lujing,name);

a.getParentFile().mkdirs();    //這裡如果不加getParentFile(),建立的資料夾為"1/2/AAAA.txt/"

那麼,a的意義就是“1/2/AAAA.txt”。這裡a是File,但是File這個類在Java裡表示的不只是檔案,雖然File在英語裡是檔案的意思。Java裡,File至少可以表示檔案或資料夾(大概還有可以表示系統裝置什麼的,這裡不考慮,只考慮檔案和資料夾)。也就是說,在“1/2/AAAA.txt”真正出現在磁碟結構裡之前,它既可以表示這個檔案,也可以表示這個路徑的資料夾。那麼,如果沒有getParentFile(),直接執行a.mkdirs(),就是說,建立“1/2/AAAA.txt”代表的資料夾,也就是“1/2/AAAA.txt/”,在此之後,執行a.createNewFile(),試圖建立a檔案,然而以a為名的資料夾已經存在了,所以createNewFile()實際是執行失敗的。你可以用System.out.println(a.createNewFile())這樣來檢查是不是真正建立檔案成功。所以,這裡,你想要建立的是“1/2/AAAA.txt”這個檔案。在建立AAAA.txt之前,必須要1/2這個目錄存在。所以,要得到1/2,就要用a.getParentFile(),然後要建立它,也就是a.getParentFile().mkdirs()。在這之後,a作為檔案所需要的資料夾大概會存在了(有特殊情況會無法建立的,這裡不考慮),就執行a.createNewFile()建立a檔案。

Java RandomAccessFile的使用

Java的RandomAccessFile提供對檔案的讀寫功能,與普通的輸入輸出流不一樣的是RamdomAccessFile可以任意的訪問檔案的任何地方。這就是“Random”的意義所在。

RandomAccessFile的物件包含一個記錄指標,用於標識當前流的讀寫位置,這個位置可以向前移動,也可以向後移動。RandomAccessFile包含兩個方法來操作檔案記錄指標。

long getFilePoint():記錄檔案指標的當前位置。

void seek(long pos):將檔案記錄指標定位到pos位置。

RandomAccessFile包含InputStream的三個read方法,也包含OutputStream的三個write方法。同時RandomAccessFile還包含一系列的readXxx和writeXxx方法完成輸入輸出。

RandomAccessFile的構造方法如下

 \

mode的值有四個

"r":以只讀文方式開啟指定檔案。如果你寫的話會有IOException。

"rw":以讀寫方式開啟指定檔案,不存在就建立新檔案。

"rws":不介紹了。

"rwd":也不介紹。

/** * 往檔案中依次寫入3名員工的資訊, * 每位員工有姓名和員工兩個欄位 然後按照 * 第二名,第一名,第三名的先後順序讀取員工資訊 */import java.io.File;import java.io.RandomAccessFile;public class RandomAccessFileTest public static void main(String[] args) throws Exception {  Employee e1 = new Employee(23, "張三");  Employee e2 = new Employee(24, "lisi");  Employee e3 = new Employee(25, "王五");  File file = new File("employee.txt");  if (!file.exists()) {   file.createNewFile();  }  // 一箇中文佔兩個位元組 一個英文字母佔一個位元組  // 整形 佔的位元組數目 跟cpu位長有關 32位的佔4個位元組  RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");  randomAccessFile.writeChars(e1.getName());  randomAccessFile.writeInt(e1.getAge());  randomAccessFile.writeChars(e2.getName());  randomAccessFile.writeInt(e2.getAge());  randomAccessFile.writeChars(e3.getName());  randomAccessFile.writeInt(e3.getAge());  randomAccessFile.close();  RandomAccessFile raf2 = new RandomAccessFile(file, "r");  raf2.skipBytes(Employee.LEN * 2 + 4);  String strName2 = "";  for (int i = 0; i < Employee.LEN; i++) {   strName2 = strName2 + raf2.readChar();  }  int age2 = raf2.readInt();  System.out.println("strName2 = " + strName2.trim());  System.out.println("age2 = " + age2);  raf2.seek(0);  String strName1 = "";  for (int i = 0; i < Employee.LEN; i++) {   strName1 = strName1 + raf2.readChar();  }  int age1 = raf2.readInt();  System.out.println("strName1 = " + strName1.trim());  System.out.println("age1 = " + age1);  raf2.skipBytes(Employee.LEN * 2 + 4);  String strName3 = "";  for (int i = 0; i < Employee.LEN; i++) {   strName3 = strName3 + raf2.readChar();  }  int age3 = raf2.readInt();  System.out.println("strName3 = " + strName3.trim());  System.out.println("age3 = " + age3); }}class Employee // 年齡 public int age; // 姓名 public String name; // 姓名的長度 public static final int LEN = 8public Employee(int age, String name) {  this.age = age;  // 對name字元長度的一個處理  if (name.length() > LEN) {   name = name.substring(0, LEN);  } else {   while (name.length() < LEN) {    name = name + "/u0000";   }  }  this.name = name; } public int getAge() {  return age; } public String getName() {  return name; }}

主體:

RandomAccessFile類。其I/O效能較之其它常用開發語言的同類效能差距甚遠,嚴重影響程式的執行效率。

開發人員迫切需要提高效率,下面分析RandomAccessFile等檔案類的原始碼,找出其中的癥結所在,並加以改進優化,建立一個"性/價比"俱佳的隨機檔案訪問類BufferedRandomAccessFile。

在改進之前先做一個基本測試:逐位元組COPY一個12兆的檔案(這裡牽涉到讀和寫)。

耗用時間(秒)
RandomAccessFileRandomAccessFile95.848
BufferedInputStream + DataInputStreamBufferedOutputStream + DataOutputStream2.935

我們可以看到兩者差距約32倍,RandomAccessFile也太慢了。先看看兩者關鍵部分的原始碼,對比分析,找出原因。

1.1.[RandomAccessFile]

Java程式碼  收藏程式碼
  1. publicclass RandomAccessFile implements DataOutput, DataInput {  
  2.     publicfinalbyte readByte() throws IOException {  
  3.         int ch = this.read();  
  4.         if (ch < 0)  
  5.             thrownew EOFException();  
  6.         return (byte)(ch);  
  7.     }  
  8.     publicnativeint read() throws IOException;   
  9.     publicfinalvoid writeByte(int v) throws IOException {  
  10.         write(v);  
  11.     }   
  12.     publicnativevoid write(int b) throws IOException;   
  13. }  

可見,RandomAccessFile每讀/寫一個位元組就需對磁碟進行一次I/O操作。

1.2.[BufferedInputStream]

Java程式碼  收藏程式碼
  1. publicclass BufferedInputStream extends FilterInputStream {  
  2.     privatestaticint defaultBufferSize = 2048;   
  3.     protectedbyte buf[]; // 建立讀快取區
  4.     public BufferedInputStream(InputStream in, int size) {  
  5.         super(in);          
  6.         if (size <= 0) {  
  7.             thrownew IllegalArgumentException("Buffer size <= 0");  
  8.         }  
  9.         buf = newbyte[size];  
  10.     }  
  11.     publicsynchronizedint read() throws IOException {  
  12.         ensureOpen();  
  13.         if (pos >= count) {  
  14.             fill();  
  15.             if (pos >= count)  
  16.                 return -1;  
  17.         }  
  18.         return buf[pos++] & 0xff// 直接從BUF[]中讀取
  19.     }   
  20.     privatevoid fill() throws IOException {  
  21.     if (markpos < 0)  
  22.         pos = 0;        /* no mark: throw away the buffer */
  23.     elseif (pos >= buf.length)  /* no room left in buffer */
  24.         if (markpos > 0) {   /* can throw away early part of the buffer */
  25.         int sz = pos - markpos;  
  26.         System.arraycopy(buf, markpos, buf, 0, sz);  
  27.         pos = sz;  
  28.         markpos = 0;  
  29.         } elseif (buf.length >= marklimit) {  
  30.         markpos = -1;   /* buffer got too big, invalidate mark */
  31.         pos = 0;    /* drop buffer contents */
  32.         } else {        /* grow buffer */
  33.         int nsz = pos * 2;  
  34.         if (nsz > marklimit)  
  35.             nsz = marklimit;  
  36.         byte nbuf[] = newbyte[nsz];  
  37.         System.arraycopy(buf, 0, nbuf, 0, pos);  
  38.         buf = nbuf;  
  39.         }  
  40.     count = pos;  
  41.     int n = in.read(buf, pos, buf.length - pos);  
  42.     if (n > 0)  
  43.         count = n + pos;  
  44.     }  
  45. }  

1.3.[BufferedOutputStream]

Java程式碼  收藏程式碼
  1. publicclass BufferedOutputStream extends FilterOutputStream {  
  2.    protectedbyte buf[]; // 建立寫快取區
  3.    public BufferedOutputStream(OutputStream out, int size) {  
  4.         super(out);  
  5.         if (size <= 0) {  
  6.             thrownew IllegalArgumentException("Buffer size <= 0");  
  7.         }  
  8.         buf = newbyte[size];  
  9.     }   
  10. publicsynchronizedvoid write(int b) throws IOException {  
  11.         if (count >= buf.length) {  
  12.             flushBuffer();  
  13.         }  
  14.         buf[count++] = (byte)b; // 直接從BUF[]中讀取
  15.    }  
  16.    privatevoid flushBuffer() throws IOException {  
  17.         if (count > 0) {  
  18.             out.write(buf, 0, count);  
  19.             count = 0;