回覆列表
  • 1 # 程式設計師小助手

    結論:大文字檔案,遠超記憶體,需要格外注意。

    前言

    生產伺服器中經常產生很多檔案,有些積年累月單個檔案,體積越來越大。

    本文使用多種程式語言,實現大檔案的讀取。

    PHP的處理方式

    大檔案如果直接open,就會被整個寫入記憶體,記憶體是吃不消的。比如4G的記憶體,10G的檔案,這是處理不了的。也沒有哪個文字編輯器可以用。

    常用的file_get_contents函式,是將檔案內容讀入到字串變數內。而字串變數分配在記憶體,所以沒有任何辦法處理大檔案。

    一般的做法是使用 fgets 函式。該函式從檔案內讀取一行。函式格式如下:

    string fgets ( resource [, int ] )

    其中引數 $handle 是檔案指標,從 $handle 指向的檔案中讀取一行並返回長度最多為 $length - 1 位元組的字串。

    碰到換行符(包括在返回值中)、EOF 或者已經讀取了 $length - 1 位元組後停止(看先碰到那一種情況)。如果沒有指定 $length,則預設為 1K,或者說 1024 位元組。

    實際用起來像下面這樣。

    此函式效率極高,一次最多讀一行。而碰到整個檔案都是一行的情況,則按照設定的 $length 按照長度依次讀取。

    Python的方式

    從上述PHP的處理方法可以看到,關鍵點是按行讀取,再按長度讀取。python的處理方法一樣,只是摻雜了一些語法糖。

    python有一個“生成器”,解決大檔案的讀取,就靠這個玩意兒。

    在python的函式(function)定義中,只要出現了yield表示式(Yield expression),那麼事實上定義的是一個generator function, 呼叫這個generator function返回值是一個generator。

    為什麼genetor效率高呢,因為其與普通函式的有區別:

    function每次都是從第一行開始執行,而generator從上一次yield開始的地方執行。

    function呼叫一次返回一個(一組)值,而generator可以多次返回。

    function可以被無數次重複呼叫,而一個generator例項在yield最後一個值或者return之後就不能繼續呼叫了。

    下面是使用帶有yield關鍵字的讀取大檔案方法。

    其實python還有更優雅便捷的寫法,就是for迴圈讀取。像下面這樣:

    或者不用重新定義函式,直接用for迴圈遍歷。

    底層使用的原理是一樣的。

    Golang的方式

    Golang的想法也一樣,它絕不把整個檔案寫入記憶體。bufio庫就是讀寫檔案的利器。

    不多解釋,直接上示例。

    Golang為了統一場景,無論普遍的和特殊的,都考慮在內了。這就是bufio的厲害之處。

    對於讀寫,資料被儲存直到達到特定大小,透過這種方式觸發的寫操作更少。同時還減少了 sycall(系統呼叫)的數量,卻可以使用更高效的方式使用底層硬體。

    Linux下的工具

    如果你在Linux處理該文字,那這完全不是問題。自帶的很多工具,能夠幫你處理這個簡單的問題。比如 head,讀取某檔案的前多少行;tail,讀取某檔案的最後多少行。

    如果只是要讀檔案,那麼 less 是你最佳的選擇。

    文件內說的很清楚,less並不直接讀入整個文件,因此處理起來,比vi/vim編輯器速度快的多。

    開啟之後,就可以上下翻頁閱讀了。

    結語

    本文透過多種程式語言,實現了大檔案的讀取。

    掌握核心的方法後,使用哪種語言實現,都可以。

  • 2 # TonyDeng

    有與低階檔案流介面的語言即可,典型如C/C++。很多高階語言都有,看你用哪種了。處理方式,都是分段讀寫,不二之選,不要一下子讀入記憶體。

  • 3 # 程式碼接盤俠

    用RandomAccessfile的類方法進行讀取檔案,會比一般的方法快很多,再用bufferwriter把得到的結果寫進txt中。

  • 4 # 李老師tome

    對於大文字檔案(超過記憶體大小的檔案),通常是無法直接載入至記憶體的。所以問題就不在用何種程式語言,而在於用什麼方法了。我通常用以下方法:

    首先將大檔案進行分割,並打上標記。

    然後使用多執行緒對各個檔案進行處理。

    最後將處理的結果進行統計。

    如果你用到JAVA的話,我覺得可以使用以下兩種方法進行讀操作:

    傳統的Block IO,這個可以直接讀取單個大檔案,直接交由JAVA的BufferedReader去處理。(這種方式是執行緒阻塞的,請注意異常處理。)

    NIO方式,這種也是我上面提到的方式,拆分檔案,利用位元組流陣列,處理拆分後的檔案,再進行彙總處理。(這種方式要注意拆分的檔案不要過大。)

  • 中秋節和大豐收的關聯?
  • 紅色蒲公英的花語是什麼?