20145107 《Java程序设计》第八周学习总结

20145107 《Java程序设计》第八周学习总结

教材学习内容总结

在本周,我们进行了教材第十四,十五章的学习,本周的学习目标是:
了解NIO
会使用Channel、Buffer与NIO2
会使用日志API、国际化
会使用正则表达式
了解JDK8增强功能

第十四章:

NIO2文件系统:

  • 1.有关NIO2文件的操作路径:
    想要操作文档,就要先指出文档的路径。path实例是在JVM中的路径的代表对象。也是NIO2文件系统API的操作起点,NIO2文件系统API中有许多操作,都必须使用path指定路径。path实际只代表路径信息,也就是说,该路径所对应的文档或文件夹不一定存在,在java中,path提供一种方法去的路径的各种信息。就像下面的程序:
package cc.openhome;

import java.nio.file.*;
import static java.lang.System.out;

public class PathDemo {
    public static void main(String[] args) {
        Path path = Paths.get(
                System.getProperty("user.home"), "Documents", "Downloads");
        out.printf("toString: %s%n", path.toString());
        out.printf("getFileName: %s%n", path.getFileName());
        out.printf("getName(0): %s%n", path.getName(0));
        out.printf("getNameCount: %d%n", path.getNameCount());
        out.printf("subpath(0,2): %s%n", path.subpath(0, 2));
        out.printf("getParent: %s%n", path.getParent());
        out.printf("getRoot: %s%n", path.getRoot());
    }
} 

此程序在IDEA中的执行情况如下所示:

  • 2.文件的属性读取与设定:
    在以前,并没有标准方式取得不同文件系统所支持的不同属性,在JDK7中,可以通过BasicFileAttributes,DosFileAttributes,PosixFileAttributes,可以针对不同的文件系统取得支持的属性信息。
    BasicFileAttributes就是取得各文件系统中都支持的属性,可以通过File.readAttributes()取得BasicFileAttributes实例,对应的代码如下:
package cc.openhome;

import java.io.IOException;
import static java.lang.System.out;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;

public class BasicFileAttributesDemo {
    public static void main(String[] args) throws IOException {
        Path file = Paths.get("C:\\Windows");
        BasicFileAttributes attrs = 
                Files.readAttributes(file, BasicFileAttributes.class);
        out.printf("creationTime: %s%n", attrs.creationTime());
        out.printf("lastAccessTime: %s%n",  attrs.lastAccessTime());
        out.printf("lastModifiedTime: %s%n", attrs.lastModifiedTime());
        out.printf("isDirectory: %b%n", attrs.isDirectory());
        out.printf("isOther: %b%n", attrs.isOther());
        out.printf("isRegularFile: %b%n",  attrs.isRegularFile());
        out.printf("isSymbolicLink: %b%n", attrs.isSymbolicLink());
        out.printf("size: %d%n", attrs.size());
    }
} 

相应执行的结果如下:

如果想取得储存装置本身的信息,可以利用Files.getFileStore()方法取得所有存储装置的FileStore实例。下面这个程序可以利用FileStore计算磁盘的使用率:

package cc.openhome;

import java.io.IOException;
import static java.lang.System.out;
import java.nio.file.*;
import java.text.DecimalFormat;

public class Disk {
    public static void main(String[] args) throws IOException {
        if (args.length == 0) {
            FileSystem fs = FileSystems.getDefault();
            for (FileStore store: fs.getFileStores()) {
                print(store);
            }
        } 
        else {
            for (String file: args) {
                FileStore store = Files.getFileStore(Paths.get(file));
                print(store);
            }
        }
    }
    
    public static void print(FileStore store) throws IOException {
        long total = store.getTotalSpace();
        long used = store.getTotalSpace() - store.getUnallocatedSpace();
        long usable = store.getUsableSpace();
        DecimalFormat formatter = new DecimalFormat("#,###,###");
        out.println(store.toString());
        out.printf("\t- 总容量\t%s\t位元组%n", formatter.format(total));
        out.printf("\t- 可用空间\t%s\t位元组%n", formatter.format(used));
        out.printf("\t- 已用空间\t%s\t位元组%n", formatter.format(usable));
    }
}

程序执行后,我的电脑中磁盘的相关信息就显示了出来:

  • 3.操作文档与目录:
    如果想要删除path代表的文档或目录,可以使用Files.delete()方法,但这个方法会出现一系列的问题。我们可以使用更高级的办法Files.deleteIfExists()方法删除文档。如果想要复制来源path的文档或目录至目的地path,可以使用File.copy()方法,这个方法的第三个选项会指定CopyOption接口的操作对象。File.copy还有两个重载的版本,一个是接受InputStream作为来源,可以直接读取数据,并将结果复制到指定的Path中;另一个File.copy()版本是将来源Path复制到指定的OutputStream,书中有一个相应的程序:
package cc.openhome;

import java.io.*;
import java.net.URL;
import java.nio.file.*;
import static java.nio.file.StandardCopyOption.*;

public class Download {
    public static void main(String[] args) throws IOException {
        URL url = new URL(args[0]);
        Files.copy(url.openStream(), Paths.get(args[1]), REPLACE_EXISTING);
    }
}

若要进行文档或目录移动,可以使用File.move方法,使用方式与File.copy方法类似,可以指定来源Path,目的地Path与CopyOption。如果要建立目录则可以使用Files.createDirectory()方法。

  • 4.读取访问目录:
    如果想取得文件系统根目录的信息,可以使用FileSystem的getRootDirectories方法相应的程序如下:
package NIO2;



        import static java.lang.System.out;
        import java.nio.file.*;

public class Roots {
    public static void main(String[] args) {
        Iterable<Path> dirs = FileSystems.getDefault().getRootDirectories();
        dirs.forEach(out::println);
    }
}

相应的程序执行如下:

也可以使用File.newDirectoryStream()方法取得DirectoryStream接口操作对象,代表指定路径下的所有文档。下面这个程序可以从命令行自变量指定目录路径,查询出该目录下的文档:

package NIO2;



        import java.io.IOException;
        import static java.lang.System.out;
        import java.nio.file.*;
        import java.util.*;

public class Dir {
    public static void main(String[] args) throws IOException {
        try(DirectoryStream<Path> directoryStream =
                    Files.newDirectoryStream(Paths.get(args[0]))) {
            List<String> files = new ArrayList<>();
            for(Path path : directoryStream) {
                if(Files.isDirectory(path)) {
                    out.printf("[%s]%n", path.getFileName());
                }
                else {
                    files.add(path.getFileName().toString());
                }
            }
            files.forEach(out::println);
        }
    }
}

第十五章:

日志:

  • 1.java.util.logging包提供了日志功能相关的类与接口,其好处是不用加入额外配置的日志组件就可以在标准的java平台上使用。日志的起点是logger类。在调用getLogger类时必须制定Logger实例所指定的名称空间,名称空间以“.”作为层级区分,层级相同的Logger其父Logger组态相同。在取得Logger实例后,可以用log方法输出信息例如:
package Logging;



        import java.util.logging.*;

public class LoggerDemo {
    public static void main(String[] args) {
        Logger logger = Logger.getLogger(LoggerDemo.class.getName());
        logger.log(Level.WARNING, "WARNING 讯息");
        logger.log(Level.INFO, "INFO 讯息");
        logger.log(Level.CONFIG, "CONFIG 讯息");
        logger.log(Level.FINE, "FINE 讯息");
    }
}

相应的程序执行情况如下:

-2.使用Handler与Formatter:

在java中负责日志输出的是Handler实例,Logger可以使用addHandler()新增handler实例,使用RomoveHandler移除实例,书中有一个程序范例,可以将目前Logger与新建的FileHandler层级设定Level.CONFIG,并使用addHandler()设定至Logger实例:

package Logging;



        import java.io.IOException;
        import java.util.logging.*;

public class HandlerDemo {
    public static void main(String[] args) throws IOException {
        Logger logger = Logger.getLogger(HandlerDemo.class.getName());
        logger.setLevel(Level.CONFIG);
        FileHandler handler = new FileHandler("%h/config.log");
        handler.setLevel(Level.CONFIG);
        logger.addHandler(handler);
        logger.config("Logger 组装完成");
    }
}

  • 3.自定义Handler,Formatter与Filter:

    如果java.util.logger包中提供的Handler成果都不符合要求,可以继承Handler类,操作抽象方法publish(),flush(),close()方法来自定义Handler,建议操作时考虑信息过滤与格式化。如果要自定义Fomatter,可以继承Fomatter后操作抽象方法format(),这个方法会传入LogRecord,储存所有的日志信息。下面的程序将ConsoleHandler的Formatter设定为自定义的Formatter:

package Logging;



        import java.time.Instant;
        import java.util.logging.*;

public class FormatterDemo {
    public static void main(String[] args) {
        Logger logger = Logger.getLogger(FormatterDemo.class.getName());
        logger.setLevel(Level.CONFIG);
        ConsoleHandler handler = new ConsoleHandler();
        handler.setLevel(Level.CONFIG);
        handler.setFormatter(new Formatter() {
            @Override
            public String format(LogRecord record) {
                return "日志來自 " + record.getSourceClassName() + "."
                        + record.getSourceMethodName() + "\n"
                        + "\t层级\t: " + record.getLevel() + "\n"
                        + "\t讯息\t: " + record.getMessage() + "\n"
                        + "\t时间\t: "  + Instant.ofEpochMilli(record.getMillis())
                        + "\n";
            }
        });
        logger.addHandler(handler);
        logger.config("自订 Formatter 讯息");
    }
}

程序相应的执行范例如下:

规则表示式:

  • 1.规则表示式简介:
    如果我想根据某个字符串或字符进行切割,可以使用String的split()方法,它会返回切割后各子字符串组成的String数组。就像下面的程序:
import static java.lang.System.out;

public class SplitDemo {
    public static void main(String[] args) {
        // 根据逗号切割
        for(String token : "Justin,Monica,Irene".split(",")) {
            out.println(token);
        }
        // 根据Orz切割
        for(String token : "JustinOrzMonicaOrzIrene".split("Orz")) {
            out.println(token);
        }
        // 根据Tab字元切割
        for(String token : "Justin\tMonica\tIrene".split("\\t")) {
            out.println(token);
        }
    }
} 

相应的程序执行范例如下:

  • 2.边界比较

    在java的编程中,我们可以使用\b来标出单词边界,就像下面这个程序:

package Regex;



public class SplitDemo3 {
    public static void main(String[] args) {
        for(String str : "Justin dog Monica doggie Irene".split("\\bdog\\b")) {
            System.out.println(str.trim());
        }
    }
}

相应的程序代码如下:

  • 3.JDK8API增强功能:

    1.如果我们有一组字符串,我们想要指定每个字符串之间以“,”进行分隔,现在,我们可以使用String新增的join()静态方法。
    2.对于数组操作,在JDK8中针对大型数组的平行化操作,在Arrays上新增了parallelPrefix(),ParallelSetall()与parallelSort()方法。

本周代码托管截图

本周代码数量截图:

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时
第一周 200/200 2/2 20/20
第二周 100/300 1/3 18/38
第三周 200/500 1/4 22/60
第四周 250/750 1/5 30/90
第五周 450/1200 1/6 20/110
第六周 400/1600 2/8 30/140
第七周 150/1750 2/10 30/170
第八周 500/2250 2/12 30/200

参考资料

posted @ 2016-04-23 21:22  20145107lcd  阅读(174)  评论(1编辑  收藏  举报