使用Java nio编写文件元数据的问题

时间:2015-04-02 19:11:57

标签: java file metadata nio

我希望使用java.nio.file.Files中的功能向任何类型的文件添加自定义元数据标记。我已经能够正确读取元数据,但每当我尝试设置元数据时都会遇到问题。

我尝试使用带有以下内容的Files.setAttribute设置带有普通字符串的自定义元数据元素

    Path photo = Paths.get("C:\\Users\\some\\picture\\path\\2634.jpeg");
    try{
        BasicFileAttributes attrs = Files.readAttributes(photo, BasicFileAttributes.class);
        Files.setAttribute(photo, "user:tags", "test");
        String attribute = Files.getAttribute(photo, "user:tags").toString();
        System.out.println(attribute);
    }
    catch (IOException ioex){
        ioex.printStackTrace();
    }

但最终出现以下错误:

线程中的异常" main" java.lang.ClassCastException:java.lang.String无法强制转换为java.nio.ByteBuffer

如果我尝试将该字符串转换为像这样的ByteBuffer

    Path photo = Paths.get("C:\\Users\\some\\picture\\path\\2634.jpeg");
    try{
        BasicFileAttributes attrs = Files.readAttributes(photo, BasicFileAttributes.class);
        Files.setAttribute(photo, "user:tags", ByteBuffer.wrap(("test").getBytes("UTF-8")));
        String attribute = Files.getAttribute(photo, "user:tags").toString();
        System.out.println(attribute);
    }
    catch (IOException ioex){
        ioex.printStackTrace();
    }

而不是输出文本' test',它输出奇怪的字符串' [B @ 14e3f41'

将String转换为bytebuffer并将其转换回字符串的正确方法是什么?是否有一种更可自定义的方法来使用java修改文件上的元数据?

1 个答案:

答案 0 :(得分:4)

用户定义的属性,即UserDefinedFileAttributeView定义的任何属性(假设您的FileSystem支持它们!),可以从Java读取/写入字节数组;如果一个给定的属性包含文本内容,那么它将依赖于进程,对于相关字符串的编码将是什么。

现在,您正在使用.{get,set}Attribute()方法,这意味着您有两个选项来编写user属性:

  • 像你一样使用ByteBuffer;或
  • 使用普通字节数组。

读取的内容总是如此。

从上面的javadoc链接(强调我的):

  

如果需要动态访问文件属性,可以使用getAttribute方法读取属性值。 属性值以字节数组(byte [])的形式返回。 setAttribute方法可用于从缓冲区(如通过调用write方法)或字节数组(byte [])写入用户定义属性的值。

所以,在你的情况下:

  • 为了该属性,从字符串中获取具有所请求编码的字节数组:

    final Charset utf8 = StandardCharsets.UTF_8;
    final String myAttrValue = "Mémé dans les orties";
    final byte[] userAttributeValue = myAttrValue.getBytes(utf8);
    Files.setAttribute(photo, "user:tags", userAttributeValue);
    
  • 为了读取属性,你需要将.getAttribute()的结果转换为字节数组,然后再从中获取字符串,再次使用正确的编码:

    final Charset utf8 = StandardCharsets.UTF_8;
    final byte[] userAttributeValue 
        = (byte[]) Files.readAttribute(photo, "user:tags");
    final String myAttrValue = new String(userAttributeValue, utf8);
    

查看其他解决方案,以防万一...

如前所述,您要处理的是UserDefinedFileAttributeViewFiles类允许您使用此方法获取任何FileAttributeView实现:

final UserDefinedFileAttributeView view
    = Files.getFileAttributeView(photo, UserDefinedFileAttributeView.class);

现在,一旦您拥有了这个视图,您就可以阅读或写信给它。

例如,以下是您阅读特定属性的方法;请注意,这里我们只使用属性 name ,因为视图(名称为"user")已经存在:

final Charset utf8 = StandardCharsets.UTF_8;
final int attrSize = view.size("tags");
final ByteBuffer buf = ByteBuffer.allocate(attrSize);
view.read("tags", buf);
return new String(buf.array(), utf8);

为了编写,您需要将字节数组包装到ByteBuffer

final Charset utf8 = StandardCharsets.UTF_8;
final int array = tagValue.getBytes(utf8);
final ByteBuffer buf = ByteBuffer.wrap(array);
view.write("tags", buf);

就像我说的那样,它会给你更多的控制权,但更多的是参与其中。

最后注意事项:正如名称所指示的那样,用户定义的属性是用户定义的;此视图的给定属性可能存在,也可能不存在。如果属性不存在,您有责任正确处理错误等;对于这种情况,JDK不提供NoSuchAttributeException这样的东西。