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(" - 总容量 %s 位元组%n", formatter.format(total));
out.printf(" - 可用空间 %s 位元组%n", formatter.format(used));
out.printf(" - 已用空间 %s 位元组%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() + "
"
+ " 层级 : " + record.getLevel() + "
"
+ " 讯息 : " + record.getMessage() + "
"
+ " 时间 : " + Instant.ofEpochMilli(record.getMillis())
+ "
";
}
});
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 Monica Irene".split("\t")) {
out.println(token);
}
}
}
相应的程序执行范例如下:
-
2.边界比较
在java的编程中,我们可以使用来标出单词边界,就像下面这个程序:
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 |