IsN*_*ull 5 java macos metadata hfs+ xattr
前言 我正在开发一个用 java 编写的依赖于平台的媒体数据库,其中媒体文件由文件哈希标识。用户应该能够移动文件,所以我不想依赖任何文件路径。导入后,我将路径和哈希值存储在我的数据库中。我开发了一种基于准确性和性能之间的权衡的快速文件哈希 ID 算法,但快速并不总是足够快。:)
为了更新和导入媒体文件,我需要(重新)创建库中所有文件的文件哈希。我现在的想法是只计算一次散列并将其存储在文件元数据(扩展属性)中,以提高支持扩展文件属性的文件系统的性能。(NTFS, HFS+, ext3...) 我已经实现了,你可以在这里找到当前的源:archimedesJ.io.metadata
尝试 乍一看,Java 1.7 通过UserDefinedFileAttributeView提供了一种处理元数据的好方法。对于大多数平台,这是有效的。遗憾的是,UserDefinedFileAttributeView在 HFS+ 上不起作用。尽管如此,我不明白为什么特别不支持 HFS+ 文件系统——它是元数据的主要格式之一?(请参阅相关问题-不提供任何解决方案)
如何使用 Java 在 OS X 上存储扩展文件属性? 为了克服这个 java 限制,我决定使用OSX 上的xattr命令行工具,并将它与 Javas Process 处理一起使用来读取它的输出。我的实现有效,但速度很慢。(文件哈希的重新计算速度更快,多么讽刺!我正在 Mac BookPro Retina 上进行测试,带有 SSD。)
事实证明,xattr 工具的运行速度很慢。(写入速度很慢,但更重要的是读取属性也很慢)为了证明这不是 Java 问题而是工具本身,我创建了一个简单的 bash 脚本,以便在具有我的自定义属性的几个文件上使用 xattr 工具:
FILES=/Users/IsNull/Pictures/
for f in $FILES
do
xattr -p vidada.hash $f
done
Run Code Online (Sandbox Code Playgroud)
如果我运行它,这些行会彼此“快速”显示,但我希望在几毫秒内立即向我显示输出。一点点延迟是清晰可见的,因此我猜这个工具并没有那么快。在 java 中使用它会给我一个额外的开销来创建一个进程,解析输出,这使得它甚至有点慢。
有没有更好的方法来使用 Java 访问 HFS+ 上的扩展属性?使用 Java 在 OS X 上使用扩展属性的快速方法是什么?
我创建了一个 JNI 包装器,用于现在直接通过 C-API 访问扩展属性。它是一个开源 Java Maven 项目,可在GitHub/xattrj上获取
作为参考,我在这里发布了有趣的源代码。最新的源码请参考上面的项目页面。
Xattrj.java
public class Xattrj {
/**
* Write the extended attribute to the given file
* @param file
* @param attrKey
* @param attrValue
*/
public void writeAttribute(File file, String attrKey, String attrValue){
writeAttribute(file.getAbsolutePath(), attrKey, attrValue);
}
/**
* Read the extended attribute from the given file
* @param file
* @param attrKey
* @return
*/
public String readAttribute(File file, String attrKey){
return readAttribute(file.getAbsolutePath(), attrKey);
}
/**
* Write the extended attribute to the given file
* @param file
* @param attrKey
* @param attrValue
*/
private native void writeAttribute(String file, String attrKey, String attrValue);
/**
* Read the extended attribute from the given file
* @param file
* @param attrKey
* @return
*/
private native String readAttribute(String file, String attrKey);
static {
try {
System.out.println("loading xattrj...");
LibraryLoader.loadLibrary("xattrj");
System.out.println("loaded!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Run Code Online (Sandbox Code Playgroud)
org_securityvision_xattrj_Xattrj.cpp
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "org_securityvision_xattrj_Xattrj.h"
#include <sys/xattr.h>
/**
* writeAttribute
* writes the extended attribute
*
*/
JNIEXPORT void JNICALL Java_org_securityvision_xattrj_Xattrj_writeAttribute
(JNIEnv *env, jobject jobj, jstring jfilePath, jstring jattrName, jstring jattrValue){
const char *filePath= env->GetStringUTFChars(jfilePath, 0);
const char *attrName= env->GetStringUTFChars(jattrName, 0);
const char *attrValue=env->GetStringUTFChars(jattrValue,0);
int res = setxattr(filePath,
attrName,
(void *)attrValue,
strlen(attrValue), 0, 0); //XATTR_NOFOLLOW != 0
if(res){
// an error occurred, see errno
printf("native:writeAttribute: error on write...");
perror("");
}
}
/**
* readAttribute
* Reads the extended attribute as string
*
* If the attribute does not exist (or any other error occurs)
* a null string is returned.
*
*
*/
JNIEXPORT jstring JNICALL Java_org_securityvision_xattrj_Xattrj_readAttribute
(JNIEnv *env, jobject jobj, jstring jfilePath, jstring jattrName){
jstring jvalue = NULL;
const char *filePath= env->GetStringUTFChars(jfilePath, 0);
const char *attrName= env->GetStringUTFChars(jattrName, 0);
// get size of needed buffer
int bufferLength = getxattr(filePath, attrName, NULL, 0, 0, 0);
if(bufferLength > 0){
// make a buffer of sufficient length
char *buffer = (char*)malloc(bufferLength);
// now actually get the attribute string
int s = getxattr(filePath, attrName, buffer, bufferLength, 0, 0);
if(s > 0){
// convert the buffer to a null terminated string
char *value = (char*)malloc(s+1);
*(char*)value = 0;
strncat(value, buffer, s);
free(buffer);
// convert the c-String to a java string
jvalue = env->NewStringUTF(value);
}
}
return jvalue;
}
Run Code Online (Sandbox Code Playgroud)
现在的 makefile 让我很困扰,让事情正常工作:
CC=gcc
LDFLAGS= -fPIC -bundle
CFLAGS= -c -shared -I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers -m64
SOURCES_DIR=src/main/c++
OBJECTS_DIR=target/c++
EXECUTABLE=target/classes/libxattrj.dylib
SOURCES=$(shell find '$(SOURCES_DIR)' -type f -name '*.cpp')
OBJECTS=$(SOURCES:$(SOURCES_DIR)/%.cpp=$(OBJECTS_DIR)/%.o)
all: $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $@
$(OBJECTS): $(SOURCES)
mkdir -p $(OBJECTS_DIR)
$(CC) $(CFLAGS) $< -o $@
clean:
rm -rf $(OBJECTS_DIR) $(EXECUTABLE)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2361 次 |
| 最近记录: |