成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Java NIO

Steve_Wang_ / 1731人閱讀

摘要:緩沖區(qū)的容量不可能為負(fù)值,創(chuàng)建后不能改變界限界限第一個(gè)不應(yīng)該被讀寫(xiě)或者寫(xiě)入的緩沖區(qū)位置索引。當(dāng)使用從中讀取數(shù)據(jù)時(shí),的值恰好等于已經(jīng)讀到了多少數(shù)據(jù)。

NIO:New IO

Java新IO概述

新IO采用內(nèi)存映射文件的方式來(lái)處理輸入/輸出,新IO文件或文件的一段區(qū)域映射到內(nèi)存中,這樣就可以訪問(wèn)內(nèi)存一樣來(lái)訪問(wèn)文件了(這種方式模擬了操作系統(tǒng)上的虛擬內(nèi)存的概念),通過(guò)這種方式來(lái)進(jìn)行輸入/輸出比傳統(tǒng)的輸入/輸出要快得多

Java中NIO相關(guān)的包如下:

java.nio包:主要提供了一些和Buffer相關(guān)的類(lèi)

java.nio.channels包:主要包括Channel和Selector相關(guān)的類(lèi)

java.nio.charset包:主要包含和字符集相關(guān)的類(lèi)

java.nio.channels.spi包:主要包含提供Channel服務(wù)的類(lèi)

java.nio.charset.spi包:主要包含提供字符集服務(wù)的相關(guān)類(lèi)

Channel(通道)和Buffer(緩沖)是新IO中的兩個(gè)核心對(duì)象,Channel是對(duì)傳統(tǒng)輸入/輸出系統(tǒng)中的模擬,在新IO系統(tǒng)中所有數(shù)據(jù)都需要通過(guò)通道傳輸;Channel與傳統(tǒng)的InputStream、OutputStream最大的區(qū)別在于它提供了一個(gè)map方法,通過(guò)該map方法可以直接將“一塊數(shù)據(jù)”映射到內(nèi)存中。如果說(shuō)傳統(tǒng)的輸入/輸出系統(tǒng)是面向流的處理,而新IO則是面向塊的處理

Buffer可以被理解成一個(gè)容器,它的本質(zhì)是一個(gè)數(shù)組,發(fā)送到Channel中的所有對(duì)象都必須首先放到Buffer中,而從Channel中讀取的數(shù)據(jù)也必須先讀到Buffer中。此處的Buffer有點(diǎn)類(lèi)似于前面我們介紹的“竹筒”,但該Buffer既可以像前面那樣一次、一次去Channel中取水,也允許使用Channel直接將文件的某塊數(shù)據(jù)映射成Buffer

除了Channel和Buffer之外,新IO還提供了用于將UNICODE字符串映射成字節(jié)序列以及逆映射操作的Charset類(lèi),還提供了用于支持非阻塞式輸入/輸出的Selector類(lèi)

使用Buffer

Buffer類(lèi)沒(méi)有提供構(gòu)造器,通過(guò)使用如下方法來(lái)得到一個(gè)Buffer對(duì)象:

static XxxBuffer allocate(int capacity):創(chuàng)建一個(gè)容量為capacity的XxxBuffer對(duì)象

使用較多的是ByteBuffer和CharBuffer。其中ByteBuffer類(lèi)還有一個(gè)子類(lèi):MappedByteBuffer,它用于表示Channel將磁盤(pán)文件的部分或全部?jī)?nèi)容映射到內(nèi)存中后得到的結(jié)果,通常MappedByteBuffer對(duì)象由Channel的map()方法返回

Buffer三個(gè)重要概念:容量(capacity)、界限(limit)、位置(position)

容量(capacity):緩沖區(qū)的容量(capacity)表示該Buffer的最大數(shù)據(jù)容量,即最多可以存儲(chǔ)多少數(shù)據(jù)。緩沖區(qū)的容量不可能為負(fù)值,創(chuàng)建后不能改變
界限(limit)

界限(limit):第一個(gè)不應(yīng)該被讀寫(xiě)或者寫(xiě)入的緩沖區(qū)位置索引。也就是說(shuō),位于limit后的數(shù)據(jù)既不可被讀,也不可被寫(xiě)

位置(position):用于指明下一個(gè)可以被讀出或者寫(xiě)入的緩沖區(qū)位置索引(類(lèi)似于IO流中的記錄指針)。當(dāng)使用Buffer從Channel中讀取數(shù)據(jù)時(shí),position的值恰好等于已經(jīng)讀到了多少數(shù)據(jù)。當(dāng)剛剛新建一個(gè)Buffer對(duì)象時(shí),其position為0;如果從Channel中讀取了2個(gè)數(shù)據(jù)到該Buffer中,則position為2,指向Buffer中的第三個(gè)(第1個(gè)位置的索引為0)位置

標(biāo)記(mark):Buffer里還支持一個(gè)可選的標(biāo)記(mark,類(lèi)似于傳統(tǒng)IO流中的mark),Buffer允許直接將position定位到該mark處。

0 <= mark <= position <= limit <= capacity

Buffer的主要作用就是裝入數(shù)據(jù),然后輸出數(shù)據(jù),開(kāi)始時(shí)Buffer的position為0,limit為capacity,程序可通過(guò)put()方法向Buffer中放入一些數(shù)據(jù)(或從channel獲取數(shù)據(jù)),每放入一些數(shù)據(jù),position向后移動(dòng)一些位置

當(dāng)Buffer裝入數(shù)據(jù)結(jié)束后,調(diào)用filp()方法,該方法將limit設(shè)置為position所在位置,將position設(shè)置為0。這樣使得從Buffer中讀取數(shù)據(jù)總是從0開(kāi)始。讀完所有裝入的數(shù)據(jù)即結(jié)束,也就是說(shuō),Buffer調(diào)用filp后,Buffer為輸出數(shù)據(jù)做好了準(zhǔn)備

當(dāng)Buffer輸出數(shù)據(jù)結(jié)束后,調(diào)用clear方法。將position置為0,將limit置為capacity,這樣為再次向Buffer中裝載數(shù)據(jù)做好準(zhǔn)備

Buffer抽象類(lèi)常用方法:

int capacity():返回Buffer的capacity大小

boolean hasRemaining():判斷當(dāng)前位置(position)和界限(limit)之間是否有元素可供處理

int limit():返回Buffer的界限(limit)的位置

Buffer limit(int newLimit):重新設(shè)置界限(limit)的值,并返回一個(gè)具有新的limit的緩沖區(qū)對(duì)象

int position():返回Buffer的position值

Buffer position(new position):設(shè)置Buffer的position值,并返回position被修改后的Buffer對(duì)象

int remaining():返回當(dāng)前位置和界限(limit)之間的元素個(gè)數(shù)

Buffer reset():將位置(position)轉(zhuǎn)到mark所在的位置

Buffer rewind():將位置(position)設(shè)置為0,取消設(shè)置的mark

put()和get()方法,用于向Buffer中放入數(shù)據(jù)和從Buffer中取出數(shù)據(jù)。當(dāng)使用put()和get()。Buffer既支持對(duì)單個(gè)數(shù)據(jù)的訪問(wèn),也支持對(duì)批量數(shù)據(jù)的訪問(wèn)(以數(shù)組作為參數(shù))

當(dāng)使用put()和get()來(lái)訪問(wèn)Buffer中的數(shù)據(jù)時(shí),分為相對(duì)和絕對(duì)兩種:

相對(duì)(Relative):從Buffer當(dāng)前位置讀取或?qū)懭霐?shù)據(jù),然后將位置(position)的值按處理元素個(gè)數(shù)增加

絕對(duì)(Absolute):直接根據(jù)索引來(lái)向Buffer中讀取或?qū)懭霐?shù)據(jù),使用絕對(duì)方式來(lái)訪問(wèn)Buffer里的數(shù)據(jù),并不會(huì)影響position的值

import java.nio.*;

public class BufferTest
{
    public static void main(String[] args)
    {
        // 創(chuàng)建Buffer
        CharBuffer buff = CharBuffer.allocate(8);    // ①
        System.out.println("capacity: "    + buff.capacity());
        System.out.println("limit: " + buff.limit());
        System.out.println("position: " + buff.position());
        // 放入元素
        buff.put("a");
        buff.put("b");
        buff.put("c");      // ②
        System.out.println("加入三個(gè)元素后,position = " + buff.position());
        // 調(diào)用flip()方法
        buff.flip();      // ③
        System.out.println("執(zhí)行flip()后,limit = " + buff.limit());
        System.out.println("position = " + buff.position());
        // 取出第一個(gè)元素
        System.out.println("第一個(gè)元素(position=0):" + buff.get());  // ④
        System.out.println("取出一個(gè)元素后,position = " + buff.position());
        // 調(diào)用clear方法
        buff.clear();     // ⑤
        System.out.println("執(zhí)行clear()后,limit = " + buff.limit());
        System.out.println("執(zhí)行clear()后,position = " + buff.position());
        System.out.println("執(zhí)行clear()后,緩沖區(qū)內(nèi)容并沒(méi)有被清除:" + "第三個(gè)元素為:" +  buff.get(2));    // ⑥
        System.out.println("執(zhí)行絕對(duì)讀取后,position = " + buff.position());
    }
}

運(yùn)行結(jié)果:

capacity: 8
limit: 8
position: 0
加入三個(gè)元素后,position = 3
執(zhí)行flip()后,limit = 3
position = 0
第一個(gè)元素(position=0):a
取出一個(gè)元素后,position = 1
執(zhí)行clear()后,limit = 8
執(zhí)行clear()后,position = 0
執(zhí)行clear()后,緩沖區(qū)內(nèi)容并沒(méi)有被清除:第三個(gè)元素為:c
執(zhí)行絕對(duì)讀取后,position = 0

代碼①:新分配的CharBuffer對(duì)象:

代碼②:向Buffer中放入3個(gè)對(duì)象后

代碼③:執(zhí)行Buffer的flip()方法后

代碼⑤:執(zhí)行clear()后的Buffer

使用Channel

Channel類(lèi)似于傳統(tǒng)的流對(duì)象,但與傳統(tǒng)的流對(duì)象有兩個(gè)主要區(qū)別:

Channel可以直接將指定文件的部分或全部直接映射成Buffer

程序不能直接訪問(wèn)Channel中的數(shù)據(jù),包括讀、寫(xiě)入都不行,Channel只能與Buffer進(jìn)行交互。也就是說(shuō),如果要從Channel中取得數(shù)據(jù),必須先用Buffer從Channel中取出一些數(shù)據(jù),然后讓程序從Buffer中取出這些數(shù)據(jù);如果要將程序中的數(shù)據(jù)寫(xiě)入Channel,一樣先讓程序?qū)⒄l(shuí)放入Buffer中,程序再將Buffer里的數(shù)據(jù)寫(xiě)入Channel中

所有的Channel都不應(yīng)該通過(guò)構(gòu)造器來(lái)直接創(chuàng)建,而是通過(guò)傳統(tǒng)的節(jié)點(diǎn)InputStream、OutputStream的getChannel()方法來(lái)返回對(duì)應(yīng)的Channel,不同的節(jié)點(diǎn)流獲得的Channle不一樣

Channel中最常用的三類(lèi)方法是map()、read()和write()

map()方法用于將Channel對(duì)應(yīng)的部分或全部數(shù)據(jù)映射成ByteBuffer;而read()或write()方法都有一系列重載形式,這些方法用于從Buffer中讀取數(shù)據(jù)或向Buffer里寫(xiě)入數(shù)據(jù)

map方法的方法簽名為:MappedByteBuffer map(FileChannel.MapMode mode, long position, long size),第一個(gè)參數(shù)執(zhí)行映射時(shí)的模式,分別有只讀,讀寫(xiě)模式,而第二個(gè),第三個(gè)參數(shù)用于控制將Channel的哪些數(shù)據(jù)映射成ByteBuffer

以下是直接將FileChannel的全部數(shù)據(jù)映射成ByteBuffer的效果的代碼。使用FileInputStream、FileOutputStream來(lái)獲取FileChannel。代碼①直接將指定Channel中的全部數(shù)據(jù)映射成ByteBuffer,代碼②直接將整個(gè)ByteBuffer的全部數(shù)據(jù)寫(xiě)入一個(gè)輸出FileChannel中,完成文件復(fù)制。使用Charset類(lèi)和CharsetDecoder類(lèi)將ByteBuffer轉(zhuǎn)換成CharBuffer

import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;

public class FileChannelTest
{
    public static void main(String[] args)
    {
        File f = new File("FileChannelTest.java");
        try(
            // 創(chuàng)建FileInputStream,以該文件輸入流創(chuàng)建FileChannel
            FileChannel inChannel = new FileInputStream(f).getChannel();
            // 以文件輸出流創(chuàng)建FileBuffer,用以控制輸出
            FileChannel outChannel = new FileOutputStream("a.txt").getChannel())
        {
            // 將FileChannel里的全部數(shù)據(jù)映射成ByteBuffer
            MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, f.length());   // ①
            // 使用GBK的字符集來(lái)創(chuàng)建解碼器
            Charset charset = Charset.forName("GBK");
            // 直接將buffer里的數(shù)據(jù)全部輸出
            outChannel.write(buffer);     // ②
            // 再次調(diào)用buffer的clear()方法,復(fù)原limit、position的位置
            buffer.clear();
            // 創(chuàng)建解碼器(CharsetDecoder)對(duì)象
            CharsetDecoder decoder = charset.newDecoder();
            // 使用解碼器將ByteBuffer轉(zhuǎn)換成CharBuffer
            CharBuffer charBuffer =  decoder.decode(buffer);
            // CharBuffer的toString方法可以獲取對(duì)應(yīng)的字符串
            System.out.println(charBuffer);
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
        }
    }
}

RandomAccessFile中也包含getChannel()方法,返回的FileChannel()讀寫(xiě)類(lèi)型取決于RandomAccessFile打開(kāi)文件的模式。以下代碼將對(duì)a.txt文件的內(nèi)容進(jìn)行復(fù)制,追加到該文件后面:

import java.io.*;
import java.nio.*;
import java.nio.channels.*;

public class RandomFileChannelTest
{
    public static void main(String[] args) throws IOException
    {
        File f = new File("a.txt");
        try(
            // 創(chuàng)建一個(gè)RandomAccessFile對(duì)象
            RandomAccessFile raf = new RandomAccessFile(f, "rw");
            // 獲取RandomAccessFile對(duì)應(yīng)的Channel
            FileChannel randomChannel = raf.getChannel())
        {
            // 將Channel中所有數(shù)據(jù)映射成ByteBuffer
            ByteBuffer buffer = randomChannel.map(FileChannel.MapMode.READ_ONLY, 0, f.length());
            // 把Channel的記錄指針移動(dòng)到最后
            randomChannel.position(f.length());
            // 將buffer中所有數(shù)據(jù)輸出
            randomChannel.write(buffer);
        }
    }
}

randomChannel.position(f.length()); 代碼將Channel的記錄指針移動(dòng)到該Channel的最后,從而可以讓程序?qū)⒅付˙yteBuffer的數(shù)據(jù)追加到該Channel后面。每次運(yùn)行上面程序,都會(huì)把a(bǔ).txt文件的內(nèi)容復(fù)制一份,并將全部?jī)?nèi)容追加到該文件的后面

使用map()方法一次將所有的文件內(nèi)容映射到內(nèi)存中引起性能下降,可以使用Channel和Buffer傳統(tǒng)的“用竹筒多次重復(fù)取水”的方式:

import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;

public class ReadFile
{
    public static void main(String[] args)
        throws IOException
    {
        try(
            // 創(chuàng)建文件輸入流
            FileInputStream fis = new FileInputStream("ReadFile.java");
            // 創(chuàng)建一個(gè)FileChannel
            FileChannel fcin = fis.getChannel())
        {
            // 定義一個(gè)ByteBuffer對(duì)象,用于重復(fù)取水
            ByteBuffer bbuff = ByteBuffer.allocate(256);
            // 將FileChannel中數(shù)據(jù)放入ByteBuffer中
            while( fcin.read(bbuff) != -1 )
            {
                // 鎖定Buffer的空白區(qū)
                bbuff.flip();
                // 創(chuàng)建Charset對(duì)象
                Charset charset = Charset.forName("GBK");
                // 創(chuàng)建解碼器(CharsetDecoder)對(duì)象
                CharsetDecoder decoder = charset.newDecoder();
                // 將ByteBuffer的內(nèi)容轉(zhuǎn)碼
                CharBuffer cbuff = decoder.decode(bbuff);
                System.out.print(cbuff);
                // 將Buffer初始化,為下一次讀取數(shù)據(jù)做準(zhǔn)備
                bbuff.clear();
            }
        }
    }
}

Buffer提供了flip()和clear()兩個(gè)方法,每次讀取數(shù)后調(diào)用flip()方法將沒(méi)有數(shù)據(jù)的區(qū)域“封印”起來(lái),避免程序從Buffer中取出null值;數(shù)據(jù)取出后立即調(diào)用clear()方法將Buffer的position設(shè)0,為下一次讀取數(shù)據(jù)做準(zhǔn)備

字符集和Charset

編碼Encode:把明文的字符序列換成計(jì)算機(jī)理解的二進(jìn)制序列
解碼Decode:把二進(jìn)制序列轉(zhuǎn)換成明文字符串

Java默認(rèn)使用Unicode字符集,但很多操作系統(tǒng)并不使用Unicode字符集,那么當(dāng)從系統(tǒng)中讀取數(shù)據(jù)到Java程序中時(shí),就可能出現(xiàn)亂碼等問(wèn)題

JDK1.4提供了Charset來(lái)處理字節(jié)序列和字符序列(字符串)之間的轉(zhuǎn)換關(guān)系,該類(lèi)包含了用于創(chuàng)建編碼和解碼的的方法,還提供了獲取所有Charset所支持的字符集的方法,Charset類(lèi)是不可變的

availableCharset()的靜態(tài)方法用于獲取當(dāng)前JDK所支持的所有字符集

import java.nio.charset.*;
import java.util.*;

public class CharsetTest
{
    public static void main(String[] args)
    {
        // 獲取Java支持的全部字符集
        SortedMap  map = Charset.availableCharsets();
        for (String alias : map.keySet())
        {
            // 輸出字符集的別名和對(duì)應(yīng)的Charset對(duì)象
            System.out.println(alias + "----->"
                + map.get(alias));
        }
    }
}

常用字符串別名:

GBK:簡(jiǎn)體中文字符串

BIG5:繁體中文字符串

ISO-8859-1:ISO拉丁字母表No.1

UTF-8:8位UCS轉(zhuǎn)換格式

UTF-16BE:16位的UCS轉(zhuǎn)換格式,Big-endian(最低地址存放高位字節(jié))字節(jié)順序

UTF-16LE:16位的UCS轉(zhuǎn)換格式,Little-endian(最高地址存放低位字節(jié))字節(jié)順序

UTF-16:16位的UCS轉(zhuǎn)換格式,字節(jié)順序由可選的字節(jié)順序標(biāo)記來(lái)標(biāo)識(shí)

調(diào)用Charset的forName()方法創(chuàng)建字符串別名對(duì)應(yīng)的Charset對(duì)象,forName()方法的參數(shù)就是相應(yīng)字符集的別名:
Charset cs = Charset.forName("ISO-8859-1");

獲得Charset對(duì)象之后,通過(guò)該對(duì)象的newDecoder()、newEncoder()方法分別返回CharsetDecoder和CharsetEncoder對(duì)象,代表該Charset的解碼器和編碼器。調(diào)用CharsetDecoder的decode()方法可以將ByteBuffer(字節(jié)序列)轉(zhuǎn)換成CharBuffer(字符序列),調(diào)用CharsetEncoder的encode()方法可以將CharBuffer或String(字符序列)轉(zhuǎn)換成ByteBuffer(字節(jié)序列)

import java.nio.*;
import java.nio.charset.*;

public class CharsetTransform
{
    public static void main(String[] args)
        throws Exception
    {
        // 創(chuàng)建簡(jiǎn)體中文對(duì)應(yīng)的Charset
        Charset cn = Charset.forName("GBK");
        // 獲取cn對(duì)象對(duì)應(yīng)的編碼器和解碼器
        CharsetEncoder cnEncoder = cn.newEncoder();
        CharsetDecoder cnDecoder = cn.newDecoder();
        // 創(chuàng)建一個(gè)CharBuffer對(duì)象
        CharBuffer cbuff = CharBuffer.allocate(8);
        cbuff.put("內(nèi)");
        cbuff.put("馬");
        cbuff.put("爾");
        cbuff.flip();
        // 將CharBuffer中的字符序列轉(zhuǎn)換成字節(jié)序列
        ByteBuffer bbuff = cnEncoder.encode(cbuff);
        // 循環(huán)訪問(wèn)ByteBuffer中的每個(gè)字節(jié)
        for (int i = 0; i < bbuff.capacity() ; i++)
        {
            System.out.print(bbuff.get(i) + " ");
        }
        // 將ByteBuffer的數(shù)據(jù)解碼成字符序列
        System.out.println("
" + cnDecoder.decode(bbuff));
    }
}

Charset類(lèi)提供了如下三個(gè)方法:

CharBuffer decode(ByteBuffer bb):將ByteBuffer中的字節(jié)序列轉(zhuǎn)換成字符序列的便捷方法

ByteBuffer encode(CharBuffer cb):將CharBuffer中的字節(jié)序列轉(zhuǎn)換成字符序列的便捷方法

ByteBuffer encode(String str):將String中的字節(jié)序列轉(zhuǎn)換成字符序列的便捷方法

獲取Charset對(duì)象后,如果僅僅需要進(jìn)行簡(jiǎn)單的編碼、解碼操作,實(shí)則無(wú)須創(chuàng)建CharsetDecoder和CharsetEncoder對(duì)象,直接調(diào)用Charset的encode()和decode()方法進(jìn)行編碼、解碼即可

文件鎖

如果多個(gè)運(yùn)行的程序需要并發(fā)修改同一個(gè)文件時(shí),程序之間需要某種機(jī)制來(lái)進(jìn)行通信,使用文件鎖可以有效阻止多個(gè)進(jìn)程并發(fā)修改同一個(gè)文件

Java提供了FileLock類(lèi)支持文件鎖功能,在FileChannel中提供的lock()/tryLock()方法可以獲得文件鎖FileLock對(duì)象,從而鎖定文件

lock()方法和trylock()方法的區(qū)別是:當(dāng)lock()試圖鎖定某個(gè)文件時(shí),如果無(wú)法得到文件鎖,程序?qū)⒁恢弊枞?,而tryLock()方法時(shí)嘗試鎖定文件,它將直接返回而不是阻塞,如果獲得了文件鎖,該方法則返回該文件鎖,否則將返回null

lock(long position, long size, boolean shared):對(duì)文件從position開(kāi)始,長(zhǎng)度為size的內(nèi)容加鎖,該方法是阻塞式的

tryLock(long position, long size, boolean shared):非阻塞式的加鎖方法

當(dāng)shared為true時(shí),表明該鎖是一個(gè)共享鎖,它將允許多個(gè)進(jìn)程來(lái)讀取文件,但不允許其他進(jìn)程將其設(shè)為排他鎖;當(dāng)shared為false的時(shí),表明這是一個(gè)排他鎖,它將鎖住對(duì)該文件的讀寫(xiě)

通過(guò)調(diào)用FileLock的isShared來(lái)判斷獲得的鎖是否為共享鎖

直接使用lock()或tryLock()方法獲取的文件鎖是排他鎖

處理完成之后,調(diào)用FileLock的release()方法釋放文件鎖

import java.io.*;
import java.nio.*;
import java.nio.channels.*;

public class FileLockTest
{
    public static void main(String[] args)
        throws Exception
    {

        try(
            // 使用FileOutputStream獲取FileChannel
            FileChannel channel = new FileOutputStream("a.txt").getChannel())
        {
            // 使用非阻塞式方式對(duì)指定文件加鎖
            FileLock lock = channel.tryLock();
            // 程序暫停10s
            Thread.sleep(10000);
            // 釋放鎖
            lock.release();
        }
    }
}
Java7的NIO2

NIO的改進(jìn)主要包括如下方面:

提供了全面的文件IO和文件系統(tǒng)訪問(wèn)支持

基于異步Channel的IO

Path、Paths和File核心API

Paths提供了get(String first, String... more)方法來(lái)獲取Path對(duì)象,Paths會(huì)將給定的多個(gè)字符串連綴成路徑,如Paths.get("D:", "java","code")將返回D:javacode路徑;getNameCount()返回Path路徑所包含的路徑名

import java.io.*;
import java.net.*;
import java.nio.file.*;

public class PathTest
{
    public static void main(String[] args)
        throws Exception
    {
        // 以當(dāng)前路徑來(lái)創(chuàng)建Path對(duì)象
        Path path = Paths.get(".");
        System.out.println("path里包含的路徑數(shù)量:" + path.getNameCount());
        System.out.println("path的根路徑:" + path.getRoot());
        // 獲取path對(duì)應(yīng)的絕對(duì)路徑
        Path absolutePath = path.toAbsolutePath();
        System.out.println(absolutePath);
        // 獲取絕對(duì)路徑的根路徑
        System.out.println("absolutePath的根路徑:" + absolutePath.getRoot());
        // 獲取絕對(duì)路徑所包含的路徑數(shù)量
        System.out.println("absolutePath里包含的路徑數(shù)量:" + absolutePath.getNameCount());
        System.out.println(absolutePath.getName(3));
        // 以多個(gè)String來(lái)構(gòu)建Path對(duì)象
        Path path2 = Paths.get("D:", "java","code");
        System.out.println(path2);
    }
}

運(yùn)行結(jié)果:

path里包含的路徑數(shù)量:1
path的根路徑:null
D:DevelopmenteclipseworkspaceCrazyJava.
absolutePath的根路徑:D:
absolutePath里包含的路徑數(shù)量:5
CrazyJava
D:javacode

以下代碼示范Files工具類(lèi)的用法:

import java.nio.file.*;
import java.nio.charset.*;
import java.io.*;
import java.util.*;

public class FilesTest
{
    public static void main(String[] args)
        throws Exception
    {
        // 復(fù)制文件
        Files.copy(Paths.get("FilesTest.java"), new FileOutputStream("a.txt"));
        // 判斷FilesTest.java文件是否為隱藏文件
        System.out.println("FilesTest.java是否為隱藏文件:"+ Files.isHidden(Paths.get("FilesTest.java")));
        // 一次性讀取FilesTest.java文件的所有行
        List lines = Files.readAllLines(Paths.get("FilesTest.java"), Charset.forName("gbk"));
        System.out.println(lines);
        // 判斷指定文件的大小
        System.out.println("FilesTest.java的大小為:" + Files.size(Paths.get("FilesTest.java")));
        List poem = new ArrayList<>();
        poem.add("感時(shí)花濺淚");
        poem.add("恨別鳥(niǎo)驚心");
        // 直接將多個(gè)字符串內(nèi)容寫(xiě)入指定文件中
        Files.write(Paths.get("pome.txt"), poem, Charset.forName("gbk"));
        // 使用Java 8新增的Stream API列出當(dāng)前目錄下所有文件和子目錄
        Files.list(Paths.get(".")).forEach(path -> System.out.println(path));
        // 使用Java 8新增的Stream API讀取文件內(nèi)容
        Files.lines(Paths.get("FilesTest.java"), Charset.forName("gbk")).forEach(line -> System.out.println(line));
        FileStore cStore = Files.getFileStore(Paths.get("C:"));
        // 判斷C盤(pán)的總空間,可用空間
        System.out.println("C:共有空間:" + cStore.getTotalSpace());
        System.out.println("C:可用空間:" + cStore.getUsableSpace());
    }
}
使用FileVisitor遍歷文件和目錄

Files類(lèi)提供了兩個(gè)方法來(lái)遍歷文件和子目錄

walkFileTree(Path start, FileVisitor visitor):遍歷start路徑下的所有文件和子目錄

walkFileTree(Path start, Set options, int maxDepth, FileVisitor visitor):遍歷start路徑下的所有文件和子目錄,最多遍歷maxDepth深度的文件

FileVisitor代表一個(gè)文件訪問(wèn)器,walkFileTree()方法會(huì)自動(dòng)遍歷start路徑下的所有文件和子目錄,遍歷文件和子目錄都會(huì)觸發(fā)FileVisitor中相應(yīng)的方法。這四個(gè)方法在下面的代碼中出現(xiàn)。FileVisitor中定義了如下4個(gè)方法:

FileVisitResult postVisitDirectory(T dir, IOException exc):訪問(wèn)子目錄之后觸發(fā)該方法

FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs):訪問(wèn)子目錄之前觸發(fā)該方法

FileVisitResult visitFile(T file, BasicFileAttributes attrs):訪問(wèn)file文件時(shí)觸發(fā)該方法

FileVisitResult visitFileFailed(T file, IOException exc):訪問(wèn)file文件失敗時(shí)觸發(fā)該方法

FileVisitResult對(duì)象,它是一個(gè)枚舉類(lèi),代表訪問(wèn)之后的后續(xù)行為,它有如下幾種后續(xù)行為:

CONTINUE:代表“繼續(xù)訪問(wèn)”的后續(xù)行為

TERMINATE:代表“終止訪問(wèn)”的后續(xù)行為

SKIP_SUBTREE:代表“繼續(xù)訪問(wèn)“,但不訪問(wèn)該目錄文件或目錄的子目錄樹(shù)

SKIP_SIBLINGS:代表“繼續(xù)訪問(wèn)”,但不訪問(wèn)該文件或目錄的兄弟文件或目錄

以下程序使用Files工具類(lèi)的walkFileTree()方法遍歷g:publishcodes15目錄下的所有文件和子目錄,直到找到的文件以“FileVisitorTest.java”結(jié)尾,則程序停止遍歷。實(shí)現(xiàn)了對(duì)指定目錄進(jìn)行搜索,直到找到指定文件為止

import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;

public class FileVisitorTest
{
    public static void main(String[] args)
        throws Exception
    {
        // 遍歷D:codingJava路徑CrazyJavacodes15目錄下的所有文件和子目錄
        Files.walkFileTree(Paths.get("D:", "coding", "Java路徑", "CrazyJava", "codes", "15"), 
        new SimpleFileVisitor()
        {
            // 訪問(wèn)文件時(shí)候觸發(fā)該方法
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException
            {
                System.out.println("正在訪問(wèn)" + file + "文件");
                // 找到了FileVisitorTest.java文件
                if (file.endsWith("FileVisitorTest.java"))
                {
                    System.out.println("--已經(jīng)找到目標(biāo)文件--");
                    return FileVisitResult.TERMINATE;
                }
                return FileVisitResult.CONTINUE;
            }
            // 開(kāi)始訪問(wèn)目錄時(shí)觸發(fā)該方法
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException
            {
                System.out.println("正在訪問(wèn):" + dir + " 路徑");
                return FileVisitResult.CONTINUE;
            }
        });
    }
}
使用WatchService監(jiān)控文件變化

register(WatchService watcher, WatchEvent.Kind ... events):用watcher監(jiān)聽(tīng)該path代表的目錄下文件變化。events參數(shù)指定要監(jiān)聽(tīng)哪些類(lèi)型的事件

WatchService代表一個(gè)文件系統(tǒng)監(jiān)聽(tīng)服務(wù),它負(fù)責(zé)監(jiān)聽(tīng)path代表的目錄下的文件變化。一旦使用register()方法完成注冊(cè)之后,可調(diào)用WatchService如下的三個(gè)方法來(lái)監(jiān)聽(tīng)目錄的文件變化事件

WatchKey poll():獲取下一個(gè)WatchKey,如果沒(méi)有WatchKey發(fā)生就立即返回null

WatcheKey poll(long timeout, TimeUnit unit):嘗試等待timeout時(shí)間去獲取下一個(gè)WatchKey

WatchKey take():獲取下一個(gè)WatchKey,如果沒(méi)有WatchKey發(fā)生就一直等待

如果程序需要一直監(jiān)控,則應(yīng)該選擇使用take()方法,如果程序只需要監(jiān)控指定時(shí)間,則使用poll方法

import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;

public class WatchServiceTest
{
    public static void main(String[] args) throws Exception
    {
        // 獲取文件系統(tǒng)的WatchService對(duì)象
        WatchService watchService = FileSystems.getDefault().newWatchService();
        // 為C:盤(pán)根路徑注冊(cè)監(jiān)聽(tīng)
        Paths.get("C:/").register(watchService
            , StandardWatchEventKinds.ENTRY_CREATE
            , StandardWatchEventKinds.ENTRY_MODIFY
            , StandardWatchEventKinds.ENTRY_DELETE);
        while(true)
        {
            // 獲取下一個(gè)文件改動(dòng)事件
            WatchKey key = watchService.take();    //①
            for (WatchEvent event : key.pollEvents())
            {
                System.out.println(event.context() +" 文件發(fā)生了 "
                    + event.kind()+ "事件!");
            }
            // 重設(shè)WatchKey
            boolean valid = key.reset();
            // 如果重設(shè)失敗,退出監(jiān)聽(tīng)
            if (!valid)
            {
                break;
            }
        }
    }
}
訪問(wèn)文件屬性

Java7的NIO.2在java.nio.file.attribute包下提供了大量工具類(lèi),可以簡(jiǎn)單地讀取、修改文件屬性。分為如下兩類(lèi):

XxxAttributeView:代表某種文件屬性的“視圖”

XxxAttributes:代表某種文件屬性的“集合”,程序一般通過(guò)XxxAttributeView對(duì)象獲取XxxAttributes

FileAttributeView是其他XxxAttributeView的父接口

AclFileAttributeView: 為特定文件設(shè)置ACL(Access Control List)及文件所有者屬性。getAcl()方法返回List對(duì)象,該返回值代表該文件的權(quán)限集,setAcl(List)方法修改該文件的ACL

BaseFileAttributeView:獲取或修改文件的基本屬性。readAttributes()方法返回一個(gè)BaseFileAttributeView對(duì)象,對(duì)文件夾基本屬性的修改是通過(guò)BaseFileAttributeView對(duì)象完成的

DosFileAttributeView:獲取或修改文件DOS相關(guān)屬性。readAttributes()方法返回一個(gè)DosFileAttributeView對(duì)象,對(duì)文件夾屬性的修改通過(guò)DosFileAttributeView對(duì)象完成的

FileOwnerAttributeView:獲取或修改文件的所有者。getOwner()方法返回一個(gè)UserPrincipal對(duì)象來(lái)代表文件所有者;也可調(diào)用setOwner(UserPrincipal owner)方法來(lái)改變文件的所有者

PosixFileAttributeView:獲取文件或修改POSIX(Portable Operating System Interface of INIX)屬性。readAttributes()方法返回一個(gè)PosixFileAttributeView對(duì)象,該對(duì)象用于獲取或修改文件的所有者、組所有者、訪問(wèn)權(quán)限信息。僅在UNIX、Linux等系統(tǒng)上有用

UserDefinedFileAttributeView:開(kāi)發(fā)者自定義文件屬性

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/66608.html

相關(guān)文章

  • Java NIO 系列教程

    摘要:異步可以讓你異步的使用,例如當(dāng)線程從通道讀取數(shù)據(jù)到緩沖區(qū)時(shí),線程還是可以進(jìn)行其他事情。當(dāng)數(shù)據(jù)被寫(xiě)入到緩沖區(qū)時(shí),線程可以繼續(xù)處理它。因此,單個(gè)的線程可以監(jiān)聽(tīng)多個(gè)數(shù)據(jù)通道。下面是系列文章的目錄概述通道之間的數(shù)據(jù)傳輸與原文譯者郭蕾校對(duì)方騰飛 Java NIO(New IO)是一個(gè)可以替代標(biāo)準(zhǔn)Java IO API的IO API(從Java 1.4開(kāi)始),Java NIO提供了與標(biāo)準(zhǔn)IO不同的...

    fanux 評(píng)論0 收藏0
  • Java NIO 概覽

    摘要:線程之間的切換對(duì)于操作系統(tǒng)來(lái)說(shuō)是昂貴的。因此,單線程可以監(jiān)視多個(gè)通道中的數(shù)據(jù)。當(dāng)方法返回后,線程可以處理這些事件。 一 NIO簡(jiǎn)介 Java NIO 是 java 1.4 之后新出的一套IO接口,這里的的新是相對(duì)于原有標(biāo)準(zhǔn)的Java IO和Java Networking接口。NIO提供了一種完全不同的操作方式。 NIO中的N可以理解為Non-blocking,不單純是New。 它支持面...

    chemzqm 評(píng)論0 收藏0
  • 關(guān)于Java IO與NIO知識(shí)都在這里

    摘要:從通道進(jìn)行數(shù)據(jù)寫(xiě)入創(chuàng)建一個(gè)緩沖區(qū),填充數(shù)據(jù),并要求通道寫(xiě)入數(shù)據(jù)。三之通道主要內(nèi)容通道介紹通常來(lái)說(shuō)中的所有都是從通道開(kāi)始的。從中選擇選擇器維護(hù)注冊(cè)過(guò)的通道的集合,并且這種注冊(cè)關(guān)系都被封裝在當(dāng)中停止選擇的方法方法和方法。 由于內(nèi)容比較多,我下面放的一部分是我更新在我的微信公眾號(hào)上的鏈接,微信排版比較好看,更加利于閱讀。每一篇文章下面我都把文章的主要內(nèi)容給列出來(lái)了,便于大家學(xué)習(xí)與回顧。 Ja...

    Riddler 評(píng)論0 收藏0
  • Java NIO 的前生今世 之一 簡(jiǎn)介

    摘要:簡(jiǎn)介是由引進(jìn)的異步由以下幾個(gè)核心部分組成和的對(duì)比和的區(qū)別主要體現(xiàn)在三個(gè)方面基于流而基于操作是阻塞的而操作是非阻塞的沒(méi)有概念而有概念基于與基于傳統(tǒng)的是面向字節(jié)流或字符流的而在中我們拋棄了傳統(tǒng)的流而是引入了和的概念在中我只能從中讀取數(shù)據(jù)到中或?qū)? 簡(jiǎn)介 Java NIO 是由 Java 1.4 引進(jìn)的異步 IO.Java NIO 由以下幾個(gè)核心部分組成: Channel Buffer Se...

    李義 評(píng)論0 收藏0
  • 動(dòng)力節(jié)點(diǎn)JavaNIO教程,輕松攻破Java NIO技術(shù)壁壘

    摘要:學(xué)習(xí)和掌握技術(shù)已經(jīng)不是一個(gè)攻城獅的加分技能,而是一個(gè)必備技能。是雙向的,不僅可以讀取數(shù)據(jù)還能保存數(shù)據(jù),程序不能直接讀寫(xiě)通道,只與緩沖區(qū)交互為了讓大家不被高并發(fā)與大量連接處理問(wèn)題所困擾,動(dòng)力節(jié)點(diǎn)推出了高效處理模型應(yīng)用教程。 大家肯定了解Java IO, 但是對(duì)于NIO一般是陌生的,而現(xiàn)在使用到NIO的場(chǎng)景越來(lái)越多,很多技術(shù)框...

    ralap 評(píng)論0 收藏0
  • Netty序章之BIO NIO AIO演變

    摘要:后改良為用線程池的方式代替新增線程,被稱(chēng)為偽異步。最大的問(wèn)題是阻塞,同步。每次請(qǐng)求都由程序執(zhí)行并返回,這是同步的缺陷。這些都會(huì)被注冊(cè)在多路復(fù)用器上。多路復(fù)用器提供選擇已經(jīng)就緒狀態(tài)任務(wù)的能力。并沒(méi)有采用的多路復(fù)用器,而是使用異步通道的概念。 Netty是一個(gè)提供異步事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用框架,用以快速開(kāi)發(fā)高性能、高可靠的網(wǎng)絡(luò)服務(wù)器和客戶端程序。Netty簡(jiǎn)化了網(wǎng)絡(luò)程序的開(kāi)發(fā),是很多框架和公司...

    VincentFF 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<