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

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

零、本文綱要

一、Channel

  1. FileChannel
  2. FileChannel傳輸

二、補(bǔ)充:Path & Paths & Files 類

  1. Path & Paths
  2. Files
  3. Files 類的 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 類

1. Path & Paths

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

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 類的 walkFileTree方法 & walk方法

① 遍歷目錄文件

此處我們重寫(xiě) SimpleFileVisitor 內(nè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ì)指定文件類型的數(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類

屬性Spring框架的話這部分是不是非常熟悉類似,此處不展開(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閱讀 227,572評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,071評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,409評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,569評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,360評(píng)論 6 404
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,895評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,979評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,123評(píng)論 0 286
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,643評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,559評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,742評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,250評(píng)論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,981評(píng)論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,363評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,622評(píng)論 1 280
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,354評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,707評(píng)論 2 370

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