我需要一个非常了解Java和内存问题的人的建议。

我有一个大文件(大约1.5GB),我需要将此文件切成许多小文件(例如100个小文件)。

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

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

使用字节API(例如FileInputStream,ByteChannel),而不要使用字符API(BufferedReader等)。 否则,您将不必要地进行编码和解码。

使用字节分割文本文件是一个坏主意。

为了节省内存,请勿在内存中不必要地存储/复制数据(即不要将其分配给循环外的变量)。只要输入输入,就立即处理输出。

是否使用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);

}

是的,仅使用适当大小的字节缓冲区数组将其从FileInputStream传递到FilOutputStream。

对我来说,数行是行不通的。关键是:我有一个文件,我需要将其分割为200个文件(此文件可能会更改,它将来自数据库)。我怎么做?仅计算行数是行不通的。能怎样 ?

然后计算写入的字节数,而不是行数。您可以事先知道文件大小(以字节为单位)。

使用lineStr.getBytes()。length?

例如。不要忘记指定正确的编码!例如。 line.getBytes(encoding)。否则会搞砸。字节长度取决于所使用的字符编码。如果您实际上不担心txt行,那么我宁愿使用InputStream / OutputStream代替,并计算传输的字节数。顺便说一下,不清楚是要说文件是存储在数据库中还是文件拆分参数是存储在数据库中。如果文件实际上也存储在数据库中,则可能是内存占用过多。确切的解决方案将取决于所使用的数据库。

您使用的"关闭"方法怎么样?

首先,如果文件包含二进制数据,则使用BufferedReader将是一个大错误(因为您会将数据转换为String,这是不必要的,并且很容易破坏数据);您应该改用BufferedInputStream。如果它是文本数据,并且需要按换行符进行分割,则可以使用BufferedReader(假设文件包含合理长度的行)。

关于内存,如果您使用大小合适的缓冲区,应该没有任何问题(我将至少使用1MB的内存来确保HD主要执行顺序读取和写入操作)。

如果发现速度是一个问题,则可以查看java.nio软件包-据说它们比java.io快,

是的,我将使用BufferedReader,因为我有一个文本文件,需要逐行读取它。现在,我还有另一个问题:写入新文件时无法检测到它的大小。这个想法是,当新文件的大小> xx MB时,将生成一个新文件。

@CC:您可以简单地继续累加要复制的行的String长度。但这取决于字符编码如何将其转换为文件大小(并且对于可变长度编码(如UTF-8)根本无法正常工作)

我建议在FileOutputStream(在底部)和OutputStreamWriter之间添加自定义FilterOutputStream。实现此过滤器只是为了跟踪通过它的字节数(apache commons io可能已经有这样的实用程序了)。

另外,常见的误解是" nio"比" io"快。在某些情况下可能是这种情况,但是通常将" nio"写为比" io"更具可伸缩性,其中"可伸缩"不一定与"更快"相同。

@james:当它上面有一个BufferedWriter时,过滤器将无法产生正确的结果,尽管差异可能并不大。

它会落后,是的,但是替代方法是尝试从chars近似字节,正如您所指出的那样,这很丑陋。无论如何,我假设存在一个软糖因素。如果计数需要非常准确,则可以在每一行之后刷新,但这当然会降低性能。

使用1MiB缓冲区的速度几乎不可能比8到16 KiB之间的速度更快。

@Software Monkey:嗯,难道要不以16 KiB块访问HD会使其严重抖动吗?操作系统或硬件缓存可能会通过预取来缓解这种情况。最后,最佳缓冲区大小可能是根据实际用例通过基准确定的。

@Michael:在我的测试中,对于大于此大小的缓冲区,批量读取/写入不再获得任何有意义的吞吐量增加。 YMMV。那时,大约在2000年代初,最佳位置大约为10K。现在可能会更大一些,但可能不会太大。它可能约为X *磁盘分配单位,其中X很小。

@MichaelBorgwardt我遇到了同样的问题,即我的信息检索项目,我必须找出最佳的缓冲区大小以及最佳的读写器,我到处都读到NIO工具比IO工具要快,但是在我的测试中,IO的工作速度更快!!

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

对于大型文件,通常速度要快得多。 YMMV是性能折衷方案,可能会使其变慢。

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

如果您只是直接阅读文件,那么很可能不会给您带来任何好处。

通常不会快很多。上次我对它进行基准测试时,我的阅读率达到了20%。

这是一篇非常好的论文:

http://java.sun.com/developer/technicalArticles/Programming/PerfTuning/

总而言之,为了获得出色的性能,您应该:

避免访问磁盘。

避免访问基础操作系统。

避免方法调用。

避免单独处理字节和字符。

例如,要减少对磁盘的访问,可以使用大缓冲区。本文介绍了各种方法。

它必须用Java完成吗?即是否需要与平台无关?如果没有,我建议在* nix中使用'split'命令。如果您确实需要,可以通过Java程序执行此命令。尽管我还没有进行测试,但我想它的执行速度要比您能想到的任何Java IO实现都要快。

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 ="

" + 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"

+"

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会更好。

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

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

请参阅我对Michael Borgwardts帖子的评论。

除非您不小心读了整个输入文件而不是逐行读取,否则您的主要限制将是磁盘速度。您可能要尝试从一个包含100行的文件开始,然后将其写入100个不同的文件,每个文件一行一行,并使触发机制在写入当前文件的行数上起作用。该程序可以轻松扩展以适应您的情况。

不要使用没有参数的read。

非常慢

最好读取它以缓冲并快速将其移动到文件中。

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

这就是全部。

java内存中读文件_关于内存管理:读取Java中的大文件相关推荐

  1. mac按文件名查找文件_如何在Mac上查找和删除大文件

    mac按文件名查找文件 Freeing up disk space on a full hard drive can be difficult, especially when it's full o ...

  2. node 生产的env文件怎么注入_前端各种文件上传攻略,从小图片到大文件断点续传...

    写在前面 今年国庆假期终于可以憋在家里了不用出门了,不用出去看后脑了,真的是一种享受.这么好的光阴怎么浪费,睡觉.吃饭.打豆豆这怎么可能(耍多了也烦),完全不符合我们程序员的作风,赶紧起来把文章写完. ...

  3. java导出jar包后,程序运行时读取图片、音乐资源文件

    java导出jar包后,程序运行时读取图片.音乐资源文件 运行时程序就可以把图片.音乐资源加载进入了 start jre/bin/java -jar 名称.jar

  4. 写给新手前端的各种文件上传攻略,从小图片到大文件断点续传

    写在前面 今年国庆假期终于可以憋在家里了不用出门了,不用出去看后脑了,真的是一种享受.这么好的光阴怎么浪费,睡觉.吃饭.打豆豆这怎么可能(耍多了也烦),完全不符合我们程序员的作风,赶紧起来把文章写完. ...

  5. 前端各种文件上传攻略,从小图片到大文件断点续传

    写在前面 今年国庆假期终于可以憋在家里了不用出门了,不用出去看后脑了,真的是一种享受.这么好的光阴怎么浪费,睡觉.吃饭.打豆豆这怎么可能(耍多了也烦),完全不符合我们程序员的作风,赶紧起来把文章写完. ...

  6. 两台电脑用蓝牙传文件出现“系统资源不足,电脑之间互相传递单个大文件,例如单个文件50g,100g

    两台电脑用蓝牙传文件出现"系统资源不足,电脑之间互相传递单个大文件,例如单个文件50g,100g 1.我的使用场景是这样的,有一个50g的文件要从一台电脑传输到另一台电脑上,想起了无线传输 ...

  7. 深入java虚拟机需要读吗_《深入理解Java虚拟机》读后总结(一)JVM内存模型

    <深入理解Java虚拟机>读后总结 基于Sun HotSpot JVM 直接上图: 从图中看到,JVM内存分为两个主要区域,一个是所有线程共享的数据区,一个是线程隔离数据区(线程私有) 线 ...

  8. java 内存泄漏样例_一次线上Java应用内存泄漏分析实例

    由于JVM的内存管理采用GC垃圾自动回收机制,这使得Java程序员在编程的时候确实可以从内存管理中释放出来,但这也引发了另外一个大问题,一旦Java应用出现内存泄漏的时候,常常让人措手不及,陷入无从下 ...

  9. java怎样读txt文件_【后端开辟】java怎样读写txt文件?

    java怎样读取txt文件? 1.运用FileInputStream完成读取txt文件内容 2.运用FileOutputStream完成写入txt文件内容 package cn.xiaobing.ut ...

最新文章

  1. 可行性nullpoj 2723 Get Luffy Out 2sat
  2. 日期时间函数(1)-time()gmtime()strftime()localtime()
  3. 【机器学习入门笔记15:BP神经网络逼近股票收盘价格2】20190218
  4. 第四范式荣获“工业和信息化系统抗击新冠肺炎疫情先进集体”称号
  5. 0x84bb0001 sqlserver_sqlserver 实现收缩数据库日志操作
  6. oschina mysql limit_如何提高MySQL Limit查询的性能
  7. Django 框架02: 模型与站点
  8. ModalPopupExtender控件主要有两种使用方式:客户端使用方式和服务器端使用方式
  9. 学了一年matlab,我到现在还不会读论文~
  10. .NET设计模式(10):装饰模式(Decorator Pattern)
  11. CSR8670 — 说说什么是ANC、CVC、DSP降噪
  12. 大话设计模式笔记(二十四)の解释器模式
  13. static this(尚学堂视频学习总结_002)
  14. hdu4415 Assassin’s Creed (贪心)
  15. 7个你不可不知的大数据定义
  16. 病毒HEUR:Trojan-Downloader.Win32.Generic
  17. oracle java.sql.SQLException: ORA-00911: 无效字符和ORA-01017: invalid username/password; logon denied
  18. vue设置页面滚动高度_vue 解决无法设置滚动位置的问题
  19. 互联网五层、七层结构
  20. 本地管理多个git账号

热门文章

  1. taobao.trade.fullinfo.get( 获取单笔交易的详细信息 )、淘宝店铺卖出订单详情接口,店铺订单明文接口,店铺订单解密接口,店铺订单消息推送接口
  2. 韩国个人数据保护类法律法规简述
  3. 提高图片的清晰度和加载速度
  4. 2022年欧盟的寒冬,中国外贸企业送温暖(暖冬外贸商品都在这里)
  5. HTML5学习之WebSocket通讯(六)
  6. python实现文字游戏_改进Python文字小游戏(4)
  7. python海龟交易策略_【手把手教你】用Python量化海龟交易法则 - 简书
  8. 面试过后等通知却没回音,到底哪里出了问题?
  9. 七牛云 转码_七牛云试用指南-音视频基本处理
  10. 让Fedora 19支持ThinkPad鼠标中键和小红点实现滚轮效果