小師妹學JavaIO之:File copy和File filter

簡介

一個linux命令的事情,小師妹非要讓我教她怎麼用java來實現,哎,攤上個這麼槓精的小師妹,我也是深感無力,做一個師兄真的好難。
在這裏插入圖片描述

使用java拷貝文件

今天小師妹找到我了:F師兄,能告訴怎麼拷貝文件嗎?

拷貝文件?不是很簡單的事情嗎?如果你有了文件的讀權限,只需要這樣就可以了。

cp www.flydean.com www.flydean.com.back

當然,如果是目錄的話還可以加兩個參數遍歷和強制拷貝:

cp -rf srcDir distDir

這麼簡單的linux命令,不要告訴我你不會。

小師妹笑了:F師兄,我不要用linux命令,我就想用java來實現,我不正在學java嗎?學一門當然要找準機會來練習啦,快快教教我吧。

既然這樣,那我就開講了。java中文件的拷貝其實也有三種方法,可以使用傳統的文件讀寫的方法,也可以使用最新的NIO中提供的拷貝方法。

使用傳統方法當然沒有NIO快,也沒有NIO簡潔,我們先來看看怎麼使用傳統的文件讀寫的方法來拷貝文件:

    public  void copyWithFileStreams() throws IOException
    {
        File fileToCopy = new File("src/main/resources/www.flydean.com");
        File newFile = new File("src/main/resources/www.flydean.com.back");
        newFile.createNewFile();
        try(FileOutputStream output = new FileOutputStream(newFile);FileInputStream input = new FileInputStream(fileToCopy)){
            byte[] buf = new byte[1024];
            int bytesRead;
            while ((bytesRead = input.read(buf)) > 0)
            {
                output.write(buf, 0, bytesRead);
            }
        }
    }

上面的例子中,我們首先定義了兩個文件,然後從兩個文件中生成了OutputStream和InputStream,最後以字節流的形式從input中讀出數據到outputStream中,最終完成了文件的拷貝。

傳統的File IO拷貝比較繁瑣,速度也比較慢。我們接下來看看怎麼使用NIO來完成這個過程:

public  void copyWithNIOChannel() throws IOException
    {
        File fileToCopy = new File("src/main/resources/www.flydean.com");
        File newFile = new File("src/main/resources/www.flydean.com.back");

        try(FileInputStream inputStream = new FileInputStream(fileToCopy);FileOutputStream outputStream = new FileOutputStream(newFile)){
            FileChannel inChannel = inputStream.getChannel();
            FileChannel outChannel = outputStream.getChannel();
            inChannel.transferTo(0, fileToCopy.length(), outChannel);
        }
    }

之前我們講到NIO中一個非常重要的概念就是channel,通過構建源文件和目標文件的channel通道,可以直接在channel層面進行拷貝,如上面的例子所示,我們調用了inChannel.transferTo完成了拷貝。

最後,還有一個更簡單的NIO文件拷貝的方法:

public  void copyWithNIOFiles() throws IOException
    {
        Path source = Paths.get("src/main/resources/www.flydean.com");
        Path destination = Paths.get("src/main/resources/www.flydean.com.back");
        Files.copy(source, destination, StandardCopyOption.REPLACE_EXISTING);
    }

直接使用工具類Files提供的copy方法即可。

使用File filter

太棒了,小師妹一臉崇拜:F師兄,我還有一個需求,就是想刪除某個目錄裏面的以.log結尾的日誌文件,這個需求是不是很常見?F師兄一般是怎麼操作的?

一般這種操作我都是一個linux命令就搞定了,如果搞不定那就用兩個:

rm -rf *.log

當然,如果需要,我們也是可以用java來實現的。

java中提供了兩個Filter都可以用來實現這個功能。

這兩個Filter是java.io.FilenameFilter和java.io.FileFilter:

@FunctionalInterface
public interface FilenameFilter {
    boolean accept(File dir, String name);
}
@FunctionalInterface
public interface FileFilter {
    boolean accept(File pathname);
}

這兩個接口都是函數式接口,所以他們的實現可以直接用lambda表達式來代替。

兩者的區別在於,FilenameFilter進行過濾的是文件名和文件所在的目錄。而FileFilter進行過濾的直接就是目標文件。

在java中是沒有目錄的概念的,一個目錄也是用File的表示的。

上面的兩個使用起來非常類似,我們就以FilenameFilter爲例,看下怎麼刪除.log文件:

public void useFileNameFilter()
    {
        String targetDirectory = "src/main/resources/";
        File directory = new File(targetDirectory);

        //Filter out all log files
        String[] logFiles = directory.list( (dir, fileName)-> fileName.endsWith(".log"));

        //If no log file found; no need to go further
        if (logFiles.length == 0)
            return;

        //This code will delete all log files one by one
        for (String logfile : logFiles)
        {
            String tempLogFile = targetDirectory + File.separator + logfile;
            File fileDelete = new File(tempLogFile);
            boolean isdeleted = fileDelete.delete();
            log.info("file : {} is deleted : {} ", tempLogFile , isdeleted);
        }
    }

上面的例子中,我們通過directory.list方法,傳入lambda表達式創建的Filter,實現了過濾的效果。

最後,我們將過濾之後的文件刪除。實現了目標。

總結

小師妹的兩個問題解決了,希望今天可以不要再見到她。

本文的例子https://github.com/ddean2009/learn-java-io-nio

本文作者:flydean程序那些事

本文鏈接:http://www.flydean.com/io-file-copy-file-filter/

本文來源:flydean的博客

歡迎關注我的公衆號:程序那些事,更多精彩等着您!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章