1. 程式人生 > >RandomAccessFile讀取文字最後一行以及倒序讀取文字

RandomAccessFile讀取文字最後一行以及倒序讀取文字

首先需要說明幾點:1.long len = rf.length();獲得的檔案長度,在seek時是從0到len-1的,如果seek了len,那麼用read方法返回-1,代表已經到了檔案末尾。所以索引是0到length-1

2.用了RandomAccessFile的read方法後,指標會往後移動一個字元,而readline後會移動到下一行的開頭,也就是再read就是下一行的開頭第一字元。

3.文字檔案,末尾是否為空行是有區別的,看圖片,前者末行是空行,後者是末行不是空行。這個並不是百度裡說的這是文字檔案的顯示效果而且說這兩個檔案是一樣的,其實這是不對的。區別在於,前者最後的字元為": 6\r\n",而後者最後的字元只是": 6".也就是說只有行與行之間才有\r\n,而第一行的開頭沒有\r\n,最後一行若不是空行那最後一行末尾也沒有\r\n。

現在做練習:

1.用RandomAccessFile正序讀取每一行文字

public class everyline {

	public static void main(String[] args) throws IOException, IOException {
		// TODO Auto-generated method stub
		 RandomAccessFile rf = new RandomAccessFile("E:\\databike.txt", "r");

		 String line=null;
		 while((line=rf.readLine())!=null)
		 {
			 //System.out.println(line);
			 System.out.println(new String(line.getBytes("ISO-8859-1"), "gbk"));
		 }
	}

}
這裡不能直接System.out.println(line)因為,用RandomAccessFile 的readline方法讀取的字串的編碼格式為ISO-8859-1,而後者則為你IDE的編碼方式,我的Eclipse的預設編碼方式是gbk,所以要設為gbk。讀每一行很簡單,直接用方法就行。

2.用RandomAccessFile倒序讀取每一行文字.這第一個版本while迴圈裡 rf.seek(nextend);不能是 rf.seek(nextend-1);

public class fromendRead {
  public static void main(String args[]) {
    RandomAccessFile rf = null;
    try {
      rf = new RandomAccessFile("E:\\databike.txt", "r");
      long len = rf.length();   //檔案長度
     
      System.out.println("檔案開始指標為"+0);
      long nextend =  len - 1;  //指標是從0到length-1
      String line;
      rf.seek(nextend); //seek到最後一個字元
      int c = -1;
      while (nextend >= 0) {
        c = rf.read();
        if (c == '\n') //只有行與行之間才有\r\n,這表示讀到每一行上一行的末尾的\n,而執行完read後,
        	            //指標指到了這一行的開頭字元
        {
          line =  new String(rf.readLine().getBytes("ISO-8859-1"), "gbk");
          //RandomAccessFile的readLine方法讀取文字為ISO-8859-1,需要轉化為windows預設編碼gbk
          System.out.println(line);
          //nextend--;
        }
        rf.seek(nextend);//這一句必須在這個位置,如果在nextend--後,那麼導致進0迴圈後去seek-1索引,報異常
                         //如果在read()以前,那麼導致進入0迴圈時,因為read指標到1,第一行少讀取一個字元
        if (nextend == 0) {// 當檔案指標退至檔案開始處,輸出第一行
          System.out.println(new String(rf.readLine().getBytes("ISO-8859-1"), "gbk"));
        }
        nextend--;
        
      }
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        if (rf != null)
          rf.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
}
還有第二個版本,就是在迴圈裡小小改動一下,效果是一樣的。之所以要改是因為第二個版本好像更符合我的思考方式。這第二個版本while迴圈裡 rf.seek(nextend);可以是是 rf.seek(nextend-1);區別在於後者的迴圈次數要少一次。
public class fromendREADnew {
  public static void main(String args[]) {
    RandomAccessFile rf = null;
    try {
      rf = new RandomAccessFile("E:\\databike.txt", "r");
      long len = rf.length();   //檔案長度
     
      System.out.println("檔案開始指標為"+0);
      long nextend =  len - 1;  //指標是從0到length-1
      String line;
      rf.seek(nextend); //seek到最後一個字元
      int c = -1;
      while (nextend >= 0) {
        c = rf.read();
        if (c == '\n') //只有行與行之間才有\r\n,這表示讀到每一行上一行的末尾的\n,而執行完read後,
        	            //指標指到了這一行的開頭字元
        {
          line =  new String(rf.readLine().getBytes("ISO-8859-1"), "gbk");
          System.out.println(line);
        }
 
        if (nextend == 0) {// 當檔案指標退至檔案開始處,輸出第一行
        	rf.seek(0);//不需要為下次做準備了,但是因為read()方法指標從0到了1,需重置為0
          System.out.println(new String(rf.readLine().getBytes("ISO-8859-1"), "gbk"));
        }
        else 
        {
        	 rf.seek(nextend-1);//為下一次迴圈做準備
        }
        	
        nextend--;
        
      }
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        if (rf != null)
          rf.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
}
但是這兩個程式都要求末行不是空行,如果是請手動刪除並儲存。思路是每一行除了首行之外,前面都是\r\n那麼使迴圈從後往前,一旦讀取到\n,便開始讀行(因為read到上一行的\n後,指標後移,剛好到下一行的開頭字元,這時再讀取行,那麼便是讀取了這一行的所有資料)。

3.讀取第一行

public class firstline {

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
         
		 RandomAccessFile rf = new RandomAccessFile("E:\\databike.txt", "r");
		 String s=rf.readLine();
		 System.out.println(s);

	}

}

4.讀取最後一行(末行為空行或不為空行)

末行不為空行時:

public class lastline {

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		 RandomAccessFile rf = new RandomAccessFile("E:\\databike.txt", "r");
         long len = rf.length();   //檔案長度
         long nextend=len-1;
       
         int c = -1;
         while (nextend > 0) 
         {
        	 rf.seek(nextend);
        	 c = rf.read();
             if (c == '\n' ) 
             {
            	 String line =  new String(rf.readLine().getBytes("ISO-8859-1"), "gbk");
                 //RandomAccessFile的readLine方法讀取文字為ISO-8859-1,需要轉化為windows預設編碼gbk
               	//line=rf.readLine();
                 System.out.println(line);
                 break;
             }
             nextend--;//是迴圈控制條件,跟指標移動沒有關係
         }
	}

}
末行為空行時:加一個flag,如果第一次遇到先置反
public class lastlineEMPTY {

	public static void main(String[] args) throws IOException {

		 RandomAccessFile rf = new RandomAccessFile("E:\\databike.txt", "r");
         long len = rf.length();   //檔案長度
         long nextend=len-1;
        
         int c = -1;
         boolean b=false;
         while (nextend > 0) 
         {
        	 rf.seek(nextend);
        	 c = rf.read();
             if (c == '\n' ) 
             {
            	 if(b==false)
            	 {
            		 b=true;
            	 }
            	 else 
            	 {
            		 String line =  new String(rf.readLine().getBytes("ISO-8859-1"), "gbk");
                     System.out.println(line);
                     break;
            	 }
             }
             nextend--;
         }
         rf.close();
	}

}

5.讀取正序第幾行。用計數器判斷。

public class frontANY {

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		 RandomAccessFile rf = new RandomAccessFile("E:\\databike.txt", "r");

		 String line=null;
		 int count=1;
		 int want=5;
		 while((line=rf.readLine())!=null)
		 {
			 if(count==want)
			 System.out.println(new String(line.getBytes("ISO-8859-1"), "gbk"));
			 count++;
		 }
		
	}

}

6.讀取倒序第幾行。只要需求不是最後一行,那麼最後一行是不是空行都無所謂,都可以有結果。但如果要的最後一行,而且最後一行是空行,那麼需要在if裡面再新增判斷條件了。
public class backANY {

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub

        //假設最後一行不是空行
		 RandomAccessFile rf = new RandomAccessFile("E:\\databike.txt", "r");
         long len = rf.length();   //檔案長度

         long nextend=len-1;
        
         int c = -1;
         int count=1;
         int want=5;
         while (nextend > 0) 
         {
        	 rf.seek(nextend);
        	 c = rf.read();
        	 if((c == '\n')&count==want)  
        	 {
        		 String line =  new String(rf.readLine().getBytes("ISO-8859-1"), "gbk");
                 System.out.println(line);
                 break;
        	 }
        	 else if(c == '\n')
        	 {
        		 count++;
        	 }

             nextend--;
         }
	}

}

用RandomAccessFile讀取檔案真的很方便,因為seek方法可以任意seek