kafka.utils.Utils閱讀

devos發表於2014-05-19

這個類實現了一些工具性質的方法,正如其名。

記下自己覺得有意思的方法:

readFileAsString(path: String, charset: Charset = Charset.defaultCharset()): String

  /**
   * Attempt to read a file as a string
   */
  def readFileAsString(path: String, charset: Charset = Charset.defaultCharset()): String = {
    val stream = new FileInputStream(new File(path))
    try {
      val fc = stream.getChannel()
      val bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size())
      charset.decode(bb).toString()
    }
    finally {
      stream.close()
    }
  }

  這裡特殊之處是使用了NIO裡FileChannel的記憶體對映,對目標檔案建立記憶體對映。然後對返回的MappedByteBuffer進行解碼, 得到CharBuffer, 然後呼叫其toString方法獲得對應的字串。

  當處理比較大的檔案時,記憶體對映會帶來效能的提升。同時,將整個檔案讀進一個大的ByteBuffer,然後由這個ByteBuffer進行字元解碼,可以直接得到整個檔案對應的字串。同樣的功能也可以用FileInputReader的read方法實現。所以,主要考慮還是記憶體對映。

引用

從程式碼層面上看,從硬碟上將檔案讀入記憶體,都要經過檔案系統進行資料拷貝,並且資料拷貝操作是由檔案系統和硬體驅動實現的,理論上來說,拷貝資料的效率是一樣的。但是通過記憶體對映的方法訪問硬碟上的檔案,效率要比read和write系統呼叫高,這是為什麼呢?原因是read()是系統呼叫,其中進行了資料拷貝,它首先將檔案內容從硬碟拷貝到核心空間的一個緩衝區,如圖2中過程1,然後再將這些資料拷貝到使用者空間,如圖2中過程2,在這個過程中,實際上完成了 兩次資料拷貝 ;而mmap()也是系統呼叫,如前所述,mmap()中沒有進行資料拷貝,真正的資料拷貝是在缺頁中斷處理時進行的,由於mmap()將檔案直接對映到使用者空間,所以中斷處理函式根據這個對映關係,直接將檔案從硬碟拷貝到使用者空間,只進行了 一次資料拷貝 。因此,記憶體對映的效率要比read/write效率高。

實際上記憶體對映就是磁碟的資料會被直接寫到使用者空間(在記憶體中);而不用記憶體對映會先寫到核心緩衝,再由CPU拷貝到使用者空間,這樣就慢了。

Java 中使用記憶體對映檔案需要考慮的 10 個問題

circularIterator[T](coll: Iterable[T])

 /**
   * Create a circular (looping) iterator over a collection.
   * @param coll An iterable over the underlying collection.
   * @return A circular iterator over the collection.
   */
  def circularIterator[T](coll: Iterable[T]) = {
    val stream: Stream[T] =
      for (forever <- Stream.continually(1); t <- coll) yield t
    stream.iterator
  }

  這方法構造了一個對指定集合的無窮迭代器。利用了Scala的特殊的for迴圈和Stream的continually方法。Stream.containually(1)會構造一個全是1組成的流,由於這個流是無窮的,所以t <- coll在遍歷完集合以後,會繼續無窮次地遍歷它。通過yeild,生成了一個流。如,集合是1 to 100,那麼這個流就是 1,2,3,..., 100, 1,2,...,100,1,2,...,100,1,2,...

 

相關文章