1. 程式人生 > >java解決大資料讀寫問題

java解決大資料讀寫問題

把SRTM的資料讀寫了一下,可以用。

記憶體對映檔案能讓你建立和修改那些因為太大而無法放入記憶體的檔案。有了記憶體對映檔案,你就可以認為檔案已經全部讀進了記憶體,然後把它當成一個非常大的陣列來訪問。這種解決辦法能大大簡化修改檔案的程式碼。
fileChannel.map(FileChannel.MapMode mode, long position, long size)將此通道的檔案區域直接對映到記憶體中。注意,你必須指明,它是從檔案的哪個位置開始對映的,對映的範圍又有多大;也就是說,它還可以對映一個大檔案的某個小片斷。


MappedByteBuffer是ByteBuffer的子類,因此它具備了ByteBuffer的所有方法,但新添了force()將緩衝區的內容強制重新整理到儲存裝置中去、load()將儲存裝置中的資料載入到記憶體中、isLoaded()位置記憶體中的資料是否與儲存設定上同步。這裡只簡單地演示了一下put()和get()方法,除此之外,你還可以使用asCharBuffer( )之類的方法得到相應基本型別資料的緩衝檢視後,可以方便的讀寫基本型別資料。

Java程式碼 複製程式碼 收藏程式碼
  1. import java.io.RandomAccessFile;   
  2. import java.nio.MappedByteBuffer;   
  3. import java.nio.channels.FileChannel;   
  4. publicclass LargeMappedFiles {   
  5. staticint length = 0x8000000// 128 Mb
  6. publicstaticvoid main(String[] args) throws Exception {   
  7. // 為了以可讀可寫的方式開啟檔案,這裡使用RandomAccessFile來建立檔案。
  8.         FileChannel fc = 
    new RandomAccessFile("test.dat""rw").getChannel();   
  9. //注意,檔案通道的可讀可寫要建立在檔案流本身可讀寫的基礎之上
  10.         MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_WRITE, 0, length);   
  11. //寫128M的內容
  12. for (int i = 0; i < length; i++) {   
  13.             out.put((byte'x');   
  14.         }   
  15.         System.out.println("Finished writing"
    );   
  16. //讀取檔案中間6個位元組內容
  17. for (int i = length / 2; i < length / 2 + 6; i++) {   
  18.             System.out.print((char) out.get(i));   
  19.         }   
  20.         fc.close();   
  21.     }   
  22. }  
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class LargeMappedFiles {
	static int length = 0x8000000; // 128 Mb

	public static void main(String[] args) throws Exception {
		// 為了以可讀可寫的方式開啟檔案,這裡使用RandomAccessFile來建立檔案。
		FileChannel fc = new RandomAccessFile("test.dat", "rw").getChannel();
		//注意,檔案通道的可讀可寫要建立在檔案流本身可讀寫的基礎之上
		MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_WRITE, 0, length);
		//寫128M的內容
		for (int i = 0; i < length; i++) {
			out.put((byte) 'x');
		}
		System.out.println("Finished writing");
		//讀取檔案中間6個位元組內容
		for (int i = length / 2; i < length / 2 + 6; i++) {
			System.out.print((char) out.get(i));
		}
		fc.close();
	}
}

儘管對映寫似乎要用到FileOutputStream,但是對映檔案中的所有輸出 必須使用RandomAccessFile,但如果只需要讀時可以使用FileInputStream,寫對映檔案時一定要使用隨機訪問檔案,可能寫時要讀的原因吧。

該程式建立了一個128Mb的檔案,如果一次性讀到記憶體可能導致記憶體溢位,但這裡訪問好像只是一瞬間的事,這是因為,真正調入記憶體的只是其中的一小部分,其餘部分則被放在交換檔案上。這樣你就可以很方便地修改超大型的檔案了(最大可以到2 GB)。注意,Java是呼叫作業系統的"檔案對映機制"來提升效能的。

package cn.edu.xjtu.nhpcc.jenva.file;
import   java.io.*;  
import   java.nio.*;  
import   java.nio.channels.*;

public class LargeFileReader {


   static   int   length   =   0x8FFFFFF;   //   128   Mb
  
 /**
  * @param args
  * @throws IOException
  * @throws FileNotFoundException
  */
 public static void main(String[] args) throws FileNotFoundException, IOException {
 
  /* The following works well.
     MappedByteBuffer out =  new RandomAccessFile( "test.dat",   "rw").getChannel().map(FileChannel.MapMode.READ_WRITE, 0, length);  
     for(int   i   =   0;   i   <   length;   i++)  
     out.put((byte) 'x');  
     System.out.println( "Finished   writing ");  
     for(int   i   =   length/2;   i   <   length/2   +   6;   i++)  
             System.out.print((char)out.get(i));       //read   file  
    */
  
  /* The following is ours. */
  FileChannel fc = new RandomAccessFile( "srtm1","r").getChannel();
  System.out.println(fc.size());
  long maxValue = length;
  if (maxValue>fc.size()) {
   maxValue = fc.size();
  }
  
     MappedByteBuffer out =  fc.map(FileChannel.MapMode.READ_ONLY, 0, maxValue);  
    
     FileWriter fw = new FileWriter("srtm1-2");
     int line =3601;
    
    
     for(int   i   =   0;   i   <   maxValue;   i++) {
      if (i != 0 &&i %(maxValue/line) == 0 ) {
       
       fw.append("/n");
       fw.append((char)out.get(i));
      }else {
       if (i<maxValue){
        //System.out.print((char)out.get(i));
        fw.append((char)out.get(i));
       }
      }
     }
     fw.close();
}
}

package cn.edu.xjtu.nhpcc.jenva.file;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

public class FileReaderTest {

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

  /*
  MyFileReader f = new MyFileReader();
  f.reader("hi");
  */
  
  /*
   * 下面這段程式碼,讀出來的長度連空格也算。
   */
  /*
  BufferedReader is = new BufferedReader(new FileReader("dbPoolParameter"));
  ArrayList<Float> a = new ArrayList<Float>();
  
   String s = is.readLine();
   System.out.println(s.length());
   */
  
  /*
   * 下面這段程式碼,讀出來的是純數字,空格不計入。
   */
   /*
  BufferedReader is = new BufferedReader(new FileReader("srtm1"));
  ArrayList<Float> a = new ArrayList<Float>();
  
   String s = is.readLine();
   s.trim();
   String b[] = s.split(" ");
   System.out.println(b.length);
  
   for (int i=0; i<b.length; i++) {
   System.out.println(b[i]);
   }
   //System.out.println(s);
    */
  
  
  /*
   * 下面這段程式碼,處理大檔案的讀寫。
   */
  BufferedReader is = new BufferedReader(new FileReader("srtm1-2"));
  ArrayList<Float> a = new ArrayList<Float>();
  int line = 2;
  for (int i=0; i<line; i++) {
   String s = is.readLine();
    s.trim();
    String b[] = s.split(" ");
    System.out.println(b.length);
   
    for (int j=0; j<b.length; j++) {
    System.out.println(b[j]);
    }
    System.out.println("********************************");
  }
 }

}