java-IO流: Path和Files詳解

Java7中文件IO發生了很大的變化,專門引入了很多新的類:

import java.nio.file.DirectoryStream;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;

……等等,來取代原來的基於java.io.File的文件IO操作方式.

  1. Path就是取代File的

A Path represents a path that is hierarchical and composed of a sequence of directory and file name elements separated by a special separator or delimiter.

Path用於來表示文件路徑和文件。可以有多種方法來構造一個Path對象來表示一個文件路徑,或者一個文件:

1)首先是final類Paths的兩個static方法,如何從一個路徑字符串來構造Path對象:

    Path path = Paths.get("C:/", "Xmp");
    Path path2 = Paths.get("C:/Xmp");

    URI u = URI.create("file:///C:/Xmp/dd");        
    Path p = Paths.get(u);

2)FileSystems構造:

Path path3 = FileSystems.getDefault().getPath(“C:/”, “access.log”);
3)File和Path之間的轉換,File和URI之間的轉換:

    File file = new File("C:/my.ini");
    Path p1 = file.toPath();
    p1.toFile();
    file.toURI();

4)創建一個文件:

    Path target2 = Paths.get("C:\\mystuff.txt");
        try {
            if(!Files.exists(target2))
                Files.createFile(target2);
        } catch (IOException e) {
            e.printStackTrace();
        }

windows下不支持PosixFilePermission來指定rwx權限。

5)Files.newBufferedReader讀取文件:

        try {
//            Charset.forName("GBK")
            BufferedReader reader = Files.newBufferedReader(Paths.get("C:\\my.ini"), StandardCharsets.UTF_8);
            String str = null;
            while((str = reader.readLine()) != null){
                System.out.println(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

可以看到使用 Files.newBufferedReader 遠比原來的FileInputStream,然後BufferedReader包裝,等操作簡單的多了。

這裏如果指定的字符編碼不對,可能會拋出異常 MalformedInputException ,或者讀取到了亂碼:

java.nio.charset.MalformedInputException: Input length = 1
    at java.nio.charset.CoderResult.throwException(CoderResult.java:281)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:339)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
    at java.io.InputStreamReader.read(InputStreamReader.java:184)
    at java.io.BufferedReader.fill(BufferedReader.java:161)
    at java.io.BufferedReader.readLine(BufferedReader.java:324)
    at java.io.BufferedReader.readLine(BufferedReader.java:389)
    at com.coin.Test.main(Test.java:79)

6)文件寫操作:

      try {
            BufferedWriter writer = Files.newBufferedWriter(Paths.get("C:\\my2.ini"), StandardCharsets.UTF_8);
            writer.write("測試文件寫操作");
            writer.flush();
            writer.close();
        } catch (IOException e1) {
            e1.printStackTrace();
        }

7)遍歷一個文件夾:

      Path dir = Paths.get("D:\\webworkspace");
        try(DirectoryStream<Path> stream = Files.newDirectoryStream(dir)){
            for(Path e : stream){
                System.out.println(e.getFileName());
            }
        }catch(IOException e){

        }


        try (Stream<Path> stream = Files.list(Paths.get("C:/"))){
            Iterator<Path> ite = stream.iterator();
            while(ite.hasNext()){
                Path pp = ite.next();
                System.out.println(pp.getFileName());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

上面是遍歷單個目錄,它不會遍歷整個目錄。遍歷整個目錄需要使用:Files.walkFileTree

8)遍歷整個文件目錄:

 public static void main(String[] args) throws IOException{
        Path startingDir = Paths.get("C:\\apache-tomcat-8.0.21");
        List<Path> result = new LinkedList<Path>();
        Files.walkFileTree(startingDir, new FindJavaVisitor(result));
        System.out.println("result.size()=" + result.size());        
    }

    private static class FindJavaVisitor extends SimpleFileVisitor<Path>{
        private List<Path> result;
        public FindJavaVisitor(List<Path> result){
            this.result = result;
        }
        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs){
            if(file.toString().endsWith(".java")){
                result.add(file.getFileName());
            }
            return FileVisitResult.CONTINUE;
        }
    }

來一個實際例子:

 public static void main(String[] args) throws IOException {
        Path startingDir = Paths.get("F:\\upload\\images");    // F:\\upload\\images\\2\\20141206
        List<Path> result = new LinkedList<Path>();
        Files.walkFileTree(startingDir, new FindJavaVisitor(result));
        System.out.println("result.size()=" + result.size()); 

        System.out.println("done.");
    }

    private static class FindJavaVisitor extends SimpleFileVisitor<Path>{
        private List<Path> result;
        public FindJavaVisitor(List<Path> result){
            this.result = result;
        }

        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs){
            String filePath = file.toFile().getAbsolutePath();       
            if(filePath.matches(".*_[1|2]{1}\\.(?i)(jpg|jpeg|gif|bmp|png)")){
                try {
                    Files.deleteIfExists(file);
                } catch (IOException e) {
                    e.printStackTrace();
                }
              result.add(file.getFileName());
            } return FileVisitResult.CONTINUE;
        }
    }

將目錄下面所有符合條件的圖片刪除掉:filePath.matches(“.*_[1|2]{1}\.(?i)(jpg|jpeg|gif|bmp|png)”)

  public static void main(String[] args) throws IOException {
        Path startingDir = Paths.get("F:\\111111\\upload\\images");    // F:\111111\\upload\\images\\2\\20141206
        List<Path> result = new LinkedList<Path>();
        Files.walkFileTree(startingDir, new FindJavaVisitor(result));
        System.out.println("result.size()=" + result.size()); 

        System.out.println("done.");
    }

    private static class FindJavaVisitor extends SimpleFileVisitor<Path>{
        private List<Path> result;
        public FindJavaVisitor(List<Path> result){
            this.result = result;
        }

        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs){
            String filePath = file.toFile().getAbsolutePath();
            int width = 224;
            int height = 300;
            StringUtils.substringBeforeLast(filePath, ".");
            String newPath = StringUtils.substringBeforeLast(filePath, ".") + "_1." 
                                            + StringUtils.substringAfterLast(filePath, ".");
            try {
                ImageUtil.zoomImage(filePath, newPath, width, height);
            } catch (IOException e) {
                e.printStackTrace();
                return FileVisitResult.CONTINUE;
            }
            result.add(file.getFileName());
            return FileVisitResult.CONTINUE;
        }
    }

爲目錄下的所有圖片生成指定大小的縮略圖。a.jpg 則生成 a_1.jpg

  1. 強大的java.nio.file.Files

1)創建目錄和文件:

     try {
            Files.createDirectories(Paths.get("C://TEST"));
            if(!Files.exists(Paths.get("C://TEST")))
                    Files.createFile(Paths.get("C://TEST/test.txt"));
//            Files.createDirectories(Paths.get("C://TEST/test2.txt"));
        } catch (IOException e) {
            e.printStackTrace();
        }

注意創建目錄和文件Files.createDirectories 和 Files.createFile不能混用,必須先有目錄,才能在目錄中創建文件。

2)文件複製:

從文件複製到文件:Files.copy(Path source, Path target, CopyOption options);

從輸入流複製到文件:Files.copy(InputStream in, Path target, CopyOption options);

從文件複製到輸出流:Files.copy(Path source, OutputStream out);

     try {
            Files.createDirectories(Paths.get("C://TEST"));
            if(!Files.exists(Paths.get("C://TEST")))
                    Files.createFile(Paths.get("C://TEST/test.txt"));
//          Files.createDirectories(Paths.get("C://TEST/test2.txt"));
            Files.copy(Paths.get("C://my.ini"), System.out);
            Files.copy(Paths.get("C://my.ini"), Paths.get("C://my2.ini"), StandardCopyOption.REPLACE_EXISTING);
            Files.copy(System.in, Paths.get("C://my3.ini"), StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            e.printStackTrace();
        }

3)遍歷一個目錄和文件夾上面已經介紹了:Files.newDirectoryStream , Files.walkFileTree

4)讀取文件屬性:

     Path zip = Paths.get(uri);
            System.out.println(Files.getLastModifiedTime(zip));
            System.out.println(Files.size(zip));
            System.out.println(Files.isSymbolicLink(zip));
            System.out.println(Files.isDirectory(zip));
            System.out.println(Files.readAttributes(zip, "*"));

5)讀取和設置文件權限:

       Path profile = Paths.get("/home/digdeep/.profile");
            PosixFileAttributes attrs = Files.readAttributes(profile, PosixFileAttributes.class);// 讀取文件的權限
            Set<PosixFilePermission> posixPermissions = attrs.permissions();
            posixPermissions.clear();
            String owner = attrs.owner().getName();
            String perms = PosixFilePermissions.toString(posixPermissions);
            System.out.format("%s %s%n", owner, perms);

            posixPermissions.add(PosixFilePermission.OWNER_READ);
            posixPermissions.add(PosixFilePermission.GROUP_READ);
            posixPermissions.add(PosixFilePermission.OTHERS_READ);
            posixPermissions.add(PosixFilePermission.OWNER_WRITE);

            Files.setPosixFilePermissions(profile, posixPermissions);    // 設置文件的權限

Files類簡直強大的一塌糊塗,幾乎所有文件和目錄的相關屬性,操作都有想要的api來支持。這裏懶得再繼續介紹了,詳細參見 jdk8 的文檔。

一個實際例子:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class StringTools {
    public static void main(String[] args) {
        try {
            BufferedReader reader = Files.newBufferedReader(Paths.get("C:\\Members.sql"), StandardCharsets.UTF_8);
            BufferedWriter writer = Files.newBufferedWriter(Paths.get("C:\\Members3.txt"), StandardCharsets.UTF_8);

            String str = null;
            while ((str = reader.readLine()) != null) {
                if (str != null && str.indexOf(", CAST(0x") != -1 && str.indexOf("AS DateTime)") != -1) {
                    String newStr = str.substring(0, str.indexOf(", CAST(0x")) + ")";
                    writer.write(newStr);
                    writer.newLine();
                }
            }
            writer.flush();
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

場景是,sql server導出數據時,會將 datatime 導成16進制的binary格式,形如:, CAST(0x0000A2A500FC2E4F AS DateTime))

所以上面的程序是將最後一個 datatime 字段導出的 , CAST(0x0000A2A500FC2E4F AS DateTime) 刪除掉,生成新的不含有datetime字段值的sql 腳本。用來導入到mysql中。

做到半途,其實有更好的方法,使用sql yog可以很靈活的將sql server中的表以及數據導入到mysql中。使用sql server自帶的導出數據的功能,反而不好處理。

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