前不久看到论坛里那个不用临时文件,将2G的文本文件逆序的帖子,我试着实践了一下,方法一是采用普通的RandomAccessFile的不停seek开头和结束,运行成功,但是处理2G文件时非常之慢
方法二是采用了nio的FileChannel的内存地址映射,运行效率明显比方法一要快,但是在最后一步把重复了两次的文件截去一半的时候总是处理不好请各位大侠为我捉刀,看看如何改善final.txt是那个2G的文本,内容类似于"?吗好你?abcde还可以"
输出的期待应该是"以可还edcba?你好吗?"
现在的输出是"以可还edcba?你好吗? ",后面多了很多空格import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;/**
*
* @author Administrator
* reverse the file character by character, without temporary file
* can deal with both single-byte character and dual-bytes character
*/
public class FileReverserFinalII {
private static int interval = 10000;
private static String sourceFile = "final.txt";
private static RandomAccessFile writer,reader;
public static void main(String[] args){
try {
MappedByteBuffer out = null;
writer = new RandomAccessFile(sourceFile,"rw");
FileChannel source = new RandomAccessFile(sourceFile,"rw").getChannel();
long length = source.size();
long currentLength = length;
writer.seek(currentLength);
boolean end = false;
// long index = 0;
long start = currentLength - interval;
long distance = interval;
do{
if(start<=0){
start = 0;
distance = currentLength;
end = true;
}
out = source.map(FileChannel.MapMode.READ_ONLY,start,distance);
byte b;
char c;
for(int i=out.capacity()-1;i>=0;){
b = out.get(i);
if(b<0){
i--;
c = out.getChar(i);
writer.writeChar(c);
}else{
writer.writeByte(b);
}
i--;
}
if(end)
break;
else{
start = start - interval;
currentLength = currentLength - interval;
}
}while(true);
start = length;
distance = interval;
writer.seek(0);
do{
if(start>=(2*length-interval)){
distance = 2*length-start;
end = true;
}
out = source.map(FileChannel.MapMode.READ_ONLY,start,distance);
byte b;
char c;
for(int i=0;i<out.capacity()-1;){
b = out.get(i);
if(b<0){
c = out.getChar(i);
writer.writeChar(c);
i+=2;
}else{
writer.writeByte(b);
i++;
}
}
if(end)
break;
else{
start = start + interval;
}
}while(true);
/**
* 最有问题的一段
* 用来将后半段文件截去
*/
currentLength = length;
writer.seek(currentLength);
while(writer.getFilePointer()<length*2){
writer.write(" ".getBytes("UTF-8"));
}
source.close();
writer.close();
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
方法二是采用了nio的FileChannel的内存地址映射,运行效率明显比方法一要快,但是在最后一步把重复了两次的文件截去一半的时候总是处理不好请各位大侠为我捉刀,看看如何改善final.txt是那个2G的文本,内容类似于"?吗好你?abcde还可以"
输出的期待应该是"以可还edcba?你好吗?"
现在的输出是"以可还edcba?你好吗? ",后面多了很多空格import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;/**
*
* @author Administrator
* reverse the file character by character, without temporary file
* can deal with both single-byte character and dual-bytes character
*/
public class FileReverserFinalII {
private static int interval = 10000;
private static String sourceFile = "final.txt";
private static RandomAccessFile writer,reader;
public static void main(String[] args){
try {
MappedByteBuffer out = null;
writer = new RandomAccessFile(sourceFile,"rw");
FileChannel source = new RandomAccessFile(sourceFile,"rw").getChannel();
long length = source.size();
long currentLength = length;
writer.seek(currentLength);
boolean end = false;
// long index = 0;
long start = currentLength - interval;
long distance = interval;
do{
if(start<=0){
start = 0;
distance = currentLength;
end = true;
}
out = source.map(FileChannel.MapMode.READ_ONLY,start,distance);
byte b;
char c;
for(int i=out.capacity()-1;i>=0;){
b = out.get(i);
if(b<0){
i--;
c = out.getChar(i);
writer.writeChar(c);
}else{
writer.writeByte(b);
}
i--;
}
if(end)
break;
else{
start = start - interval;
currentLength = currentLength - interval;
}
}while(true);
start = length;
distance = interval;
writer.seek(0);
do{
if(start>=(2*length-interval)){
distance = 2*length-start;
end = true;
}
out = source.map(FileChannel.MapMode.READ_ONLY,start,distance);
byte b;
char c;
for(int i=0;i<out.capacity()-1;){
b = out.get(i);
if(b<0){
c = out.getChar(i);
writer.writeChar(c);
i+=2;
}else{
writer.writeByte(b);
i++;
}
}
if(end)
break;
else{
start = start + interval;
}
}while(true);
/**
* 最有问题的一段
* 用来将后半段文件截去
*/
currentLength = length;
writer.seek(currentLength);
while(writer.getFilePointer()<length*2){
writer.write(" ".getBytes("UTF-8"));
}
source.close();
writer.close();
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
解决方案 »
- 急求Deitel<How To Program Java(第五版) >的范例代码
- [JMF RTP]在使用JMF进行网络RTP实时媒体播放的时候总是会出现ControllerErrorEvent
- 写了一个表格利用AbstractTableModel,如何实现动态插入行呢?
- 关于大文件的行数的取得
- [请教]关于按钮关闭窗口
- 菜鸟提问,JAVA程序运行问题
- 求救关于java中文乱码的
- 如何把一个byte[2]的数组赋值给一个short类型的变量??
- 懂者容易!请进!1
- *** 高分, 关于数据库中文在英文系统下出乱码的问题, 请高手指教, 一定给分。 ****
- 关于图片的传输
- 关于swing项目的结构问题的讨论
因为删除后的内容比原有内容小了,所以重新用FileChannel写回去后,也会出现原有文件的末端出现在新文件的尾端的情况,跟你的后面有空格类似,我在映射内存后执行truncate也出现了问题,现解决方法如下:
将映射内存后得到的buff句柄都置成null,然后强制执行一次System.gc();然后在用FileChannel写入文件内容并执行truncate就可以了