在java中读取大型CSV文件(数百万行)时出现内存不足错误
在java中读取大型CSV文件时出现内存不足错误。我该如何处理这个问题。我增加了堆的大小,也尝试了使用BufferedReader,但同样的问题仍然存在。这是我的密码在java中读取大型CSV文件(数百万行)时出现内存不足错误,java,csv,Java,Csv,在java中读取大型CSV文件时出现内存不足错误。我该如何处理这个问题。我增加了堆的大小,也尝试了使用BufferedReader,但同样的问题仍然存在。这是我的密码 public class CsvParser { public static void main(String[] args) { try { FileReader fr = new FileReader((args.length > 0) ? args[0] : "data.
public class CsvParser {
public static void main(String[] args) {
try {
FileReader fr = new FileReader((args.length > 0) ? args[0] : "data.csv");
Map<String, List<String>> values = parseCsv(fr, " ", true);
System.out.println(values);
} catch (IOException e) {
e.printStackTrace();
}
}
public static Map<String, List<String>> parseCsv(Reader reader, String separator, boolean hasHeader)
throws IOException {
Map<String, List<String>> values = new LinkedHashMap<String, List<String>>();
List<String> columnNames = new LinkedList<String>();
BufferedReader br = null;
br = new BufferedReader(reader);
String line;
int numLines = 0;
while ((line = br.readLine()) != null) {
if (StringUtils.isNotBlank(line)) {
if (!line.startsWith("#")) {
String[] tokens = line.split(separator);
if (tokens != null) {
for (int i = 0; i < tokens.length; ++i) {
if (numLines == 0) {
columnNames.add(hasHeader ? tokens[i] : ("row_" + i));
} else {
List<String> column = values.get(columnNames.get(i));
if (column == null) {
column = new LinkedList<String>();
}
column.add(tokens[i]);
values.put(columnNames.get(i), column);
}
}
}
++numLines;
}
}
}
return values;
}
}
公共类CsvParser{
公共静态void main(字符串[]args){
试一试{
FileReader fr=新的FileReader((args.length>0)?args[0]:“data.csv”);
映射值=parseCsv(fr,“,true);
System.out.println(值);
}捕获(IOE异常){
e、 printStackTrace();
}
}
公共静态映射解析CSV(读卡器、字符串分隔符、布尔hashreader)
抛出IOException{
映射值=新建LinkedHashMap();
List columnNames=新建LinkedList();
BufferedReader br=null;
br=新的BufferedReader(读卡器);
弦线;
int numLines=0;
而((line=br.readLine())!=null){
if(StringUtils.isNotBlank(行)){
如果(!line.startsWith(“#”){
String[]tokens=line.split(分隔符);
if(令牌!=null){
for(int i=0;i
如果要加载内存中的所有内容,则需要内存
通过在内存中加载完整的文件,您将始终面临OutOfMemory错误的风险
如果你真的需要所有的数据总是可以访问的,你可以开始考虑使用数据库。像sqlite这样的嵌入式数据库易于集成,开销小,并且能够管理磁盘上的数据。这样无论文件有多大,都不会出现内存问题 内存是一种有限的资源,因此如果你想处理大文件,你需要有一种处理部分内存的方法。我建议看看NIO库的RandomAccessFile和MappedByteBuffer。这是我能想到的解决你问题的最好办法。您可以访问文件的数据,而无需将其完全加载到内存中。看看link,快速开始。不是
csv文件本身填满了内存,而是values
变量包含文件本身的“副本”和某些对象开销
我还看到,您正在“转置”原始csv文件。这意味着,正如其他海报已经提到的,你必须使用一些基于文件的存储来保持最小的内存指纹,或者为你的计算机添加更多的RAM,并希望它能有所帮助,而不是将其全部加载到内存中,试着一次做一点
类似于a或a的内容应该可以帮助您管理这一点。假设:C列、L行、每个字段B个字符和64位JVM:
CSV文件中的数据大约包含C×L×B字符,因此需要(32+24+2×B)C×L×B字节的内存才能将所有值存储为字符串。如果值重复,或者将它们作为UTF-8字节数组存储在(24 +B)C×L×B字节中,可以考虑对它们进行交互。或者,如果您有信心,可以将两者结合起来,为字节数组实现一个实习池
LinkedList
每个节点需要40个字节,因此它是另一个40×C×L字节ArrayList
s更小,每个节点只占用8字节,而且在几乎所有用例中都更快,包括您的
您至少需要(96+2×B)×L×C字节的内存,外加一点开销。如果切换到ArrayList和byte数组,则需要大约(32+B)×L×C加上开销。不要尝试构建自定义解析器。您的实现可能不会足够快或灵活,无法处理所有紧急情况
您应该尝试使用CSV解析器来处理这个问题。它带有一个内置的CSV解析器。披露:我是这个图书馆的作者。它是开源和免费的(Apache V2.0许可证)
它的内存效率非常高,我们在其体系结构的基础上构建了一个自定义解析器来解析一个42GB的MySQL转储文件,其中包含超过10亿行
下面是一个如何使用uniVocity解析器CSV解析器的快速而直接的示例:
CsvParserSettings settings = new CsvParserSettings();
CsvParser parser = new CsvParser(settings);
// parses all rows in one go.
List<String[]> allRows = parser.parseAll(new FileReader(yourFile));
CsvParserSettings设置=新的CsvParserSettings();
CsvParser parser=新的CsvParser(设置);
//一次性解析所有行。
List allRows=parser.parseAll(新文件读取器(您的文件));
你忘了扔掉一些信息。如果您自己找不到原因,那么这将是一个很好的机会来学习如何在JDKDo中使用像jvisualvm这样的探查器,以便将每一行都保存在内存中?你不能一次只处理一个吗?你想对csv文件的内容做什么?我想对该文件进行分区。示例:如果我有类型属性(列),并且类型(属性)有n个不同的值,那么我需要执行n个分区。更改默认内存。定义新的JVM大小我不能访问任何类型的数据库,任何其他solution@AnoopDobhal-有时你不能做你想做的事。它是否适用于非csv文件,例如纯文本文件?csv只是纯文本,你能澄清一下吗?我不一定要解析逗号等,我只想使用换行符将文本文件中的所有行指定给列表
,以确定行的结尾