2011-07-09 17 views
10

Tengo un problema con millis y leo en Android 2.3.4 en un Nexus One. Este es el código:file.lastModified() nunca es lo que se configuró con file.setLastModified()

File fileFolder = new File(Environment.getExternalStorageDirectory(), appName + "/" 
    + URLDecoder.decode(folder.getUrl())); 
if (fileFolder != null && !fileFolder.exists()) { 
    fileFolder.setLastModified(1310198774); 
    fileFolder.mkdirs(); 
    fileFolder.setLastModified(1310198774); 
} 

if (fileFolder != null && fileFolder.exists()) { 
    long l = fileFolder.lastModified(); 
} 

En este pequeño test que escribo 1310198774 pero el resultado que se devuelve desde lastModified() es 1310199771000.

Incluso si corto el trailing "000" hay una diferencia de varios minutos.

Necesito sincronizar archivos entre un servicio web y el dispositivo Android. Los últimos millis de modificación son parte de los datos enviados por este servicio. Sí configuro los milis a los archivos/carpetas creados/copiados para verificar si el archivo/carpeta necesita sobrescribirse.

Todo funciona, PERO los millis que se devuelven del sistema de archivos son diferentes de los valores que se establecieron.

Estoy bastante seguro de que hay algún problema con mi código, pero no puedo encontrarlo.

Muchas gracias de antemano. HJW

+4

Consulte http://code.google.com/p/android/issues/detail?id=1699 y http://code.google.com/p/android/issues/detail?id=1992 –

+0

Gracias por tu rápido comentario. ¿Esto significa que nadie puede crear una función de sincronización basada en la marca de tiempo en tarjetas SD en dispositivos Android? Parece que necesito usar una base de datos para eso ... –

+0

No almacenando la última fecha de modificación como un atributo de archivo. –

Respuesta

6

Así que tal vez me falta algo, pero veo algunos problemas con el código anterior. Su problema específico puede ser debido (como @JB se menciona) a los problemas de Android, pero para la posteridad, pensé que iba a dar una respuesta.

En primer lugar, File.setLastModified() toma el tiempo en milisegundos. Aquí están los javadocs. Parece que intentas configurarlo en segundos. Así que el código debe ser algo como:

fileFolder.setLastModified(1310198774000L); 

Como se mencionó en los javadocs, muchos sistemas de ficheros solamente de apoyo segundos granularidad para el tiempo de última modificación. Así que si usted necesita ver al mismo tiempo la modificación de un archivo, entonces debería hacer algo como lo siguiente:

private void changeModificationFile(File file, long time) { 
    // round the value down to the nearest second 
    file.setLastModified((time/1000) * 1000); 
} 
+1

Esto no resuelve el problema en absoluto, es un error en Android (https://code.google.com/p/android/issues/detail?id=18624). – fhucho

+0

¿Eh? Ese error habla de _permissions_ de llamadas modificadas. El OP no tenía un problema de permisos. Estaba usando millis en lugar de segundos @fhucho. Creo que estás equivocado. – Gray

+0

setLastModified() no funciona incluso si lo redondeo al segundo más cercano. Los permisos de archivos parecen ser la razón subyacente de este error. – fhucho

1

Obras en algunos dispositivos, pero no en otros. No diseñe una solución que dependa de que funcione. Ver https://code.google.com/p/android/issues/detail?id=18624#c29

Aquí hay una prueba simple para ver si funciona.

public void testSetLastModified() throws IOException { 
    long time = 1316137362000L; 
    File file = new File("/mnt/sdcard/foo"); 
    file.createNewFile(); 
    file.setLastModified(time); 
    assertEquals(time, file.lastModified()); 
} 
+0

NO funciona (en algunos dispositivos). –

5

En Jelly Bean +, es diferente (en su mayoría en los dispositivos Nexus todavía, y otros que utilizan la nueva capa fusible para mnt/corteza de emulación sdcard// emulado):

Es un problema de permisos VFS, el syscall utimensat() falla con EPERM debido a permisos inapropiados (por ejemplo, propiedad).

en la plataforma/sistema/núcleo/sdcard/sdcard.c:

/* todos los ficheros titularidad de raíz.sdcard */
attr-> uid = 0;
attr-> gid = AID_SDCARD_RW;

De utimensat() 's syscall página del manual:

2. the caller's effective user ID must match the owner of the file; or 
3. the caller must have appropriate privileges. 

To make any change other than setting both timestamps to the current time 
(i.e., times is not NULL, and both tv_nsec fields are not UTIME_NOW and both 
tv_nsec fields are not UTIME_OMIT), either condition 2 or 3 above must apply. 

grasa vieja ofrece una sustitución de la iattr-> bandera de validez a través de una opción de montaje para permitir el cambio de marcas de tiempo para cualquier persona, FUSIBLE + tarjeta sd de Android -FUSE no hace esto en este momento (por lo que la llamada 'inode_change_ok() falla) y el intento se rechaza con -EPERM. Aquí está ./fs/fat/file.c de FAT:

/* Check for setting the inode time. */ 
ia_valid = attr->ia_valid; 
if (ia_valid & TIMES_SET_FLAGS) { 
    if (fat_allow_set_time(sbi, inode)) 
     attr->ia_valid &= ~TIMES_SET_FLAGS; 
} 

error = inode_change_ok(inode, attr); 

También he añadido esta información a este open bug.

5

Si todo esto no funciona pruebe esta solución (feo) citado de https://code.google.com/p/android/issues/detail?id=18624:

//As a workaround, this ugly hack will set the last modified date to now:  
RandomAccessFile raf = new RandomAccessFile(file, "rw"); 
long length = raf.length(); 
raf.setLength(length + 1); 
raf.setLength(length); 
raf.close(); 
+0

Esto realmente funciona. Sin embargo, me preocupan las implicaciones de rendimiento que podría tener. En teoría, esta llamada podría hacer que el archivo sea reubicado por el sistema de archivos, lo que haría que esta sea una llamada * muy * cara. – Adam

+0

¿Esta causa y problema para los archivos de imagen/video/pdf? – Jaydev

0

Si sólo desea cambiar la fecha/hora de un directorio a la fecha/hora actual (es decir, "ahora"), entonces puede crear algún tipo de archivo temporal dentro de ese directorio, escribir algo en él, y luego eliminarlo de inmediato. Esto tiene el efecto de cambiar la fecha/hora 'lastModified()' del directorio a la fecha/hora actual. Sin embargo, esto no funcionará, si desea cambiar la fecha/hora del directorio a algún otro valor aleatorio, y obviamente no se puede aplicar a un archivo.

Cuestiones relacionadas