本人要读一个2G左右的文本文件,一行一行读,边读边分析,然后入数据库。大家给点思路该怎么办啊?我的电脑配置是1G内存
用 MappedByteBuffer inputBuffer = new RandomAccessFile("d:\filename","r").getChannel().map(FileChannel.MapMode.READ_ONLY,0,filename.length())读取时出错:java.io.IOException:储存空间不足,无法处理此命令。map函数第三个参数 是什么意思啊 查API也没查到。
请大家 多多 指点
用 MappedByteBuffer inputBuffer = new RandomAccessFile("d:\filename","r").getChannel().map(FileChannel.MapMode.READ_ONLY,0,filename.length())读取时出错:java.io.IOException:储存空间不足,无法处理此命令。map函数第三个参数 是什么意思啊 查API也没查到。
请大家 多多 指点
public abstract MappedByteBuffer map(FileChannel.MapMode mode,
long position,
long size)
throws IOException将此通道的文件区域直接映射到内存中。 对于大多数操作系统而言,与通过普通的 read 和 write 方法读取或写入数千字节的数据相比,将文件映射到内存中开销更大。从性能的观点来看,通常将相对较大的文件映射到内存中才是值得的。
参数:
mode - 根据是按只读、读取/写入或专用(写入时拷贝)来映射文件,分别为 FileChannel.MapMode 类中所定义的 READ_ONLY、READ_WRITE 或 PRIVATE 之一
position - 文件中的位置,映射区域从此位置开始;必须为非负数
size - 要映射的区域大小;必须为非负数且不大于 Integer.MAX_VALUE //这个值你设置得太大了,2个G的文件你全部映射到内存中来了。
抛出:
NonReadableChannelException - 如果 mode 是 READ_ONLY,但是不允许对此通道进行读取操作
NonWritableChannelException - 如果 mode 是 READ_WRITE 或 PRIVATE,但是不允许此通道进行读取和写入操作
IllegalArgumentException - 如果关于参数的前提不成立
IOException - 如果发生其他 I/O 错误
另请参见:
FileChannel.MapMode, MappedByteBuffer
int bufSize = 1024;
byte[] bs = new byte[bufSize];
ByteBuffer byteBuf = ByteBuffer.allocate(1024);
FileChannel channel = new RandomAccessFile("d:\\filename","r").getChannel();
while(channel.read(byteBuf) != -1) {
int size = byteBuf.position();
byteBuf.rewind();
byteBuf.get(bs);
// 把文件当字符串处理,直接打印做为一个例子。
System.out.print(new String(bs, 0, size));
byteBuf.clear();
}
}
byte [] buff = new byte[1024];
int len = 0;
while ((len = in.read(buff)) != -1) {
if (len < 1024) {
bufout.write(buff, 0, len);
} else {
bufout.write(buff);
}
}
bufout.flush();
将文件分成若干次读取,设置每次读取的最大量(length),当达到时就关闭文件流,然后再重新打开文件读取.
此时从文件偏移量(seek = length * i, 其中i代表第i+1次读取文件)处开始读取,当seek > length * (i + i)时关闭文件流流汗中...
br.readLine();
这样读文件不是很爽吗?
读取大文件的策略都是一部分一部分的读进内存做处理。加大内存是绝对不可取的。现在文件2G你内存加到2G。他日文件10G那又怎么处理。
同意6楼!!
其实这样是不对的。下面的代码是把文件分几次读取的一个小例子。当然也不一定要通过管道操作完成。
public static void main(String[] args) throws Exception {
int bufSize = 1024;
byte[] bs = new byte[bufSize];
// 这里是分配缓存大小。也就是用来存放从硬盘中度出来的文件
// 什么叫一次把文件读出来?其实就是当缓存大小和在硬盘中文件大小一样,
// 只通过一个read指令把整个文件都扔到缓存里面。例如要一次读一个2G的文件,把缓存设为2G就能一次读出来。
// 不过当分配空间的时候,这个缓存根本是分配不出来的,因为内存不足。
ByteBuffer byteBuf = ByteBuffer.allocate(bufSize);
FileChannel channel = new RandomAccessFile("d:\\filename","r").getChannel();
int size;
// 因为这里缓存大小是1K,所以每个channel.read()指令最多只会读到文件的1K的内容。
// 如果文件有1M大小,这里for会循环1024次,把文件分开1024次读取出来
while((size = channel.read(byteBuf)) != -1) {
byteBuf.rewind();
byteBuf.get(bs);
// 把文件当字符串处理,直接打印做为一个例子。
System.out.print(new String(bs, 0, size));
byteBuf.clear();
}
channel.close();
}
String line = null;
while((line = br.readLine()) != null){
System.out.println(line);
}
如果你把读出来的内容,又放到一个内存空间里面,那是不行的。
例如你建一个StringBuffer类,把读出来的东西都放进去。结果一样内存不足,但是内存不足的原因不是读文件造成的。
代码是死的,人是活的。给你的只是一个例子。既然2G会死机,能不能先试试500M,700M... 再试试1G,2G,慢慢研究一下临界在哪里分析一下为什么。
或者先在循环里面放一个打印语句,看看到底循环多少次的时候不动了?
先把业务代码都去掉,看看空负载的情况循环能不能跑完?
能不能改一下缓存大小,例如把缓存改到1024 * 1024大小,看看减少IO操作又会怎么样?
回过头,我想先问一下,那个2G的文件是什么类型的文件。如果是二进制文件,那你照抄那个例子,跑着跑着死机也不奇怪。因为例子上写清楚啦,是把文件当文本文件输出。
int bufSize = 1024;
byte[] bs = new byte[bufSize];
ByteBuffer byteBuf = ByteBuffer.allocate(1024);
FileChannel channel = new RandomAccessFile("d:\\filename","r").getChannel();
while(channel.read(byteBuf) != -1) {
int size = byteBuf.position();
byteBuf.rewind();
byteBuf.get(bs);
// 把文件当字符串处理,直接打印做为一个例子。
System.out.print(new String(bs, 0, size));
byteBuf.clear();
}
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.*;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.DESKeySpec;
import java.io.*;
import javax.crypto.SecretKeyFactory;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;/**
* 加密解密
*
* @author shy.qiu
* @since http://blog.csdn.net/qiushyfm
*/
public class Test12 {
/**
* 测试
*
* @param args
*/
private void initbytes(byte[] bs){
for(int i=0;i<bs.length;i++){
bs[i]=0;
}
} public void readTxt(){
try{
int bufSize = 1024;
byte[] bs = new byte[bufSize];
byte[] tmpbs = new byte[2*bufSize];
byte[] lessbs = new byte[bufSize]; // 这里是分配缓存大小。也就是用来存放从硬盘中度出来的文件
// 什么叫一次把文件读出来?其实就是当缓存大小和在硬盘中文件大小一样,
// 只通过一个read指令把整个文件都扔到缓存里面。例如要一次读一个2G的文件,把缓存设为2G就能一次读出来。
// 不过当分配空间的时候,这个缓存根本是分配不出来的,因为内存不足。
ByteBuffer byteBuf = ByteBuffer.allocate(bufSize);
FileChannel channel = new RandomAccessFile("F:\\SFTBNS20100326.txt", "r").
getChannel();
int size;
// 因为这里缓存大小是1K,所以每个channel.read()指令最多只会读到文件的1K的内容。
// 如果文件有1M大小,这里for会循环1024次,把文件分开1024次读取出来
StringBuffer strbuf=new StringBuffer();
int count=0;
int linecount=0; while ( (size = channel.read(byteBuf)) != -1) {
byteBuf.rewind();
byteBuf.get(bs); initbytes(tmpbs);
//先加上上次结余数据
int tempcount=0;
for(int i=0;i<lessbs.length;i++){
if(lessbs[i]==0){
break;
}
tmpbs[i]=lessbs[i];
tempcount=i;
}
//再加上本次读取数据
for(int i=0;i<bs.length;i++){
tmpbs[tempcount+i]=bs[i];
} //计算应该读多少个字节
int vbytef=0,vbyteb=0;
for(int i=tmpbs.length-1;i>=0;i--){
if(tmpbs[i]=='\n'){
break;
}
vbytef++;
}
vbyteb=tmpbs.length-vbytef; //分析包里所有行,
for(int i=0;i<vbyteb;i++){
if(tmpbs[i]=='\n'){
System.out.println("");
System.out.print(linecount+":");
linecount++;
}
System.out.print((char)tmpbs[i]);
} //剩余的数据放到下一个包中
initbytes(lessbs);
int index=0;
for(int i=vbyteb;i<tmpbs.length;i++){
lessbs[index++]=tmpbs[i];
if(tmpbs[i]==0 || index>=lessbs.length){
break;
}
} count++;
byteBuf.clear();
System.out.println();
}
channel.close(); }catch(Exception ex){
ex.printStackTrace();
} }
public static void main(String[] args) {
Test12 t1=new Test12();
t1.readTxt();
}
}方法笨了点,但没想出更好的方法
要注意每次读取后分割的首尾,要和下一次的首尾拼接。每次读出来以后进行处理,处理完成以后立刻清空,然后再读下一个这样子读出来也就花点时间而已,不会出现内存不够的情况