写文件
需求:写入1亿行,7位以内的随机的数字。
首先看成果图,代表没骗大家!!!!!
这个是最终生成的文件,有770多MB 。下面用glogg打开预览:
程序打印耗时
7149ms + 923 ms = 8072ms ,也就是8秒,写入1个亿数据到文件!!!!(还可以参数调优)
思想
利用nio高效写文件,先写入20个小文件,最后合并,每个小文件开一个线程。
代码:
public static void main(String[] args) throws CloneNotSupportedException, InterruptedException, IOException {
int totals = 100000000;
int segment = 20 ;
// 写入5亿条数据
// 开启20个线程
ExecutorService service = Executors.newFixedThreadPool(segment);
AtomicInteger incr = new AtomicInteger(0);
CountDownLatch downLatch = new CountDownLatch(segment);
long s = System.currentTimeMillis();
for(int j=0;j<segment;j++) {
service.execute(()->{
RandomAccessFile acf;
FileChannel fc = null ;
try {
String fName = "E:\\tmp_" + incr.getAndIncrement()+".txt";
acf = new RandomAccessFile(fName, "rw");
fc = acf.getChannel();
int offset = 0;
for (int i = 0; i < totals/segment/10000; i++) { //25000000
//每次写1w个 数字
StringBuilder sb = new StringBuilder();
for (int k=0;k<10000;k++) {
sb.append(new Random().nextInt(10000000) + "\n");
}
byte[] bs = sb.toString().getBytes();
MappedByteBuffer mbuf = fc.map(FileChannel.MapMode.READ_WRITE, offset, bs.length);
mbuf.put(bs);
offset = offset + bs.length;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
downLatch.countDown();
try {
fc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
downLatch.await();
System.out.println("await 唤醒, 小文件写入完毕! 耗時:" + (System.currentTimeMillis()-s));
List<File> files = new ArrayList<File>();
for(int i=0;i<segment;i++) {
files.add(new File("E:\\tmp_" + i+".txt"));
}
s = System.currentTimeMillis();
//合併文件
merge(files, "E:\\last.txt");
System.out.println("合併文件完毕! 耗時:" + (System.currentTimeMillis()-s));
service.shutdown();
}
public static void merge(List<File> files , String to) {
File t = new File(to);
FileInputStream in = null;
FileChannel inChannel = null;
FileOutputStream out = null ;
FileChannel outChannel = null ;
try {
out = new FileOutputStream(t, true);
outChannel = out.getChannel();
// 记录新文件最后一个数据的位置
long start = 0;
for (File file : files) {
in = new FileInputStream(file);
inChannel = in.getChannel();
// 从inChannel中读取file.length()长度的数据,写入outChannel的start处
outChannel.transferFrom(inChannel, start, file.length());
start += file.length();
in.close();
inChannel.close();
}
}catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
outChannel.close();
} catch (Exception e2) {
}
}
}
读文件
先看效果图:
读取了100000000行,花了18341 也就是18秒。而且无论原始文件多大都不会OOM 。
思想
- 先将大原始文件拆分成小文件。
- 开多线程分批行读取。
代码: (这种方法不合适!!!后面有更高效的方法)
读取待优化点
可以换成NIO的切割文件方式,这是我读取一亿行数据耗时结果图:
切分成20个文件,耗时 :743ms 。 加上读取一起耗时: 3252 ms。 有质的提升!!!
切分后的文件截图:
NIO切割指定的是字节数, 这里要进行一定的操作(避免将一行的整数切分到两个不同的文件)。
源码在这个上面。写代码不容易,需要花3块钱 购买切分的源码,维持生计,谢谢!!!
下单了没反应或者 不会用 可以联系我QQ: 657455400