2015-04-02 6 views
5

Sto cercando di aggiungere un tag metadata personalizzato a qualsiasi tipo di file utilizzando la funzionalità di java.nio.file.Files. Sono stato in grado di leggere correttamente i metadati, ma ho problemi ogni volta che provo ad impostare i metadati.Problemi con i metadati dei file con Java nio

Ho cercato di impostare un elemento di metadati personalizzati con una stringa semplice utilizzando Files.setAttribute con il seguente

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(); 
    } 

ma finiscono con il seguente errore:

Exception in thread "main" java.lang.ClassCastException: java.lang.String non può essere lanciato a java.nio.ByteBuffer

se provo a lanciare quella stringa in un ByteBuffer in questo modo

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(); 
    } 

invece di emettere il testo di 'test', che emette la stringa di caratteri strani '[B @ 14e3f41'

Qual è il modo corretto per convertire una stringa in un ByteBuffer e lo hanno essere convertibile in una stringa e c'è un modo più personalizzabile per modificare i metadati su un file usando java?

risposta

4

Gli attributi definiti dall'utente, ovvero qualsiasi attributo definito da UserDefinedFileAttributeView (a condizione che il proprio FileSystem li supporti!), Siano leggibili/scrivibili da Java come matrici di byte; se un determinato attributo contiene del contenuto testuale, dipende dal processo che cosa sarà la codifica per la stringa in questione.

Ora, si utilizzano i metodi .{get,set}Attribute(), il che significa che ci sono due opzioni per scrivere user attributi:

  • sia utilizzando un ByteBuffer come avete fatto; oppure
  • utilizzando un array di byte semplici.

Che cosa si legge leggi ma è sempre un array di byte.

Dal link qui sopra Javadoc (sottolineatura mia):

in cui gli attributi è richiesto l'accesso dinamico di file, il metodo getAttribute possono essere utilizzati per leggere il valore di attributo. Il valore dell'attributo viene restituito come una matrice di byte (byte []). Il metodo setAttribute può essere utilizzato per scrivere il valore di un attributo definito dall'utente da un buffer (come se invocando il metodo di scrittura) o l'array di byte (byte []).

Quindi, nel tuo caso:

  • al fine di scrittura l'attributo, ottenere un array di byte con la codifica richiesto dalla stringa:

    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); 
    
  • al fine per leggi l'attributo, devi trasmettere il risultato di .getAttribute() a un array di byte e quindi ottenere una stringa fuori di esso, ancora una volta utilizzando la codifica corretta:

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

Una sbirciatina in altra soluzione, nel caso in cui ...

Come già detto, ciò che si vuole affrontare è un UserDefinedFileAttributeView. La classe Files consente di ottenere qualsiasi FileAttributeView implementazione utilizzando questo metodo:

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

Ora, una volta che hai questo punto di vista a vostra disposizione, è possibile leggere, o scrivere, esso.

Ad esempio, ecco come leggeresti il ​​tuo particolare attributo; notiamo che qui usiamo solo il nome dell'attributo , poiché la vista (con il nome "user") è già presente:

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); 

Per poter scrivere, è necessario avvolgere la matrice di byte in una ByteBuffer:

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

Come ho detto, ti dà più controllo, ma è più coinvolto.

Nota finale: come il nome impone, gli attributi definiti dall'utente sono definiti dall'utente; un dato attributo per questa vista può, o non può esistere. È tua responsabilità gestire correttamente gli errori se un attributo non esiste ecc; il JDK non offre nulla come NoSuchAttributeException per questo tipo di scenario.

+0

Grazie per la risposta dettagliata, ha aiutato a risolvere il problema, ma ciò significa che TUTTI i tag definiti dall'utente di qualsiasi tipo di dati che potrei avere dovrebbero prima essere codificati in un array di byte in scrittura e decodificati nel tipo corrispondente ogni volta che dovevano essere letti? – lobobabysaurus

+0

@PhilSimmons, in effetti, significa esattamente questo; gli attributi definiti dall'utente possono essere letteralmente qualsiasi cosa, non solo contenuti di testo! – fge

+0

@PhilSimmons nota che c'è un'altra opzione per leggere/scrivere attributi (passando attraverso 'View'); è un po 'più complicato, tuttavia – fge