FileAttributeView出现空指针异常原因分析

问题?     

      Java7新增了关于文件属性信息的一些新特性,通过java.nio.file.*包下面的类可以实现设置或者读取文件的元数据信息(比如最后修改时间,创建时间,文件大小,是否为目录等等)。尤其是UserDefinedFileAttributeView,可以用来自定义文件的元数据信息。于是在自己的mac上写了个小程序测试了下:

 1 import java.io.IOException;
 2 import java.nio.ByteBuffer;
 3 import java.nio.charset.Charset;
 4 import java.nio.file.Files;
 5 import java.nio.file.Path;
 6 import java.nio.file.Paths;
 7 import java.nio.file.attribute.UserDefinedFileAttributeView;
 8 import java.util.*;
 9 
10 public class FileAttributeViewDemo {
11     private final static Charset CS = Charset.forName("UTF-8");
12 
13     public Map<String, String> getAttributes(Path path) throws IOException {
14         Map<String, String> map = new HashMap<>();
15         Set<String> keys = Files.readAttributes(path, "*").keySet();
16         for (String attr : keys) {
17             map.put(attr, Files.getAttribute(path, attr).toString());
18         }
19         return map;
20     }
21 
22     public Map<String, String> getUserMeta(Path path) throws IOException {
23         UserDefinedFileAttributeView view = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class);
24         List<String> metaKeys = view.list();
25         Map<String, String> map = new HashMap<>();
26         for (String metaKey : metaKeys) {
27             ByteBuffer buff = ByteBuffer.allocate(view.size(metaKey));
28             view.read(metaKey, buff);
29             buff.flip();
30             map.put(metaKey, CS.decode(buff).toString());
31         }
32         return map;
33     }
34 
35     public void writeUserMeta(Path path) {
36         UserDefinedFileAttributeView view = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class);
37         try {
38             view.write("author", CS.encode("everSeeker"));
39             view.write("date", CS.encode("20160505"));
40             view.write("title", CS.encode("Effective-Java中文版.pdf"));
41             view.write("pageTotal", CS.encode("229"));
42         } catch (IOException e) {
43             e.printStackTrace();
44         }
45     }
46 
47     public static void main(String[] args) throws IOException {
48         FileAttributeViewDemo demo = new FileAttributeViewDemo();
49         Path path = Paths.get("/root/xxx/Java/Effective-Java.pdf");
50         //读取文件属性信息
51         Map<String, String> attrMap = demo.getAttributes(path);
52         for (Map.Entry<String, String> entry : attrMap.entrySet()) {
53             System.out.println(entry.getKey() + " : " + entry.getValue());
54         }
55         System.out.println("--------------------------------------------------------------");
56         //写自定义文件属性
57         demo.writeUserMeta(path);
58         //读取自定义文件属性
59         Map<String, String> userMetaMap = demo.getUserMeta(path);
60         for (Map.Entry<String, String> entry : userMetaMap.entrySet()) {
61             System.out.println(entry.getKey() + " : " + entry.getValue());
62         }
63     }
64 }

      整个程序分为3个部分:1、读取文件Effective-Java.pdf文件的元数据信息;2、自定义文件的元数据信息,新增作者,时间,标题,页数这4个文件属性;3、读取自定义的属性信息。

      然后运行了下,就报错了。程序的第38行,view.write("author", CS.encode("everSeeker")); 报空指针错误。通过debug模式查看,发现第36行

UserDefinedFileAttributeView view = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class);

定义的view==null。这就很奇怪了,因为这行代码是jdk 8.0 API手册里面的例子。把代码发给同事在window系统上跑了下,一切正常;自己又在kali linux系统上跑了下,也能正常运行。

 

分析:

      1、首先,通过UserDefinedFileAttributeView自定义的文件元数据信息(UserMeta)肯定是持久化了。因为调用一次writeUserMeta(Path path)方法后,重启程序,直接调用getUserMeta(Path path),还是可以获得自定义的元数据信息。所以现在的问题是,这些信息持久化到哪里去了?这个问题在Vamei的博客里面找到了答案。传送门:Linux文件系统的实现。Linux文件存储系统中的inode(索引节点)存储了文件的大小,时间戳,文件权限等信息以及文件数据块block的位置信息。通过命令stat [文件名]可以直接获得inode的相关信息。

      那么,mac系统的文件存储是怎样的呢?通过命令diskutil list发现,我的OSX Yosemite 10.10.5系统的分区格式为Apple_CoreStorage。和Linux系统采取了完全不同的文件系统。所以,基本判断程序异常的原因在于操作系统的区别。

      2、继续研究,发现java7之后的supportedFileAttributeViews方法可以查看本机上面支持的FileAttributeView类型。

1 public void supportedWhichViews() {
2         Path path = Paths.get("/Users/xxxx/Books/Java并发编程的艺术.pdf");
3         FileSystem fileSystem = path.getFileSystem();
4         Set<String> supportedViews = fileSystem.supportedFileAttributeViews();
5 
6         for (String view : supportedViews) {
7             System.out.println(view);
8         }
9     }

      运行结果为basic, owner, unix, posix;而在Linux系统上运行这段代码,结果为owner, dos, basic, posix, user, unix。可见空指针异常的原因在于在mac osx系统,Java7根本就不支持UserDefinedFileAttributeView这个类。

posted @ 2016-05-05 18:19  everSeeker  阅读(1617)  评论(0编辑  收藏  举报