• 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这个类。

  • 相关阅读:
    C# 获取枚举集合的其中两种方式
    UITextField限制字数的方法
    iOS
    iOS
    iOS
    iOS 获取已连接的wifi信息
    AFNetWorking 的简单使用
    CoreData 基本操作方法封装
    在Ios里UIWebView参入js
    AFNetworking教程
  • 原文地址:https://www.cnblogs.com/everSeeker/p/5462853.html
Copyright © 2020-2023  润新知