用Java读取大文件

我需要知道Java的人以及内存问题的build议。 我有一个大文件(类似1.5GB),我需要剪切这个文件在很多(例如100个小文件)较小的文件。

我通常知道如何做到这一点(使用BufferedReader ),但我想知道你是否有任何关于内存的build议,或者提示如何更快地做到这一点。

我的文件包含文本,它不是二进制文件,每行大约有20个字符。

首先,如果你的文件包含二进制数据,那么使用BufferedReader将是一个很大的错误(因为你将数据转换为string,这是不必要的,可能很容易破坏数据)。 你应该使用BufferedInputStream来代替。 如果是文本数据,并且需要沿着换行符分割,那么使用BufferedReader是可以的(假定文件包含合理长度的行)。

关于内存,如果你使用了一个大小适中的缓冲区(我至less使用1MB来确保HD主要是连续读取和写入)应该没有任何问题。

如果速度变成一个问题,你可以看一下java.nio包 – 它们应该比java.io快,

为了节省内存,不要在存储器中不必要地存储/复制数据(即不要将它们分配给循环外的variables)。 只要input刚刚处理输出。

不pipe你是否使用BufferedReader都没关系。 这不会像一些暗示的那样,花费更多的记忆。 最高只会从performance中击中几个百分点。 使用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); } 

您可以考虑使用内存映射文件,通过FileChannel 。

一般来说,大文件的速度要快很多 。 有性能权衡可能会让它变慢,所以YMMV。

相关的答案: Java NIO FileChannel与FileOutputstream性能/有用性

这是一篇非常好的文章: http : //java.sun.com/developer/technicalArticles/Programming/PerfTuning/

总而言之,为了performance出色,您应该:

  1. 避免访问磁盘。
  2. 避免访问底层操作系统。
  3. 避免方法调用。
  4. 避免单独处理字节和字符。

例如,为了减less对磁盘的访问,可以使用一个大的缓冲区。 文章介绍了各种方法。

这是否必须在Java中完成? 即是否需要平台独立? 如果没有,我build议在* nix中使用' split '命令。 如果你真的想,你可以通过你的java程序执行这个命令。 虽然我还没有testing过,但是我认为它的执行速度要快于任何可以实现的Java IO实现。

您可以使用比传统input/输出stream更快的java.nio:

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

是。 我也认为使用read()和read(char [],int init,int end)是更好的方法来读取这样一个大文件(例如:read(buffer,0,buffer.length))

而且我还遇到了为二进制数据inputstream使用BufferedReader而不是BufferedInputStreamReader的缺失值的问题。 所以,在这种情况下使用BufferedInputStreamReader更好。

不要使用没有参数的读取。 这很慢。 更好地读取它缓冲并将其快速移动到文件。

使用bufferedInputStream是因为它支持二进制读取。

而这一切。

除非你不小心读入整个input文件,而不是逐行读取,那么你的主要限制将是磁盘速度。 您可能想要尝试从包含100行的文件开始,将其写入100行不同的文件中,并使触发机制在写入当前文件的行数上工作。 该计划将容易扩展到您的情况。

 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(); } } }