簡體   English   中英

讀取Java中的大文件

[英]Read large files in Java

我需要一個非常了解Java和內存問題的人的建議。 我有一個大文件(大約1.5GB),我需要將此文件切成許多小文件(例如100個小文件)。

我通常知道如何做到這一點(使用BufferedReader ),但是我想知道您是否對內存有任何建議,或者提示如何更快地做到這一點。

我的文件包含文本,它不是二進制文件,每行大約有20個字符。

為了節省內存,請勿在內存中不必要地存儲/復制數據(即,不要將其分配給循環外的變量)。 只要輸入輸入,就立即處理輸出。

是否使用BufferedReader並不重要。 正如一些隱含的暗示那樣,它不會花費太多的內存。 最多只能將性能降低幾個百分點。 使用NIO時也是如此。 它只會提高可伸縮性,而不會提高內存使用率。 僅當您在同一個文件上運行數百個線程時,它才會變得有趣。

只需遍歷文件,在讀入時立即將每一行寫到其他文件,對行進行計數,如果達到100行,則切換到下一個文件,依此類推。

開球示例:

String encoding = "UTF-8";
int maxlines = 100;
BufferedReader reader = null;
BufferedWriter writer = null;

try {
    reader = new BufferedReader(new InputStreamReader(new FileInputStream("/bigfile.txt"), encoding));
    int count = 0;
    for (String line; (line = reader.readLine()) != null;) {
        if (count++ % maxlines == 0) {
            close(writer);
            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("/smallfile" + (count / maxlines) + ".txt"), encoding));
        }
        writer.write(line);
        writer.newLine();
    }
} finally {
    close(writer);
    close(reader);
}

首先,如果您的文件包含二進制數據,則使用BufferedReader將是一個大錯誤(因為您會將數據轉換為String,這是不必要的,並且很容易破壞數據); 您應該改用BufferedInputStream 如果它是文本數據,並且需要按換行符進行拆分,則可以使用BufferedReader (假定文件包含合理長度的行)。

關於內存,如果您使用大小合適的緩沖區應該沒有任何問題(我將至少使用1MB的內存來確保HD主要執行順序讀取和寫入操作)。

如果發現速度是一個問題,則可以看看java.nio軟件包-據說這些軟件包比java.io快,

您可以考慮通過FileChannel使用內存映射文件。

一般來說很多大文件的速度更快。 YMMV是性能折衷方案, 可能會使其變慢。

相關答案: Java NIO FileChannel與FileOutputstream的性能/有用性

這是一篇很好的文章: http : //java.sun.com/developer/technicalArticles/Programming/PerfTuning/

總而言之,為了獲得出色的性能,您應該:

  1. 避免訪問磁盤。
  2. 避免訪問基礎操作系統。
  3. 避免方法調用。
  4. 避免單獨處理字節和字符。

例如,要減少對磁盤的訪問,可以使用大緩沖區。 本文介紹了各種方法。

它必須用Java完成嗎? 即它需要獨立於平台嗎? 如果沒有,我建議在* nix中使用' split '命令。 如果您確實需要,可以通過Java程序執行此命令。 盡管我還沒有進行測試,但我想它的執行速度要比您能想到的任何Java IO實現都要快。

您可以使用比傳統輸入/輸出流更快的java.nio:

http://java.sun.com/javase/6/docs/technotes/guides/io/index.html

 package all.is.well; import java.io.IOException; import java.io.RandomAccessFile; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import junit.framework.TestCase; /** * @author Naresh Bhabat * Following implementation helps to deal with extra large files in java. This program is tested for dealing with 2GB input file. There are some points where extra logic can be added in future. Pleasenote: if we want to deal with binary input file, then instead of reading line,we need to read bytes from read file object. It uses random access file,which is almost like streaming API. * **************************************** Notes regarding executor framework and its readings. Please note :ExecutorService executor = Executors.newFixedThreadPool(10); * for 10 threads:Total time required for reading and writing the text in * :seconds 349.317 * * For 100:Total time required for reading the text and writing : seconds 464.042 * * For 1000 : Total time required for reading and writing text :466.538 * For 10000 Total time required for reading and writing in seconds 479.701 * * */ public class DealWithHugeRecordsinFile extends TestCase { static final String FILEPATH = "C:\\\\springbatch\\\\bigfile1.txt.txt"; static final String FILEPATH_WRITE = "C:\\\\springbatch\\\\writinghere.txt"; static volatile RandomAccessFile fileToWrite; static volatile RandomAccessFile file; static volatile String fileContentsIter; static volatile int position = 0; public static void main(String[] args) throws IOException, InterruptedException { long currentTimeMillis = System.currentTimeMillis(); try { fileToWrite = new RandomAccessFile(FILEPATH_WRITE, "rw");//for random write,independent of thread obstacles file = new RandomAccessFile(FILEPATH, "r");//for random read,independent of thread obstacles seriouslyReadProcessAndWriteAsynch(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } Thread currentThread = Thread.currentThread(); System.out.println(currentThread.getName()); long currentTimeMillis2 = System.currentTimeMillis(); double time_seconds = (currentTimeMillis2 - currentTimeMillis) / 1000.0; System.out.println("Total time required for reading the text in seconds " + time_seconds); } /** * @throws IOException * Something asynchronously serious */ public static void seriouslyReadProcessAndWriteAsynch() throws IOException { ExecutorService executor = Executors.newFixedThreadPool(10);//pls see for explanation in comments section of the class while (true) { String readLine = file.readLine(); if (readLine == null) { break; } Runnable genuineWorker = new Runnable() { @Override public void run() { // do hard processing here in this thread,i have consumed // some time and ignore some exception in write method. writeToFile(FILEPATH_WRITE, readLine); // System.out.println(" :" + // Thread.currentThread().getName()); } }; executor.execute(genuineWorker); } executor.shutdown(); while (!executor.isTerminated()) { } System.out.println("Finished all threads"); file.close(); fileToWrite.close(); } /** * @param filePath * @param data * @param position */ private static void writeToFile(String filePath, String data) { try { // fileToWrite.seek(position); data = "\\n" + data; if (!data.contains("Randomization")) { return; } System.out.println("Let us do something time consuming to make this thread busy"+(position++) + " :" + data); System.out.println("Lets consume through this loop"); int i=1000; while(i>0){ i--; } fileToWrite.write(data.getBytes()); throw new Exception(); } catch (Exception exception) { System.out.println("exception was thrown but still we are able to proceeed further" + " \\n This can be used for marking failure of the records"); //exception.printStackTrace(); } } } 

是。 我還認為,將read()與read(Char [],int init,int end)等參數一起使用是讀取此類大文件的更好方法(例如:read(buffer,0,buffer.length))

而且我還遇到了以下問題:對於二進制數據輸入流,使用BufferedReader而不是BufferedInputStreamReader會丟失值。 因此,在這種情況下,使用BufferedInputStreamReader會更好。

不要使用沒有參數的read。 非常慢 最好讀取它以緩沖並快速將其移動到文件中。

使用bufferedInputStream,因為它支持二進制讀取。

這就是全部。

除非您不小心讀了整個輸入文件而不是逐行讀取,否則您的主要限制將是磁盤速度。 您可能要嘗試從一個包含100行的文件開始,然后將其寫入100個不同的文件,每個文件一行一行,並使觸發機制在寫入當前文件的行數上起作用。 該程序可以輕松擴展以適應您的情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM