Kill_Java -- 文件類相關

前言

最近作項目的時候,用java獲取文件。
雖然用框架很容易,可是其內部的原理讓我很疑惑。在本身寫類似的代碼的時候,每每會出現各類各樣的錯誤。因此這裏,對相關的類以及方法進行一個整合。
好比 file 類,path 類。 絕對路徑與相對路徑。 getResource 方法 , getRealPath方法等java

絕對路徑與相對路徑

在使用 File 類的時候,發現絕對路徑和相對路徑的使用有很大的區別。
你們都知道:File類是用來構造文件或文件夾的類,在其構造函數中要求傳入一個String類型的參數,用於指示文件所在的路徑
絕對路徑名是完整的路徑名,不須要任何其餘信息就能夠定位自身表示的文件。
相對路徑名必須使用來自其餘路徑名的信息進行解釋linux

由於我使用的是 idea ,因此下面,我就用idea 給你們演示一下,他們的區別。
廢話很少說,直接上代碼web

public class testFile {
    public static void main(String[] args) throws IOException {
        // 絕對路徑
        File fi1 = new File("D://sy.ini");
        // 相對路徑
        File fi2 = new File("sy.ini");
        String test = "000";
        try {
            // 將 test 分別寫入 fi1 fi2
            FileOutputStream fo1 = new FileOutputStream(fi1);
            FileOutputStream fo2 = new FileOutputStream(fi2);
            fo1.write(test.getBytes());
            fo2.write(test.getBytes());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // 驗證 getPath 與 getAbsolubtePath 的區別。
        System.out.println(fi1.getPath());
        System.out.println(fi1.getAbsolutePath());

        System.out.println(fi2.getPath());
        System.out.println(fi2.getAbsolutePath());
    }
}

輸出的結果以下網絡

D:\sy.ini
D:\sy.ini
sy.ini
D:\Programme\0-Java\J_Example\Arithmetic\sy.ini

用兩張圖片輔助結果框架

從這個結果中,咱們能夠看出兩點ide

  1. getPath 只是簡單的返回 你賦予的String 值,不論是 相對路徑仍是絕對路徑。
  2. 相對路徑是相對於自身的項目地址。而且不加 "/"

getResource

用代碼說話。。。函數

URL resource = testFile.class.getClassLoader().getResource(".");
        URL resource1 = testFile.class.getResource(".");
        System.out.println(resource);
        System.out.println(resource1);

輸出的結果爲post

file:/D:/Programme/0-Java/J_Example/Arithmetic/out/production/3_basic/
file:/D:/Programme/0-Java/J_Example/Arithmetic/out/production/3_basic/test_01/

因此對於 getResource 來講 。性能

  1. 若是使用 Class 類 ,則表明該類所在的包爲 相對路徑的起點。
  2. 若是使用 ClassLoader類 , 則表明該類所在的 模塊爲 相對路徑的起點。

JSP 中的路徑

使用 EL 表達式
${pageContext.request.contextPath} 這裏的路徑指的是 web 的根目錄.測試

File類 與 Path類

Path 類 是 JDK 7 中加入的新內容。比File 類更快,並且有報錯機制,因此更容易使用。

他們兩個的 區別 我會寫在內部的 註釋中。
就不單獨拿出來寫了。

  1. 建立文件
// 若是存在重複 會報錯。
        Path path = Paths.get("D://test.txt");
        Files.createFile(path);
        // 這裏有一個 方法,可直接設置文件的屬性。
        Set perms= PosixFilePermissions.fromString("rw-rw-rw-")
        Files.crateFile(path,perms);


        // 若是存在重複,會從新建立。
        // 可使用 file.exists() 來確認是否存在重複。
        File file = new File("D://test02.txt");
        file.createNewFile();

共同點: 想要建立多級目錄下的文件,都必須先建立目錄,才能建立文件。

  1. 建立目錄
// 能夠直接建立多級目錄
        Path path = Paths.get("D://test/test01/");
        Files.createDirectories(path);

        // mkdir 只能建立一級目錄
        // mkdirs 能夠建立多級目錄
        File file = new File("D://test02/test3/test3");
        file.mkdir();
        file.mkdirs();
  1. 刪除
// 若是文件夾下存在多級目錄,則報錯
        // DirectoryNotEmptyException
        Path path = Paths.get("D://test/");
        Files.delete(path);

        // 若是文件夾下存在多級目錄,則沒有反應。。
        File file = new File("D://test02");
        file.delete();

若是想要刪除相應的文件,直接將 路徑更改成文件的路徑便可。

  1. 遍歷文件
public static void fileForEach(String path) {
        File file = new File(path);
        File[] files = file.listFiles();
        for (File f : files) {
            // 判斷是 文件仍是 目錄
            if (f.isFile()) {
                System.out.println(f.getName() + "是文件!");
            } else if (f.isDirectory()) {
                System.out.println(f.getName());
                fileForEach(f.getPath());
            }
        }
    }

    public static void main(String[] args) throws IOException {
        Path path = Paths.get("D://test/");
        Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
            // 訪問文件夾前使用
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                System.out.println(dir.getFileName());
                return super.preVisitDirectory(dir, attrs);
            }

            // 訪問文件夾後使用
            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                return super.postVisitDirectory(dir, exc);
            }

            // 訪問文件時使用
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                if (file.toString().endsWith(".txt")) {
                    System.out.println(file.getFileName());
                }
                return super.visitFile(file, attrs);
            }

            // 訪問文件失敗使用
            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                return super.visitFileFailed(file, exc);
            }
        });

        fileForEach("D://test02/");
    }}

這裏出現了 SimpleFileVisitor 這個類,具體使用方法就是覆寫其內部方法。
通過個人測試 , 由於這個類的方法, 能夠比 fileForEach 快大約 30%

  1. 複製與移動
    移動的同時能夠更更名字。這一點,都同樣。而且與 linux 的操做也相似

Path 類

Path path = Paths.get("D://test/test01/cs.txt");
        Path to = Paths.get("D://test/test01/test2.txt");
        Files.move(path, to, StandardCopyOption.REPLACE_EXISTING);
        Files.copy(path, to, StandardCopyOption.REPLACE_EXISTING);

這裏的 StandardCopyOption 有三個屬性。
注意: ATOMIC_MOVE 方法只支持 move 方法。若是將之使用到 copy 方法,則會報錯。

/* 若是存在則覆蓋
     * Replace an existing file if it exists. 
     */
    REPLACE_EXISTING,
    /* 將屬性一同拷貝。
     * Copy attributes to the new file.
     */
    COPY_ATTRIBUTES,
    /* 只支持 move 方法,不支持 copy 方法
     * Move the file as an atomic file system operation.
     */
    ATOMIC_MOVE;

下面是file 類

// 拷貝 方法
        public void copyFile(String oldFile,String newFile){
        try{
        int bytesum = 0;
        int byteread = 0;
        File oldfile = new File(oldFile);
        //判斷文件是否存在,若是文件存在則實現該文件向新文件的複製
        if(oldfile.exists()){
            //讀取原文件
            InputStream ins = new FileInputStream(oldFile);
            //建立文件輸出流,寫入文件
            FileOutputStream outs = new FileOutputStream(newFile);
            //建立緩衝區,大小爲500字節
            byte[] buffer = new byte[500];
            //每次從文件流中讀取500字節數據,計算當前爲止讀取的數據總數
            while((byteread = ins.read(buffer)) != -1){
            bytesum += byteread;
            System.out.println(bytesum);
            //把當前緩衝區中的數據寫入新文件
            outs.write(buffer,0,byteread);
            }
            ins.close();
        }
        else  //若是原文件不存在,則扔出異常
            throw new Exception();
        }catch(Exception ex){
        System.out.print("原文件不存在!");
        ex.printStackTrace();
        }

        // 移動 方法
        File file = new File("D://test02/test02/test02.txt");
        file.renameTo(new File("D://test02/test02/test.txt"));

從這裏咱們能夠看出, path 類相對應的 複製方法 很是簡單,不須要使用 直接使用輸入輸出流就能夠複製文件。

  1. 輸入輸出流

Path類

File類

File file = new File("D://test02/test02/test02.txt");
        FileInputStream fileInputStream = new FileInputStream(file);
        FileReader fileReader = new FileReader(file);

相對比,咱們也能夠看出,Path類相對 file類也簡化了不少操做。更有利於開發。

  1. 相互轉化
path.toFile()
File.toPath()

總結

  1. 關於路徑的使用總結。
  2. 關於Path 與 File 類的使用總結。
    Path 類 相比較於 File 類 ,在操做上更直觀,沒有涉及到更深的層面.能夠看出 研發人員 從中做出了不少改進。 可讓人更專一於邏輯的編寫,而非是 底層的基礎。

雖然並無針對其 性能做出確切的比較,不過就現有的網絡統計來講, Path 類在使用中大都會比 File 類快 , 而且在最新的 lucene 中,也是用 Path 代替了 file 的操做, 相關的文章請參考 []。

綜上,推薦使用 Path 類替代 File 類。

結語

碼字不易,各位看官多多點贊喲~~~
謝謝大佬們的支持。
本人我的博客killCode,不定時乾貨。

相關文章
相關標籤/搜索