File.lastModified() никогда не был установлен с file.setLastModified()
У меня проблема с набором миллисов и чтение на Android 2.3.4 на Nexus One. Это код:
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();
}
В этом небольшом тесте я пишу 1310198774, но результат, который возвращается из lastModified(), равен 1310199771000.
Даже если я вырезаю конечный "000", разница в несколько минут.
Мне нужно синхронизировать файлы между веб-сервисом и устройством Android. Минуты последней модификации являются частью данных, отправленных этой службой. Я устанавливаю миллионы для созданных/скопированных файлов и папок, чтобы проверить, нужно ли перезаписывать файл/папку.
Все работает, но миллины, которые возвращаются из файловой системы, отличаются от значений, которые были установлены.
Я уверен, что с моим кодом что-то не так, но я не могу его найти.
Большое спасибо заранее.
HJW
Ответы
Ответ 1
Так что, возможно, я что-то пропустил, но вижу некоторые проблемы с вашим кодом выше. Ваша конкретная проблема может быть вызвана (как указано в @JB) на проблемы с Android, но для потомков я думал, что дам ответ.
Во-первых, File.setLastModified()
занимает время в миллисекундах. Вот javadocs. Кажется, вы пытаетесь установить его за считанные секунды. Таким образом, ваш код должен выглядеть примерно так:
fileFolder.setLastModified(1310198774000L);
Как упоминалось в javadocs, многие файловые системы поддерживают только секундную детализацию секунд для последней модификации. Поэтому, если вам нужно увидеть такое же время модификации в файле, вы должны сделать что-то вроде следующего:
private void changeModificationFile(File file, long time) {
// round the value down to the nearest second
file.setLastModified((time / 1000) * 1000);
}
Ответ 2
На желе Bean + он отличается (в основном, на устройствах Nexus еще и другими, которые используют новый слой плавкого предохранителя для эмуляции эмуляции /mnt/shell/emulated sdcard):
Это проблема разрешения VFS, syscall utimensat() терпит неудачу с EPERM из-за несоответствующих разрешений (например, права собственности).
в платформе /system/core/sdcard/sdcard.c:
/* все файлы, принадлежащие root.sdcard */
attr- > uid = 0;
attr- > gid = AID_SDCARD_RW;
Из страницы utimensat() syscall man:
2. the caller 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.
Старый FAT предлагает переопределить флаг iattr- > valid с помощью опции mount, чтобы разрешить изменение временных меток кому-либо, FUSE + Android sdcard-FUSE не делает этого в данный момент (поэтому сбой inode_change_ok() завершается с ошибкой) и попытка отклоняется с помощью -EPERM. Здесь FAT./fs/fat/file.c:
/* 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);
Я также добавил эту информацию в эту открытую ошибку.
Ответ 3
Если это не работает, попробуйте это (уродливое) обходное решение, указанное в 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();
Ответ 4
Работает на некоторых устройствах, но не на других. Не разрабатывайте решение, основанное на его работе. См. https://code.google.com/p/android/issues/detail?id=18624#c29
Вот простой тест, чтобы увидеть, работает ли он.
public void testSetLastModified() throws IOException {
long time = 1316137362000L;
File file = new File("/mnt/sdcard/foo");
file.createNewFile();
file.setLastModified(time);
assertEquals(time, file.lastModified());
}
Ответ 5
Если вы хотите изменить дату/время каталога на текущую дату/время (т.е. "сейчас" ), вы можете создать какой-то временный файл внутри этого каталога, записать что-нибудь в него, а затем сразу удали это. Это приводит к изменению даты/времени "lastModified()" для текущей даты/времени. Однако это не сработает, если вы хотите изменить дату/время каталога на какое-либо другое случайное значение и не можете быть применены к файлу, очевидно.