2017-04-06 31 views
0

我写了这个代码:Java的读大文件的Java堆空间

try(BufferedReader file = new BufferedReader(new FileReader("C:\\Users\\User\\Desktop\\big50m.txt"));){ 
       String line; 
       StringTokenizer st; 

       while ((line = file.readLine()) != null){ 
        st = new StringTokenizer(line); // Separation of integers of the file line 
        while(st.hasMoreTokens()) 
         numbers.add(Integer.parseInt(st.nextToken())); //Converting and adding to the list of numbers 
        } 

      } 
      catch(Exception e){ 
       System.out.println("Can't read the file..."); 

      } 

的big50m文件有50.000.000整数和我得到这个运行时错误:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 
    at java.util.Arrays.copyOf(Arrays.java:3332) 
    at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124) 
    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:596) 
    at java.lang.StringBuffer.append(StringBuffer.java:367) 
    at java.io.BufferedReader.readLine(BufferedReader.java:370) 
    at java.io.BufferedReader.readLine(BufferedReader.java:389) 
    at unsortedfilesapp.UnsortedFilesApp.main(UnsortedFilesApp.java:37) 
C:\Users\User\AppData\Local\NetBeans\Cache\8.2\executor-snippets\run.xml:53: Java returned: 1 
BUILD FAILED (total time: 5 seconds) 

我认为这个问题是字符串变量名为line。你能告诉我如何修复它 ?因为我想快速阅读我使用StringTokenizer。

+0

你看过文件结构吗? – Sedrick

+0

是的..例如:100 5 55 75 13 ....整数1整数空间整数2 ... – LeAdErQ

+0

该文件中是否有\ n's? – Sedrick

回答

1

从文件中创建BufferedReader,并通过char创建read() char。将数字字符放入String,然后Integer.parseInt(),跳过任何非数字字符并继续解析下一位数字等。

0

这里是一个最小化内存使用情况的版本。没有字节到字符转换。没有字符串操作。但在这个版本中,它不处理负数。

public static void main(final String[]a) { 
     final Set<Integer> number = new HashSet<>(); 
     int v = 0; 
     boolean use = false; 
     int c; 
     // Input stream avoid char conversion 
     try(InputStream s = new FileInputStream("C:\\Users\\User\\Desktop\\big50m.txt")) { 
      // No allocation in the loop 
      do { 
       if((c = s.read()) == -1) break; 
       if(c>='0' && c<='9') { v = v * 10 + c-'0'; use =  true; continue; } 
       if(use) number.add(v); 
       use = false; 
       v = 0; 
      } while(true); 
      if(use) number.add(v); 
     } catch(final Exception e){ System.out.println("Can't read the file..."); } 
    } 
+0

嗨SkateScout,我看到你使用Set,但我不想设置,我想要添加相同的值.. – LeAdErQ

+0

嗨,我想要一个工作示例,因为你的查询没有包含任何有关数字的信息,它可以是一个集合或一些自定义的类。但它不影响优化。 – SkateScout

+0

为什么v是final?如果它是最终它不能改变它第二次.. – LeAdErQ

0

readLine()方法一次读取整行,因此吃掉了很多内存。这是非常低效的,不能扩展到任意大文件。

您可以使用一个StreamTokenizer

这样的:

StreamTokenizer tokenizer = new StreamTokenizer(new FileReader("bigfile.txt")); 
tokenizer.parseNumbers(); // default behaviour 
while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) { 
    if (tokenizer.ttype == StreamTokenizer.TT_NUMBER) { 
     numbers.add((int)Math.round(tokenizer.nval)); 
    } 
} 

我没有测试代码,但它给你的总体思路。

+0

仍然存在的问题... Java堆空间错误 – LeAdErQ

+0

对不起,我没有意识到你正在存储在列表中的数字。除非这只是一个玩具程序,否则增加堆空间并不是真正的解决方案。内存是一个昂贵且有限的资源。在实际问题中,您必须将合理数量的数据读入内存,然后对其进行处理,直到数据耗尽。 JVM可以一次访问有限的内存,因此将所有数字读入列表不会缩放。如果这是一个真实的世界问题,您应该考虑使用缓存技术并分别处理这些数字。我估计你的方法是使用500MB以上的内存。 – whbogado

0

在有-Xmx2048m程序运行后,所提供的片段工作(有一些调整:申报数量为列表编号=新的ArrayList <>(5000);)

+0

我不知道整数的数量 – LeAdErQ

0

由于所有的数字是一个行内的BufferedReader方法不起作用或不能很好地扩展。完整的文件将被读入内存。因此,流式传输方式(例如来自@whbogado)的确是要走的路。

StreamTokenizer tokenizer = new StreamTokenizer(new FileReader("bigfile.txt")); 
tokenizer.parseNumbers(); // default behaviour 
while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) { 
    if (tokenizer.ttype == StreamTokenizer.TT_NUMBER) { 
     numbers.add((int)Math.round(tokenizer.nval)); 
    } 
} 

当你写,你得到一个堆空间错误还有,我认为,这不是用流问题了。不幸的是,你正在存储一个列表中的所有值。我认为这是现在的问题。你在评论中说,你不知道数字的实际数量。因此,您应该避免将它们存储在列表中,并在此处进行某种流式传输。

对于所有谁有兴趣,这里是我的小测试代码(java 8),产生所需大小USED_INT_VALUES的测试文件。我现在限制在500万个整数。正如你看到的那样,在读取文件的同时,内存稳步增加。拥有那么多内存的唯一地方是号码List

要知道,与初始容量初始化ArrayList分配内存存储的对象需要,你的情况你Integers

import java.io.File; 
import java.io.FileReader; 
import java.io.FileWriter; 
import java.io.IOException; 
import java.io.StreamTokenizer; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Random; 
import java.util.logging.Level; 
import java.util.logging.Logger; 

public class TestBigFiles { 

    public static void main(String args[]) throws IOException { 
     heapStatistics("program start"); 
     final int USED_INT_VALUES = 5000000; 
     File tempFile = File.createTempFile("testdata_big_50m", ".txt"); 
     System.out.println("using file " + tempFile.getAbsolutePath()); 
     tempFile.deleteOnExit(); 

     Random rand = new Random(); 
     FileWriter writer = new FileWriter(tempFile); 
     rand.ints(USED_INT_VALUES).forEach(i -> { 
      try { 
       writer.write(i + " "); 
      } catch (IOException ex) { 
       Logger.getLogger(TestBigFiles.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     }); 
     writer.close(); 
     heapStatistics("large file generated - size=" + tempFile.length() + "Bytes"); 
     List<Integer> numbers = new ArrayList<>(USED_INT_VALUES); 

     heapStatistics("large array allocated (to avoid array copy)"); 

     int c = 0; 
     try (FileReader fileReader = new FileReader(tempFile);) { 
      StreamTokenizer tokenizer = new StreamTokenizer(fileReader); 

      while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) { 
       if (tokenizer.ttype == StreamTokenizer.TT_NUMBER) { 
        numbers.add((int) tokenizer.nval); 
        c++; 
       } 
       if (c % 100000 == 0) { 
        heapStatistics("within loop count " + c); 
       } 
      } 
     } 

     heapStatistics("large file parsed nummer list size is " + numbers.size()); 
    } 

    private static void heapStatistics(String message) { 
     int MEGABYTE = 1024 * 1024; 
     //clean up unused stuff 
     System.gc(); 
     Runtime runtime = Runtime.getRuntime(); 
     System.out.println("##### " + message + " #####"); 

     System.out.println("Used Memory:" + (runtime.totalMemory() - runtime.freeMemory())/MEGABYTE + "MB" 
       + " Free Memory:" + runtime.freeMemory()/MEGABYTE + "MB" 
       + " Total Memory:" + runtime.totalMemory()/MEGABYTE + "MB" 
       + " Max Memory:" + runtime.maxMemory()/MEGABYTE + "MB"); 
    } 
} 
相关问题