`
hr10108
  • 浏览: 11479 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

NIO按行读写数据

    博客分类:
  • IO
阅读更多
                                     Nio学习
                                                ——如何以行为单位来读写数据   Victor
    最近在学习Nio,想比较出Nio与io之间的效率。确实发现Nio在大部分情况下比io要快、消耗的内存与CPU要小,在处理大数据、多并发的情况下,使用Nio更好。
    随着学习的深入,却发现Nio没有按行读取文件的方法。这在某种特殊要求下,无疑限制了Nio的使用,于是我试着自己实现下Nio按行读写的功能。
    首先,实现读取一行的功能,具体代码如下:
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

/**
 * Use for reader line from file by use Nio
 *
 * @author Victor
 */
public class NioReader {
  private static final String lineSeparator = "\r\n";//换行关键字
  private final int size = 1024 * 8;//块的大小
  private static int n;//该文件可分成块数量
  private FileInputStream fin;//读取文件的流
  private FileChannel fcin;//管道
  private static int count = 0;//记录该块读取到第几行
  private static int piece = 0;//记录读取到哪一块
  private static String[] strs;//该块转换后的数组,一行数据对应一个元素

  public NioReader(String path)
      throws IOException {
    fin = new FileInputStream(path);
    fcin = fin.getChannel();
    long length = fcin.size();
    n = (int)length / size;
    strs = getStrsBySize();
  }

  public String getNextLine()
      throws IOException {
    String s = null;
    int lengh = strs.length - 1;
    if (count < lengh) {
      s = strs[count];
      count++;
    } else if (count == lengh) {
      if (piece > n) {
        s = strs[count];
        count++;
      } else {
        strs = getStrsBySize();
        s = getNextLine();
      }
    }
    return s;
  }
  
/**
 * 获取下一块的String数组
 */
  private String[] getStrsBySize()
      throws IOException {
    count = 0;
    if (piece <= n) {
      long opint = piece * size;
      MappedByteBuffer buffer;
      byte[] content = new byte[size];
      if (piece == n) {
        long length = fcin.size();
        int finalsize = (int)(length - opint);
        buffer = fcin.map(FileChannel.MapMode.READ_ONLY, opint,
            finalsize);
        buffer.get(content, 0, finalsize);
      } else {
        buffer = fcin.map(FileChannel.MapMode.READ_ONLY, opint,
            size);
        buffer.get(content, 0, size);
      }
      String str;
      if (piece == 0) {
        str = new String(content);
        str.trim();
      } else {
        String newStr = new String(content);
        newStr.trim();
        str = strs[strs.length - 1] + newStr;
      }
      strs = str.split(lineSeparator);
      piece++;
    }
    return strs;
  }

  public void close()
      throws IOException {
    if (fin != null) {
      fin.close();
    }
    if (fcin != null) {
      fcin.close();
    }
  }
}

    然后实现写一行的功能:
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class NioWriter {
	private static final String lineSeparator = "\r\n";
	private FileOutputStream fout;
	private FileChannel fcout;
	private ByteBuffer buffer;

	public NioWriter(String path) throws IOException {
		fout = new FileOutputStream(path);
		fcout = fout.getChannel();
	}

	public void putln(String s) {
		if (fcout == null) {
			throw new IllegalArgumentException(
					"attempt to use a closed Writer");
		}
    buffer= ByteBuffer.allocate(1024*8);
		buffer.clear();
		s = s.trim() + lineSeparator;
		byte[] bytes = s.getBytes();
		buffer.put(bytes);
		buffer.flip();
		try {
			fcout.write(buffer);
			fout.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public void close() throws IOException {
		if (fout != null) {
			fout.close();
		}
		if (fcout != null) {
			fcout.close();
		}
	}
}

    接下来就是测试了,为了方便测试它的内存消耗,我还特意写个测试内存的工具类:
public class RuntimeMemory {
	  private static final int MB = 1024 * 1024;
	  public static DecimalFormat df = new DecimalFormat("#####.##");

	  public static void getMemory() {
	    Runtime run = Runtime.getRuntime();
	    long max = run.maxMemory();
	    long total = run.totalMemory();
	    long free = run.freeMemory();
	    long usable = max - total + free;
	    StringBuffer sb = new StringBuffer();
	    sb.append("[RuntimeMemory] Max :").append(getMb(max)).append(
	        " Assigned :").append(getMb(total)).append(" Free :").append(
	        getMb(free)).append(" Usable :").append(getMb(usable));
	    System.out.println(sb.toString());
	  }
  	private static String getMb(long memory) {
	    double mb = (double)memory / MB;
	    return "[" + df.format(mb) + " MB]; ";
	}
}

    主测试类:
public class TestNio {

	/**
	 * @author Victor
	 * @throws IOException
	 */
	public static void main(String[] args) throws IOException {
		long start = System.currentTimeMillis();
		RuntimeMemory.getMemory();
		String infile = "D:\\test.txt";
		String outfile = "D:\\copy.txt";

		NioReader reader=new NioReader(infile);
		NioWriter writer=new NioWriter(outfile);
		String line;
		
		while ((line = reader.getNextLine()) != null) {
			try {
				if ((line == null) || line.trim().equals("")) {
					continue;
				}
				writer.putln(line);
			} catch (Exception ex) {
				ex.printStackTrace();
			} 
		}
    	reader.close();
    	writer.close();
		long end = System.currentTimeMillis();
		System.out.println((end - start) + "ms");
		RuntimeMemory.getMemory();
	}
}

    当然为了对比,我另外还写了普通io的测试,在此就不展示代码了,下面是我对二者测试的结果分析:
    1. 当数据量为7M时:
    Nio:
        [RuntimeMemory] Max :[63.56 MB];  Assigned :[4.94 MB];  Free :[4.4 MB];  Usable :[63.02 MB];
        1201ms 1357ms 1279ms 1295ms 1404ms (运行了多次)
        [RuntimeMemory] Max :[63.56 MB];  Assigned :[4.94 MB];  Free :[4.5 MB];  Usable :[63.13 MB];
    Io:
        [RuntimeMemory] Max :[63.56 MB];  Assigned :[4.94 MB];  Free :[4.39 MB];  Usable :[63.02 MB];
        281ms 234ms 249ms 265ms 234ms
        [RuntimeMemory] Max :[63.56 MB];  Assigned :[4.94 MB];  Free :[3.77 MB];  Usable :[62.4 MB];
    2. 当数据量为370M时:
    Nio:
        [RuntimeMemory] Max :[63.56 MB];  Assigned :[4.94 MB];  Free :[4.4 MB];  Usable :[63.02 MB];
        55799ms
        [RuntimeMemory] Max :[63.56 MB];  Assigned :[4.94 MB];  Free :[3.31 MB];  Usable :[61.94 MB];
    Io:
        [RuntimeMemory] Max :[63.56 MB];  Assigned :[4.94 MB];  Free :[4.39 MB];  Usable :[63.02 MB];
        9882ms
        [RuntimeMemory] Max :[63.56 MB];  Assigned :[4.94 MB];  Free :[4.39 MB];  Usable :[63.02 MB];
    一些小数据也测试过,但差别不大,就不列举了。
    此外,对于CPU的消耗,在运行时,我进行了监测,相对来说使用Nio所消耗的CPU较大些。

    从上面的数据可以分析出:
    用Nio来以行为单位读写数据的速度是普通Io的5-6倍(汗!!!可能我写的代码并不完善),虽然Nio在内存的消耗上占据一点优势,但不明显,消耗的CPU却更多。
    宗上,在需要以行为单位来读写数据时,还是得采用普通IO。。。。

    再说说测试中所遇到的问题:
    首先,就是reader的时候,因为它是按指定的大小拆分块,有可能会把一行拆分到不同的块中,所以我采取的策略就是保留每块转换成数组后的最后一个元素,添加到下一个块中。
    然后,就是在写数据的时候,要注意ByteBuffer的大小,由于我没有txt的大数据,采用了一个数据库的脚本,结果运行时老是报缓冲区溢出的异常,找了很久。。。才发现是被复制的文本有问题:那个sql中有些行竟然有将近1M的大小,哎!
    最后,再说一些还没有解决的问题,就是在更大的数据拷贝完成后,悲催的发现,拷贝后的文件竟然比源文件要大一些(源文件500M的样子,复制的文件多出了5-6k,由于数据大多了,无法仔细分析)!
                            (新手!仅供参考!求前辈指点!)
0
0
分享到:
评论
1 楼 freemailfjgh 2013-09-03  
哥们,不知道“所以我采取的策略就是保留每块转换成数组后的最后一个元素,添加到下一个块中。”这个具体是怎么实现的呢,我也是新手,谢谢帮助。

相关推荐

    java nio 包读取超大数据文件

    ### Java NIO 处理超大数据文件的知识点详解 #### 一、Java NIO简介 Java NIO(New IO)是Java平台上的新输入/输出流API,它提供了与传统IO(即Java IO)不同的数据处理方式。NIO在Java 1.4版本引入,并在后续版本...

    java NIO.zip

    自Java 1.4版本引入NIO后,它为Java开发者提供了更高效的数据传输方式,尤其是在处理大量并发连接时。NIO的核心在于通道(Channels)和缓冲区(Buffers)的概念,与传统的流(Streams)有所不同。 1. **通道...

    NIO 入门.chm,NIO 入门.chm

    8. **聚合操作(Scatter/Gather)**:NIO支持数据的分散读取(Scatter)和聚集写入(Gather),即可以从多个缓冲区分散读取数据,也可以将数据聚集到多个缓冲区进行写入。 9. **文件锁(File Locking)**:NIO提供...

    nio demo for nio学习笔记(体系结构以及模块介绍)

    同时,Buffer的使用也非常重要,学会如何正确地读写数据,以及如何有效地管理缓冲区。 总的来说,NIO为Java开发者提供了更高效的I/O处理能力,尤其在处理高并发和大流量场景时,它的优势更加明显。然而,NIO的学习...

    NIO编程实现实例

    - 读写数据:使用通道与缓冲区交互,将数据从通道读入缓冲区,或者将缓冲区中的数据写入通道。 - 注册选择器:将通道注册到选择器,指定感兴趣的事件类型。 - 监控事件:调用选择器的select方法,获取已准备就绪...

    Java NIO英文高清原版

    NIO在Java 1.4版本引入,提供了更高效的数据处理和通道通信方式,特别适用于高并发、大数据量的系统。Netty是一个基于NIO的高性能、异步事件驱动的网络应用框架,它简化了网络编程,广泛应用于服务器端应用开发。 ...

    IO和NIO区别

    标准 IO 以流的方式处理数据,也就是说数据是以流的形式传输的,而 NIO 则以块的方式处理数据。这种差异对数据的传输和处理方式产生了很大的影响。在标准 IO 中,数据是以流的形式读取和写入的,而 NIO 则将数据读取...

    大数据学习之旅——NIO源码

    NIO(New Input/Output)是Java提供的一种非阻塞I/O模型,它极大地提高了系统在处理大量数据时的性能。本篇文章将带你深入理解NIO的源码,揭示其在大数据环境下的应用与优势。 NIO与传统的IO模型(-blocking I/O)...

    nio_javanio_NIO_

    - **通道(Channel)**:在NIO中,数据的读写都是通过通道进行的。通道类似于流,但具有双向性,可以同时进行读写操作。常见的通道类有FileChannel、SocketChannel、ServerSocketChannel和DatagramChannel等。 - **...

    NIO学习系列:核心概念及基本读写

    本篇内容将深入讲解NIO的核心概念以及基本的读写操作。 ### NIO核心概念 1. **通道(Channel)**:通道是NIO中的关键组件,它连接到I/O设备(如文件、网络套接字等)。通道可以读取或写入数据,且是双向的。例如,...

    Java NIO系列教程(一) Java NIO 概述

    - **Buffers**:Buffers是NIO中的数据容器,用于存储从Channel读取的数据或将数据写入Channel。Java NIO支持多种类型的Buffer,包括: - **ByteBuffer**:用于存储字节数据。 - **CharBuffer**:用于存储字符数据...

    NIO笔记.doc

    - Channel是数据传输的通道,它可以连接到I/O设备(如文件、套接字等)并读写数据。Java NIO提供了多种类型的通道,如FileChannel、SocketChannel、ServerSocketChannel等。通道是双向的,既可读又可写。 4. **...

    深入浅出NIO

    传统的IO模型,如描述中的“阻塞I/O”,在读写数据时会一直等待数据的到达,这可能导致资源的浪费和效率的降低。NIO则提供了更加高效和灵活的解决方案。 NIO的核心概念包括: 1. **通道(Channel)**:通道是NIO中...

    java NIO 写文件

    Java NIO(New IO)是Java 1.4版本引入的一个新模块,它提供了一种新的方式来处理I/O操作,相比传统的IO流,NIO提供了更高效、更灵活的数据读写方式。在这个主题中,我们将深入探讨Java NIO如何用于写文件,特别是在...

    NIO入门pdf分享

    《NIO入门》一书是理解Java NIO(New Input/Output)的重要参考资料,NIO在Java编程中扮演着至关重要的角色,特别是在处理高并发、大数据传输等场景下。本PDF文档将引领读者深入理解这一核心概念。 NIO,全称New ...

    实例:往服务器中读写数据

    总的来说,这个实例展示了如何在实际环境中利用编程语言(这里是Java)与服务器进行交互,进行数据的读写操作。了解这些技术对于开发Web应用或进行服务器管理至关重要。在实践中,我们还需要考虑更多的因素,如性能...

    java NIO实例

    3. **Buffer(缓冲区)**:在NIO中,数据读写都是通过缓冲区进行的。缓冲区是一个可以容纳特定类型数据(如字节、字符、整数等)的容器,它提供了对数据的高效访问和管理。 4. **FileChannel**:用于文件的读写,...

    JAVA NIO 学习资料

    - **Buffer的创建和操作**:可以通过allocate()方法创建Buffer,然后使用put()和get()方法读写数据。Buffer的clear()、flip()和rewind()方法用于调整position和limit状态,以适应读写需求。 - **Channel的打开和...

Global site tag (gtag.js) - Google Analytics