我制作了一个采用File
和String
的方法。它将文件替换为带有该字符串作为其内容的新文件。
这就是我所做的:
public static void Save(File file, String textToSave) {
file.delete();
try {
BufferedWriter out = new BufferedWriter(new FileWriter(file));
out.write(textToSave);
out.close();
} catch (IOException e) {
}
}
但是它很慢。它有时需要一分钟。
如何编写成千上万的大文件,其中可能包含多达一百万个字符?
答案 0 :(得分:19)
确保分配足够大的缓冲区:
BufferedWriter out = new BufferedWriter(new FileWriter(file), 32768);
你在运行什么样的操作系统?这也可以产生很大的不同。但是,用分钟写出一个不太大的文件听起来像是一个系统问题。在Linux或其他* ix系统上,您可以使用strace
之类的东西来查看JVM是否正在进行大量不必要的系统调用。 (很久以前,Java I / O非常愚蠢,如果你不小心,会发出疯狂的低级别write()
系统调用,但是当我说“很久以前”时,我的意思是1998年左右。)
编辑 - 请注意,Java程序以简单的方式编写一个简单文件但速度非常慢的情况本质上是奇怪的。在写入文件时,能否判断CPU是否负载过重?不应该;从这样的事情应该几乎没有CPU负载。
答案 1 :(得分:16)
为您进行简单的测试
char[] chars = new char[100*1024*1024];
Arrays.fill(chars, 'A');
String text = new String(chars);
long start = System.nanoTime();
BufferedWriter bw = new BufferedWriter(new FileWriter("/tmp/a.txt"));
bw.write(text);
bw.close();
long time = System.nanoTime() - start;
System.out.println("Wrote " + chars.length*1000L/time+" MB/s.");
打印
Wrote 135 MB/s.
答案 2 :(得分:5)
您可以了解Java的NIO功能。它可能支持您想要做的事情。
Java NIO FileChannel versus FileOutputstream performance / usefulness
答案 3 :(得分:3)
尝试使用内存映射文件:
FileChannel rwChannel = new RandomAccessFile("textfile.txt", "rw").getChannel();
ByteBuffer wrBuf = rwChannel.map(FileChannel.MapMode.READ_WRITE, 0, textToSave.length());
wrBuf.put(textToSave.getBytes());
rwChannel.close();
答案 4 :(得分:0)
您好我创建了两种创建大文件的方法,在Windows 7,64位,8 GB RAM机器上运行程序,JDK 8及以下是结果。
在这两种情况下,创建的180 MB文件包含每行中1到2千万的数字(印度系统中为2亿卢比)。
Java程序内存逐渐增长到600 MB
第一次输出
Approach = approach-1 (Using FileWriter)
Completed file writing in milli seconds = 4521 milli seconds.
第二次输出
Approach = approach-2 (Using FileChannel and ByteBuffer)
Completed file writing in milli seconds = 3590 milli seconds.
一个观察 - 我在方法#2中计算位置(pos变量),如果我将其注释掉,那么由于位置被覆盖,只有最后一个字符串可见,但时间减少到接近2000毫秒。
附加代码。
import java.io.FileWriter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.concurrent.TimeUnit;
public class TestLargeFile {
public static void main(String[] args) {
writeBigFile();
}
private static void writeBigFile() {
System.out.println("--------writeBigFile-----------");
long nanoTime = System.nanoTime();
String fn = "big-file.txt";
boolean approach1 = false;
System.out.println("Approach = " + (approach1 ? "approach-1" : "approach-2"));
int numLines = 20_000_000;
try {
if (approach1) {
//Approach 1 -- for 2 crore lines takes 4.5 seconds with 180 mb file size
approach1(fn, numLines);
} else {
//Approach 2 -- for 2 crore lines takes nearly 2 to 2.5 seconds with 180 mb file size
approach2(fn, numLines);
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Completed file writing in milli seconds = " + TimeUnit.MILLISECONDS.convert((System.nanoTime() - nanoTime), TimeUnit.NANOSECONDS));
}
private static void approach2(String fn, int numLines) throws IOException {
StringBuilder sb = new StringBuilder();
FileChannel rwChannel = new RandomAccessFile(fn, "rw").getChannel();
ByteBuffer wrBuf;
int pos = 0;
for (int i = 1; i <= numLines; i++) {
sb.append(i).append(System.lineSeparator());
if (i % 100000 == 0) {
wrBuf = rwChannel.map(FileChannel.MapMode.READ_WRITE, pos, sb.length());
pos += sb.length();
wrBuf.put(sb.toString().getBytes());
sb = new StringBuilder();
}
}
if (sb.length() > 0) {
wrBuf = rwChannel.map(FileChannel.MapMode.READ_WRITE, pos, sb.length());
wrBuf.put(sb.toString().getBytes());
}
rwChannel.close();
}
private static void approach1(String fn, int numLines) throws IOException {
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= numLines; i++) {
sb.append(i).append(System.lineSeparator());
}
FileWriter fileWriter = new FileWriter(fn);
fileWriter.write(sb.toString());
fileWriter.flush();
fileWriter.close();
}
}
答案 5 :(得分:-3)
在Java中,BufferWriter非常慢:直接使用本机方法,并尽可能少地调用它们(尽可能为每个调用提供尽可能多的数据)。
try{
FileOutputStream file=new FileOutputStream(file);
file.write(content);
file.close();
}catch(Throwable e){
D.error(e);
}//try
此外,删除文件可能需要一段时间(可能首先将其复制到回收站)。只需覆盖该文件,就像上面的代码一样。