本文章来源于我的个人博客: java nio 通道(二)

一,文件通道

文件通道总是堵塞式的,因此不能被置于非堵塞模式。

FileChannel对象是线程安全的。多个进程能够在同一个实例上并发调用方法而不会引起不论什么问题,只是非全部的操作都是多线程的。影响通道位置或者影响文件大小的操作都是单线程的。

通过FileChannel实例看到的某个文件的视图同通过一个外部的非java进程看到的该文件的视图可能一致也可能不一致。

创建文件通道:

RandomAccessFile randomAccessFile = new RandomAccessFile(filename,"r");
//设置读取文件的位置
randomAccessFile.seek(1000);
//创建文件通道
FileChannel fileChannel = randomAccessFile.getChannel();
System.out.println(fileChannel.position());  // print 1000
randomAccessFile.seek(500);
System.out.println(fileChannel.position());  //print 500
fileChannel.position(200);  
System.out.println(randomAccessFile.getFilePointer());  //print 200

二,文件锁定(FileLock)

大家都知道,文件锁分为独占所和共享锁。独占锁是当有一个锁拥有了文件的操作权限之后,其他的訪问者都必须等待当前的操作者完毕才干操作文件;而共享锁是全部的訪问者都能够同一时候使用该文件。

独占锁最重要用于文件的写,而共享锁用于文件的读。

java的文件锁仅仅与文件关联,而不是与通道关联。文件锁旨在在进程级别上判优文件訪问,比方在基本的程序组件之间或者在继承其它供应商的组件时。假设须要控制多个java线程的并发訪问。就须要自己做锁定方案。

再FileChannel类中有四个请求锁的方法,分别为:

public final FileLock lock();
public abstract FileLock lock(long position, long size, boolean shared);
public final FileLock tryLock();
public abstract FileLock tryLock(long position, long size,boolean shared);

两个带參数的请求所方法的意思是指定须要锁定文件的区域位置,并设置这个锁是否为共享锁,注意,假设要请求一个独占锁,则文件必须是以写模式打开的,锁区域的size值能够超出文件尾部,这样能够提前锁定须要待写入的文件数据区域,也能够锁定一个不包括不论什么内容的文件内容区域。不带參数的请求方法是请求整个文件的独占锁,也就是使用无參数的请求方法获取的锁,会堵塞后来的操作,仅仅当这个锁定的訪问者运行完它的操作为止。

请一定要记住,在操作完毕之后。一定要release锁,不然将可能导致程序奔溃或者死锁现象。

三,内存映射文件(MappedByteBuffer file):

FileChannel类提供了一个名为map()的方法,该方法能够在一个打开的文件和一个特殊类型的ByteBuffer之间建立一个虚拟内存映射MappedByteBuffer。这个对象和基于内存的缓冲区类似。仅仅只是该对象的数据元素存储在磁盘上的一个文件里。调用get()方法会从磁盘文件里获取数据,此数据反映该文件的当前内容。即使在映射建立之后文件已经被一个外部进程做了改动。也会同步到该对象所在的内存视图中;当然该对象的put()方法也会同步更新此文上的文件。即对文件的改变其它的訪问者也是可见的。

通过内存映射机制来訪问一个文件会比使用常规方法读写高效得多。甚至比使用通道的效率都高。由于不须要做明白的系统调用。那会非常消耗时间,更重要的是,操作系统的虚拟内存能够自己主动缓存内存页。这些内存页是系统内存来缓存的,所以不会消耗java虚拟机内存堆。

(注:这段话由于涉及了操作系统的内存机制,博主也不怎么理解。博主的想法是仅仅要知道使用这个对象会脱离JVM的内存堆。剔除了JVM这个中间桥梁)。

FileChannel类调用内存映射的方法例如以下:

public abstract MappedByteBuffer map(MapMode mode, long position, long size);
public static class MapMode{
    public static final MapMode READ_ONLY;
    public static final MapMode READ_WRITE;
    //代表须要一个写时拷贝的映射。 意味着通过put()方法所做的不论什么改动都会导致产生一个私有的数据拷贝并且
    //该拷贝中的数据仅仅有MappedByteBuffer实例能够看到。该过程不会对地城文件做不论什么改动。并且一旦缓冲
    //区被拖到垃圾收集动作。那些改动的数据都会丢失。使用此模式时。其他的操作者对文件的改动。也都能反映
    //到这个内存映射区域。除非该缓冲区已经改动了文件上的同一区域。 public static final MapMode PRIVATE;
}

这种方法的第一个參数是设定这个内存映射区域是仅仅读还是仅仅写或者私有方式訪问,第二个參数和第三个參数一起决定了内存映射的区域。要注意,这个内存映射的锁方式和文件锁的范围机制是不一样的。假设给这个内存映射对象的size的值设置为Integer.MAX_VALUE。则这个文件的大小会扩张到超过2.1GB。也就是说。这个内存映射文件的锁定区域假设超出了文件的大小,那么它会自己主动给这个设定的区域增加数据。

MappedByteBuffer对象被创建之后,就不会受通道的关闭影响,也就是假设关闭相关联的FileChannel不会破坏映射,仅仅有丢弃缓冲区对象本身才会破坏该映射。

MappedByteBuffer类有下面的几个独有方法:

public final MappedByteBuffer load();
public final boolean isLoaded();
public final MappedByteBuffer force();

当为一个文件建立虚拟内存映射之后,文件数据通常不会因此被从磁盘读取到内存(这取决于操作系统)。

该过程类似于打开一个文件:文件先被定位,然后一个文件句柄会被创建。当准备好之后,就能够通过句柄来訪问文件数据。

对于映射缓冲区。虚拟内存系统将依据须要来把文件里对应区块的数据读进来。

这个页验证或防错过程须要一定的时间,由于将文件数据读取到内存须要一次或多次磁盘訪问。

load()方法会载入整个文件以使它常驻内存。可是调用此方法是一个代价高昂的操作。由于它会导致大量的页调入。

force()方法会强制将映射缓冲区上的更改应用到永久磁盘存储器上。

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode; public class TestMappedByte { /**
 * @param args
 * @throws IOException 
 */
public static void main(String[] args) throws IOException {
 File file = new File("/home/lifeix/3.txt");
        if(!file.exists()) {
            file.createNewFile();
        }
        String str = "jiang fuqiang is cool
";
        //此类没有追加文件选项。假设须要追加。则须要调用fos.seek(int)方法
        RandomAccessFile fos = new RandomAccessFile(file,"rws"); 
        FileChannel fc = fos.getChannel();
        ByteBuffer bb = ByteBuffer.allocateDirect(str.length());
        bb.put(str.getBytes());
        bb.flip();
        fc.write(bb);
        bb.clear();
        
        //假设这里不使用fc.position(),则此处写入的数据会覆盖掉上面写入的数据,这是一种自己实现的文件追加方式。
        //此处不能用FileOutputStream,不然会报错
        MappedByteBuffer mbb = fc.map(MapMode.READ_WRITE, fc.position(), 1024);
        mbb.put(str.getBytes());
        mbb.force();
        mbb.clear();
        fc.close();
        fos.close();
        
        FileInputStream fis = new FileInputStream(file);
        FileChannel fc1 = fis.getChannel();
        MappedByteBuffer mbb1  = fc1.map(MapMode.READ_ONLY, 0, fc1.size());
        byte[] b = new byte[mbb1.remaining()];
        mbb1.get(b);
        System.out.println(new String(b));
        fc1.close();
        fis.close();
        
} }

java nio 通道(二)的更多相关文章

  1. JAVA NIO学习二:通道(Channel)与缓冲区(Buffer)

    今天是2018年的第三天,真是时光飞逝,2017年的学习计划还没有学习完成,因此继续开始研究学习,那么上一节我们了解了NIO,那么这一节我们进一步来学习NIO相关的知识.那就是通道和缓冲区.Java ...

  2. Java NIO (二) 缓冲区(Buffer)

    缓冲区(Buffer):一个用于特定基本数据类型的容器,由 java.nio 包定义的,所有缓冲区都是 Buffer 抽象类的子类. Java NIO 中的Buffer 主要用于和NIO中的通道(Ch ...

  3. Java NIO -- 通道 Channel

    通道(Channel):由 java.nio.channels 包定义的.Channel 表示 IO 源与目标打开的连接.Channel 类似于传统的“流”.只不过 Channel本身不能直接访问数据 ...

  4. 对java NIO 通道的一些了解

    @引言 reactor(反应器)模式 使用单线程模拟多线程,提高资源利用率和程序的效率,增加系统吞吐量.下面例子比较形象的说明了什么是反应器模式: 一个老板经营一个饭店, 传统模式 - 来一个客人安排 ...

  5. Java NIO(二) Channel

    Java NIO的通道类似流,但又有些不同: 既可以从通道中读取数据,又可以写数据到通道.但流的读写通常是单向的. 通道可以异步地读写. 通道中的数据总是要先读到一个Buffer,或者总是要从一个Bu ...

  6. Java NIO(二)缓冲区

    概念 缓冲区:一个用于特定基本数据类型的容器,由java.nio包定义的所有缓冲区都是Buffer抽象类的子类.其作用于与NIO的通道进行交互,数据从通道读入缓冲区,数据从缓冲区写入通道 Buffer ...

  7. 海纳百川而来的一篇相当全面的Java NIO教程

    目录 零.NIO包 一.Java NIO Channel通道 Channel的实现(Channel Implementations) Channel的基础示例(Basic Channel Exampl ...

  8. Java NIO文章列表(强烈推荐 转)

    IO流学习总结 一 Java IO,硬骨头也能变软 二 java IO体系的学习总结 三 Java IO面试题 NIO与AIO学习总结 一 Java NIO 概览 二 Java NIO 之 Buffe ...

  9. Java NIO 缓冲技术详解

    缓冲区(buffer)是从即将写入通道(channel)或刚刚从通道中读出的一段数据.它是一个持有数据,并扮演NIO通道端点的对象.缓冲区为数据访问和读写过程提供正式机制. 它是NIO和老版Java ...

随机推荐

  1. poj 1637 混合图欧拉回路 学习笔记

    题目大意 求混合图是否存在欧拉回路 做法 有向边我们只有增加入度出度 对于无向边,我们给它设定一个初始方向 如果不能满足|入度-出度|为偶数,无解 然后在网络流图中, 设设定方向的反向连一条边,表示反 ...

  2. POJ 2228 naptime

    环形DP 先考虑如果只是一天,我们可以用线性DP写出转移方程,注意初始化 如果是一个环的话,我们发现少了一种第n天和第一天连起来的情况,那么我们就再进行一次DP 强制这种情况 #include < ...

  3. 【CF1023A】Single Wildcard Pattern Matching(模拟)

    题意:给定两个串s与t,其中s可能有至多一个通配符*可以被当做任意长度与内容的串,问t能否与s匹配 n,m<=2e5 思路: #include<cstdio> #include< ...

  4. 学习在requirejs下如何使用underscore.js模板

    近期在学习underscore.js 这个小而美的js库,是前端 MVC 框架backbone依赖库,他的模板方法主要应用场景是ajax交互过程到页面需要大量的字符串拼接,这部分如果一旦不够仔细就很容 ...

  5. AC日记——最短路 洛谷 P2384

    题目背景 狗哥做烂了最短路,突然机智的考了Bosh一道,没想到把Bosh考住了...你能帮Bosh解决吗? 他会给你100000000000000000000000000000000000%10金币w ...

  6. Codeforces Gym101502 H.Eyad and Math-换底公式

    H. Eyad and Math   time limit per test 2.0 s memory limit per test 256 MB input standard input outpu ...

  7. git commit或pull后恢复到原来版本

    https://blog.csdn.net/litao31415/article/details/87713712

  8. 转:关于使用ImageMagick和Tesseract进行简单数字图像识别

    据说Tesseract可是世界排名第三的OCR神器,2010年又更新了3.0版本.Tesseract原先是HP写的,现在Open Source了. 下面介绍怎么用Tesseract配合ImageMag ...

  9. SpringBoot中@EnableAutoConfiguration注解用法收集

    参考: http://blog.csdn.net/xiaoyu411502/article/details/52770723 https://docs.spring.io/spring-boot/do ...

  10. IDEA查看源码时提示:Library source does not match the bytecode for class的问题分析

    通过Maven查看依赖的源码时,通常是Maven自动下载JAR包附属的source包,但是会出现一个问题,由于使用lombok插件会造成编写的Java文件和编译后的class上有差别,所以IDEA打开 ...