java new I/O

java在1.4中引入了nio包,而且旧的io包也用nio重新实现过,同样享受速度上的提升.因为nio的结构更贴近操作系统执行io的方式:通道和缓冲器.

唯一直接与管道通信的缓冲器为java.nio.ByteBuffer

旧io中的三个类FileInputStream,FileOutputStream,RandomAccessFile被修改了,拥有可以获取管道的方法getChannel()方法.

Reader和Writer这样的字符模式类不能产生管道,但是java.nio.channels.Channels类中提供了使用方法可以产生reader和writer.

常用方法:

  • getChannel():用以产生管道
  • write():将byteBuffer写入管道
  • close():关闭管道
  • size():管道内容长度
  • wrap():将已存在数组包装入byteBuffer
  • allocate():分配ByteBuffer
  • read():将管道内容读入ByteBuffer
  • put():给ByteBuffer填充内容
  • clear():让byteBuffer做好填充数据的准备
  • flip():让byteBuffer做好被别人读取的准备
  • transgerTo()和transferFrom()将两个管道直接相连

使用实例

public static void main(String[] args) throws IOException {
    FileChannel fc = new FileOutputStream("out\\out.dat").getChannel();
    fc.write(ByteBuffer.wrap("some text".getBytes()));
    fc.close();
    fc = new FileInputStream("out\\out.dat").getChannel();
    ByteBuffer bf = ByteBuffer.allocate(1024);
    fc.read(bf);
    bf.flip();
    System.out.println("19 :" + bf.asCharBuffer());
    bf.rewind();
    String encoding = System.getProperty("file.encoding");
    System.out.println("22 :" + "decoded using " + encoding + ":\n" + Charset.forName(encoding).decode(bf));
    fc = new FileOutputStream("out\\out.dat").getChannel();
    fc.write(ByteBuffer.wrap("some text".getBytes("UTF-16BE")));
    fc.close();
    fc = new FileInputStream("out\\out.dat").getChannel();
    bf.clear();
    fc.read(bf);
    bf.flip();
    System.out.println("30 :" + bf.asCharBuffer().toString());
    fc = new FileOutputStream("out\\out.dat").getChannel();
    bf = ByteBuffer.allocate(24);
    bf.asCharBuffer().put("some text");
    fc.write(bf);
    fc.close();
    fc = new FileInputStream("out\\out.dat").getChannel();
    bf.clear();
    fc.read(bf);
    bf.flip();
    System.out.println("40 :" + bf.asCharBuffer());
}

可以对ByteBuffer使用视图缓冲器来写入和读取各种类型的数值.

视图缓冲器asXXXBuffer (xxx对应各种基本类型),可以对视图缓冲期调用get()和put()方法.

字节存放次序

不同机器会有不同的字节排序方法,分为大端序和小端序,大端序为高位低字节,小端序为高位高字节.

对于ByteBuffer可以使用order()方法改变byteBuffer的字节序,两者的区别为假如把一个16个字节的byteBuffer当作shortBuffer来get的话,

get[0]的结果将会不同,对于大端序获得了高八位,小端序则获得低八位.

小用法

对于由数组支持的ByteBuffer可以使用array()方法显示视图底层的字节.对于非数组支持的byteBuffer使用会抛出UnsupportedOperationException

用缓冲器操作数据

byteBuffer是唯一将数据移进移出通道的方式,可以使用as方法从byteBuffer获得基本类型缓冲期,但是并不能把基本类型缓冲器转换为ByteBuffer.

缓冲器的细节

方法 描述
capacity() 返回缓冲区容量
clear() 清空缓冲区,将position设置为0,limit设置为容量.我们可以调用此方法复写缓冲区
flip() 将limit设置为position,position设置为0.此方法用于准备从缓冲区读取已经写入的数据
limit() 返回limit
limit(int lim) 设置limit
mark() 将mark设置为postion
position() 返回position
positon(int pos) 设置position
remaining() 返回(limit-position)
hasRemaining() 若有介于position和limit之间的元素则返回true

内存映射文件

内存映射文件允许我们创建和修改太大而不能载入内存的文件,有了内存映射文件,我们可以假定文件都在内存中,而且当作一个超大数组进行访问.

static int length = 100;

public static void main(String[] args) throws IOException {
    MappedByteBuffer out = new RandomAccessFile("out\\test.out", "rw").getChannel()
            .map(FileChannel.MapMode.READ_WRITE, 0, length);

    for (int i = 0; i < length; i++) {
        out.put((byte) ‘x‘);
    }
    System.out.println("finished writing");
    for (int i = length / 2; i < length / 2 + 6; i++) {
        System.out.print((char) out.get(i));
    }
}

文件加锁

在jdk1.4引入了文件加锁机制,允许我们同步访问某个作为共享资源的文件,不过文件锁对于非java线程或是另一个虚拟机上的java线程是可见的.

public static void main(String[] args) throws IOException, InterruptedException {
    FileOutputStream fos = new FileOutputStream("out\\test.out");
    FileLock fl = fos.getChannel().tryLock();
    if (fl != null) {
        System.out.println("locked file");
        TimeUnit.MILLISECONDS.sleep(100);
        fl.release();
        System.out.println("released lock");
    }
    fos.close();
}

通过对fileChannel调用tryLock()或者lock(),就可以获得整个文件的fileLock.SocketChannel,DatagramChannel和ServerSocketChannel不需要加锁,因为他们是单进程实体继承而来,不能在多个进程之间共享.

  • tryLock() 非阻塞 尝试获得锁,如果不能获得将直接从调用处返回.
  • Lock() 阻塞 会阻塞进程知道获得锁 或者调用的线程中断,或者调用的通道关闭
  • FileLock.release() 释放锁.

tryLock()和Lock() 还可以通过指定参数,对文件的一部分上锁 : (try)Lock(long position , long size , boolean shared )

第三个参数表示是否共享锁.

无参数的加锁方法会根据文件尺寸改变而改变,有参数的加锁方式不会改变,无论文件变大变小,超出position到positon+size的文件部分将不会被锁定.

如果操作系统不支持.那么只能使用独占锁,锁的类型通过FileLock.isShared()查询

对映射文件部分加锁

由于内存映射文件通常用于超大文件,因此我们就可能需要使用部分加锁,以便其他线程更改文件的其他部分.例如数据库就是这样.因此多个用户可以同时访问到它.

public static void main(String[] args) throws IOException {
    fc = new RandomAccessFile("out\\test.out","rw").getChannel();
    MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_WRITE,0,length);
    for(int i = 0;i<length;i++){
        out.put((byte)‘x‘);
    }
    new LockAndModify(out,0,length/2);
    new LockAndModify(out,length/2,length/2+length/4);

}

private static class LockAndModify extends Thread{
    private ByteBuffer buff;
    private int start,end;
    LockAndModify(ByteBuffer mbb,int start, int end){
        this.start = start;
        this.end = end;
        mbb.limit(end);
        mbb.position(start);
        buff = mbb.slice();
        start();
    }
    public void run(){
        try{
            FileLock fl = fc.lock(start,end,false);
            System.out.println("locked :"+start+" to "+end);
            while (buff.position()<buff.limit()-1){
                buff.put((byte)(buff.get()+1));
            }
            fl.release();
            System.out.println("release :"+start +" to "+end);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

static int length = 100;
static FileChannel fc ;

当尝试一个两个线程的文件锁区域有所重合时,抛出了一个错误,暂时还没弄懂

来自为知笔记(Wiz)

时间: 2024-10-28 11:41:53

java new I/O的相关文章

Java多线程学习(吐血超详细总结)

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线程状态转换 五线程调度 六常用函数说明 使用方式 为什么要用join方法 七常见线程名词解释 八线程同步 九线程数据传递 本文主要讲了java中多线程的使用方法.线程同步.线程数据传递.线程状态及相应的一些线程函数用法.概述等. 首先讲一下进程和线程

Java TM 已被阻止,因为它已过时需要更新的解决方法

公司的堡垒机需要通过浏览器登陆,且该堡垒机的网站需要Java的支持,最近通过浏览器登陆之后总是提示"java TM 已被阻止,因为它已过时需要更新的解决方法"导致登陆之后不能操作, 但是操作系统中确实已经安装了比较新的JDK,安装的JDK版本是jdk-7u67-windows-i586,因为太烦人,所以决定搞清楚报错的原因,一劳永逸,彻底解决这个问题 准备工作:安装JDK,安装版本jdk-7u67-windows-i586.exe,因为机器的Eclipse还依赖64位的JDK,所以另安

Java四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor

介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? Java new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } }).start(); 1 2 3 4 5 6 7 new Thread(new

由@NotNull 注解引出的关于Java空指针的控制(转)

Java 小技巧和在java应用避免NullPonintException的最佳方法 在java应用程序中,一个NullPonintException(空指针异常)是最好解决(问题)的方法.同时,空指针也是写健壮的顺畅运行的代码的关键.“预防好过治疗”这句话也同样适用于令人不爽的NullPonintException.通过应用防御性的编码技术和在遵守多个部分之间的约定,你可以再很大程度上避免NullPointException.下面的这些java小技巧可以最小化像!=null这种检查的代码.作为

Java注解(2)-注解处理器(运行时|RetentionPolicy.RUNTIME)

如果没有用来读取注解的工具,那注解将基本没有任何作用,它也不会比注释更有用.读取注解的工具叫作注解处理器.Java提供了两种方式来处理注解:第一种是利用运行时反射机制:另一种是使用Java提供的API来处理编译期的注解. 反射机制方式的注解处理器 仅当定义的注解的@Retention为RUNTIME时,才能够通过运行时的反射机制来处理注解.下面结合例子来说明这种方式的处理方法. Java中的反射API(如java.lang.Class.java.lang.reflect.Field等)都实现了接

jvm系列(一):java类的加载机制

java类的加载机制 原文:http://www.cnblogs.com/ityouknow/p/5603287.html 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构.类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口. 类加载器并不需要等到某个

Java注解(1)-注解基础

注解(Annotation)是在JAVA5中开始引入的,它为在代码中添加信息提供了一种新的方式.注解在一定程度上把元数据与源代码文件结合在一起,正如许多成熟的框架(Spring)所做的那样.那么,注解到底可以做什么呢? 1.注解的作用. 提供用来完整地描述程序所需要的信息,如编译期校验程序信息. 生成描述符文件,或生成新类的定义. 减轻编写"样板"代码(配置文件)的负担,可以使用注解自动生成. 更加干净易读的代码. 编译期类型检查. 2.Java提供的注解 Java5内置了一些原生的注

异常笔记--java编程思想

开一个新的系列,主要记一些琐碎的重要的知识点,把书读薄才是目的...特点: 代码少,概念多... 1. 基本概念 异常是在当前环境下无法获得必要的信息来解决这个问题,所以就需要从当前环境跳出,就是抛出异常.抛出异常后发生的几件事: 1.在堆上创建异常对象. 2.当前的执行路径中止                                          3. 当前环境抛出异常对象的引用.                                         4. 异常处理机制接

Java自学序言

Java自学序言 亲爱的自己和各位读者朋友: 您们好! 这是作者本人自学Java编程开发的一系列文章,不具有一定的权威性,也算是自己一个人的学习笔记和总结,希望自己通过博客的形式将我自己的学习效率得到提高.如自学的稳重存在不足或错误的地方希望广大的博客朋友们多多指教.本人在此不胜感激! 学习Java是一件很痛苦的事儿,我自己要想不断的去挑战一下自己,把自己大学所学的Java知识能够巩固起来.不断的去改正自己开发中的不足之处.如何来学习Java?如何来更好的掌握Java开发语言?这些都是我们要不断

接口测试(java+testng+ant+jenkins)第五篇 java二

1.数据代码分离,方便维护. 一般做法是将数据保存在excel,通过程序读取. 2.读取excel数据. 在D盘新建excel,A列放url,B列放参数. 新建class redExcel package com.lx; import java.io.File; import java.io.IOException; import jxl.*; import jxl.read.biff.BiffException; public class redExcel{ public static voi