Netty基礎(chǔ)-NIO(二)

前置文章:
Netty基礎(chǔ)-NIO(一)棚唆,該文主要引入NIO三大組件,介紹了Buffer結(jié)構(gòu)冗栗,及Buffer具體使用演顾。

零、本文綱要

一隅居、Channel

  1. FileChannel
  2. FileChannel傳輸

二钠至、補(bǔ)充:Path & Paths & Files 類(lèi)

  1. Path & Paths
  2. Files
  3. Files 類(lèi)的 walkFileTree方法 & walk方法

一、Channel

1. FileChannel

注意:FileChannel 只能工作在阻塞模式下

① 獲取方式

FileInputStream → 只讀胎源;
FileOutputStream → 只寫(xiě)棉钧;
RandomAccessFile → 讀寫(xiě);

FileChannel readChannel = new FileInputStream("src/main/resources/data.txt").getChannel();
FileChannel writeChannel = new FileOutputStream("src/main/resources/data_back.txt").getChannel();
final RandomAccessFile rwChannel = new RandomAccessFile("src/main/resources/data.txt", "rw");

② read方法

讀數(shù)據(jù)到buffer涕蚤,返回值表示讀到了多少字節(jié)宪卿,0 / -1 表示到達(dá)了文件的末尾。

ByteBuffer buffer = ByteBuffer.allocate(16);
FileChannel readChannel = new FileInputStream("src/main/resources/data.txt").getChannel();
// TODO 只讀Channel中讀取數(shù)據(jù)万栅,填充至Buffer
int read = readChannel.read(buffer);
log.debug("當(dāng)前讀取了:{}字節(jié)內(nèi)容愧捕。", read);
debugAll(buffer);
readChannel.close();

注意:此處官方一般用 -1 來(lái)做讀完數(shù)據(jù)的標(biāo)志。

③ channel#write方法 & buffer#hasRemaining方法

FileChannel writeChannel = new FileOutputStream("src/main/resources/data_back.txt").getChannel();
while (buffer.hasRemaining()) {
    writeChannel.write(buffer);
}
writeChannel.close();

④ close方法

因?yàn)樯婕暗劫Y源流處理申钩,使用完關(guān)閉資源是良好的習(xí)慣。

⑤ position方法

該方法用于獲取position指針的當(dāng)前位置

log.debug("buffer position is: {}", buffer.position());
log.debug("channel position is: {}", writeChannel.position());
buffer position is: 11
channel position is: 11

⑥ size方法

該方法獲取能文件的大小

⑦ force方法

操作系統(tǒng)出于性能的考慮瘪阁,會(huì)將數(shù)據(jù)緩存撒遣,不是立刻寫(xiě)入磁盤(pán)。
可以調(diào)用 force(true) 方法將文件內(nèi)容和元數(shù)據(jù)(文件的權(quán)限等信息)立刻寫(xiě)入磁盤(pán)管跺。

2. FileChannel傳輸

① 傳統(tǒng)的方式

readChannel 從文件讀取數(shù)據(jù)至 buffer 义黎,而后從 buffer 取數(shù)據(jù)通過(guò) writeChannel 寫(xiě)數(shù)據(jù)至文件

ByteBuffer buffer = ByteBuffer.allocate(16);
FileChannel readChannel = new FileInputStream("src/main/resources/data.txt").getChannel();
int read = readChannel.read(buffer);
log.debug("當(dāng)前讀取了:{}字節(jié)內(nèi)容。", read);
debugAll(buffer);
readChannel.close();

buffer.flip(); //注意:要手動(dòng)將position重置為0

FileChannel writeChannel = new FileOutputStream("src/main/resources/data_back.txt").getChannel();
while (buffer.hasRemaining()) {
    writeChannel.force(true);
    writeChannel.write(buffer);
    log.debug("buffer position is: {}", buffer.position());
    log.debug("channel position is: {}", writeChannel.position());
}
writeChannel.close();

② transferTo方法

final String IN_FILE = "src/main/resources/data.txt";
final String OUT_FILE = "src/main/resources/data_back.txt";
try (
    FileChannel readChannel = new FileInputStream(IN_FILE).getChannel();
    FileChannel writeChannel = new FileOutputStream(OUT_FILE).getChannel();
) {
    readChannel.transferTo(0, readChannel.size(), writeChannel);
} catch (IOException e) {
    log.debug(e.getMessage());
}

二豁跑、補(bǔ)充:Path & Paths & Files 類(lèi)

1. Path & Paths

Path:用來(lái)表示文件路徑
Paths:用于獲取Path的工具類(lèi)

String URI = "src/main/resources/data.txt";
String URL = "D:\\JavaStudy\\Level1\\netty-nio\\src\\main\\resources\\data.txt";
Path sourceOne = Paths.get(URI);
Path sourceTwo = Paths.get(URL);

2. Files

① exists方法

用于判斷文件是否存在廉涕。

log.debug("Is file exists? {}", Files.exists(sourceOne));

② createDirectory方法 & createDirectories方法

用于創(chuàng)建目錄/多級(jí)目錄的方法。

createDirectory方法
a艇拍、如果目錄已存在狐蜕,會(huì)拋異常 FileAlreadyExistsException;
b卸夕、不能一次創(chuàng)建多級(jí)目錄层释,否則會(huì)拋異常 NoSuchFileException。
c快集、createDirectories方法可以創(chuàng)建多級(jí)目錄贡羔。

③ copy方法

用于拷貝文件的方法廉白。

Path source = Paths.get("stone/source.txt");
Path backup = Paths.get("stone/backup.txt");

Files.copy(source, backup);

注意:如果文件已存在,會(huì)拋異常 FileAlreadyExistsException乖寒。

StandardCopyOption可以用于控制copy文件的形式猴蹂,REPLACE_EXISTING用于覆蓋已存在的backup文件,如下:

Files.copy(source, backup, StandardCopyOption.REPLACE_EXISTING);

④ move方法

用于移動(dòng)文件楣嘁,StandardCopyOption.ATOMIC_MOVE 保證文件移動(dòng)的原子性磅轻,如下:

Files.move(source, backup, StandardCopyOption.ATOMIC_MOVE);

⑤ delete方法

用于刪除目錄的方法。

Path target = Paths.get("stone/directory");

Files.delete(target);

注意:如果目錄還有內(nèi)容马澈,會(huì)拋異常 DirectoryNotEmptyException瓢省。

3. Files 類(lèi)的 walkFileTree方法 & walk方法

① 遍歷目錄文件

此處我們重寫(xiě) SimpleFileVisitor 內(nèi)部類(lèi)的 preVisitDirectory、visitFile 方法

final String JAVA_PATH = "C:\\Program Files\\Java\\jdk1.8.0_311";
Path path = Paths.get(JAVA_PATH);
AtomicInteger dirCount = new AtomicInteger();
AtomicInteger fileCount = new AtomicInteger();
Files.walkFileTree(path, new SimpleFileVisitor<Path>(){
    @Override
    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
            throws IOException {
        log.debug(dir.getFileName().toString());
        dirCount.incrementAndGet();
        return super.preVisitDirectory(dir, attrs);
    }

    @Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
            throws IOException {
        log.debug(file.getFileName().toString());
        fileCount.incrementAndGet();
        return super.visitFile(file, attrs);
    }
});
log.debug("directory count is: {}.", dirCount);
log.debug("file count is: {}.", fileCount);

② 統(tǒng)計(jì)指定文件類(lèi)型的數(shù)目

比如統(tǒng)計(jì) .jar包 的數(shù)量

final String JAVA_PATH = "C:\\Program Files\\Java\\jdk1.8.0_311";
Path path = Paths.get(JAVA_PATH);
AtomicInteger fileCount = new AtomicInteger();
Files.walkFileTree(path, new SimpleFileVisitor<Path>(){
    @Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
            throws IOException {
        String fileName = file.getFileName().toString();
        if (fileName.endsWith(".jar")) {
            log.debug("{}", fileName);
            fileCount.incrementAndGet();
        }
        return super.visitFile(file, attrs);
    }
});
log.debug("file count is: {}.", fileCount);

③ 刪除多級(jí)目錄

注意:謹(jǐn)慎操作

final String DELETE_PATH = "D:\\use-to-delete";
Path path = Paths.get(DELETE_PATH);
AtomicInteger dirCount = new AtomicInteger();
AtomicInteger fileCount = new AtomicInteger();
Files.walkFileTree(path, new SimpleFileVisitor<Path>(){
    @Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
        fileCount.incrementAndGet();
        Files.delete(file);
        return super.visitFile(file, attrs);
    }

    @Override
    public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
        dirCount.incrementAndGet();
        Files.delete(dir);
        return super.postVisitDirectory(dir, exc);
    }
});
log.debug("The deleted file count is: {}.", fileCount);
log.debug("The deleted directories count is: {}.", dirCount);

④ 拷貝多級(jí)目錄

final String SOURCE = "D:\\logs";
final String BACKUP = "D:\\logs-backup";
Files.walk(Paths.get(SOURCE)).forEach( path -> {
    try {
        String backupName = path.toString().replace(SOURCE, BACKUP);
        if (Files.isDirectory(path)) {
            Files.createDirectory(Paths.get(backupName));
        }
        else if (Files.isRegularFile(path)) {
            Files.copy(path, Paths.get(backupName));
        }
    } catch (IOException e) {
        log.debug(e.getMessage());
    }
});

⑤ 補(bǔ)充:SimpleFileVisitor類(lèi)

屬性Spring框架的話這部分是不是非常熟悉類(lèi)似痊班,此處不展開(kāi)勤婚。

a、preVisitDirectory:訪問(wèn)目錄前涤伐;
b馒胆、visitFile:訪問(wèn)文件;
c凝果、visitFileFailed:訪問(wèn)不可訪問(wèn)的文件(無(wú)權(quán)限)祝迂;
d、postVisitDirectory:訪問(wèn)目錄后器净。

public class SimpleFileVisitor<T> implements FileVisitor<T> {

    protected SimpleFileVisitor() {
    }

    @Override
    public FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)
        throws IOException
    {
        Objects.requireNonNull(dir);
        Objects.requireNonNull(attrs);
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult visitFile(T file, BasicFileAttributes attrs)
        throws IOException
    {
        Objects.requireNonNull(file);
        Objects.requireNonNull(attrs);
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult visitFileFailed(T file, IOException exc)
        throws IOException
    {
        Objects.requireNonNull(file);
        throw exc;
    }

    @Override
    public FileVisitResult postVisitDirectory(T dir, IOException exc)
        throws IOException
    {
        Objects.requireNonNull(dir);
        if (exc != null)
            throw exc;
        return FileVisitResult.CONTINUE;
    }
}

三型雳、結(jié)尾

以上即為Netty基礎(chǔ)-NIO(二)的全部?jī)?nèi)容,感謝閱讀山害。

注意:該文集系列鋪墊的內(nèi)容會(huì)稍微有些多纠俭。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市浪慌,隨后出現(xiàn)的幾起案子冤荆,更是在濱河造成了極大的恐慌,老刑警劉巖权纤,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钓简,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡汹想,警方通過(guò)查閱死者的電腦和手機(jī)外邓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)古掏,“玉大人坐榆,你說(shuō)我怎么就攤上這事∪呷祝” “怎么了席镀?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵匹中,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我豪诲,道長(zhǎng)顶捷,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任屎篱,我火速辦了婚禮服赎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘交播。我一直安慰自己重虑,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布秦士。 她就那樣靜靜地躺著缺厉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪隧土。 梳的紋絲不亂的頭發(fā)上提针,一...
    開(kāi)封第一講書(shū)人閱讀 51,208評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音曹傀,去河邊找鬼辐脖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛皆愉,可吹牛的內(nèi)容都是我干的嗜价。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼幕庐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼久锥!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起翔脱,我...
    開(kāi)封第一講書(shū)人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎媒鼓,沒(méi)想到半個(gè)月后届吁,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绿鸣,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年疚沐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片潮模。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡亮蛔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出擎厢,到底是詐尸還是另有隱情究流,我是刑警寧澤辣吃,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站芬探,受9級(jí)特大地震影響神得,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜偷仿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一哩簿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧酝静,春花似錦节榜、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至亿遂,卻和暖如春浓若,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蛇数。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工挪钓, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人耳舅。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓碌上,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親浦徊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子馏予,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容