本人要读一个2G左右的文本文件,一行一行读,边读边分析,然后入数据库。大家给点思路该怎么办啊?我的电脑配置是1G内存
用 MappedByteBuffer inputBuffer = new RandomAccessFile("d:\filename","r").getChannel().map(FileChannel.MapMode.READ_ONLY,0,filename.length())读取时出错:java.io.IOException:储存空间不足,无法处理此命令。map函数第三个参数 是什么意思啊 查API也没查到。
 
请大家 多多 指点

解决方案 »

  1.   

    map
    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
      

  2.   

    读取大文件的策略都是一部分一部分的读进内存做处理。加大内存是绝对不可取的。现在文件2G你内存加到2G。他日文件10G那又怎么处理。  public static void main(String[] args) throws Exception {
        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();
        }
      }
      

  3.   

    我做的一段代码
    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();
      

  4.   

    一下纯属个人YY:
      将文件分成若干次读取,设置每次读取的最大量(length),当达到时就关闭文件流,然后再重新打开文件读取.
      此时从文件偏移量(seek = length * i, 其中i代表第i+1次读取文件)处开始读取,当seek > length * (i + i)时关闭文件流流汗中...
      

  5.   

    BufferedReader br = new BufferedReader(new InputStreamReader(new FilterInputStream(new File("pathName"))));
    br.readLine();
    这样读文件不是很爽吗?
      

  6.   

    [Quote=引用 6 楼 calibure 的回复:]
    读取大文件的策略都是一部分一部分的读进内存做处理。加大内存是绝对不可取的。现在文件2G你内存加到2G。他日文件10G那又怎么处理。 
    同意6楼!!
      

  7.   

    好像有不少人有点误会,以为把文件分几次读取,是说读出文件一部分后,把文件关啦。处理完读出的部分,在通过定位再打开文件。
    其实这样是不对的。下面的代码是把文件分几次读取的一个小例子。当然也不一定要通过管道操作完成。
      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();
      }
      

  8.   

    当然可以一行一行读。不过分行读是只能对文本文件操作。    BufferedReader br = new BufferedReader(new FileReader("d:\\filename.txt"));
        
        String line = null;
        while((line = br.readLine()) != null){
          System.out.println(line);
        }
      

  9.   

    我怎么读了一个4G的文件都没问题。你把内容读出来之后做了什么操作呢?
    如果你把读出来的内容,又放到一个内存空间里面,那是不行的。
    例如你建一个StringBuffer类,把读出来的东西都放进去。结果一样内存不足,但是内存不足的原因不是读文件造成的。
      

  10.   

    没错,我测试的时候4g的文件都能读完。先说一个问题,lz有自己试过动手吗?自己找一下原因好不。
    代码是死的,人是活的。给你的只是一个例子。既然2G会死机,能不能先试试500M,700M... 再试试1G,2G,慢慢研究一下临界在哪里分析一下为什么。
    或者先在循环里面放一个打印语句,看看到底循环多少次的时候不动了?
    先把业务代码都去掉,看看空负载的情况循环能不能跑完?
    能不能改一下缓存大小,例如把缓存改到1024 * 1024大小,看看减少IO操作又会怎么样?
    回过头,我想先问一下,那个2G的文件是什么类型的文件。如果是二进制文件,那你照抄那个例子,跑着跑着死机也不奇怪。因为例子上写清楚啦,是把文件当文本文件输出。
      

  11.   

    我发现 死机的情况就看  int bufSize = 1024; 这个值设多大 读完就死机
      

  12.   

    public static void main(String[] args) throws Exception {
        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();
        }
      }
      

  13.   

    学习了不知道JAVA的机制是什么样的,把硬盘位置和内存位置做一个映射,然后读一段操作一段应该就可以把记得做过类似的
      

  14.   

    相当复杂的问题,LZ所说的一行估计就是一条记录,要存到数据库的,假如某一行就有2G嘿嘿
      

  15.   

    package com.hnlink.test;import java.io.FileInputStream;
    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();
      }
    }方法笨了点,但没想出更好的方法
      

  16.   

    分段读取,读出来以后按照换行符(有可能是\r\n也有可能是\n)分割,这样就能得到每一行的数据。
    要注意每次读取后分割的首尾,要和下一次的首尾拼接。每次读出来以后进行处理,处理完成以后立刻清空,然后再读下一个这样子读出来也就花点时间而已,不会出现内存不够的情况