file.lastModified () никогда не является тем, что было установлено с помощью file.setLastModified () - PullRequest
11 голосов
/ 09 июля 2011

У меня есть проблема с установленным и прочитанным в 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. Последняя модификация - это часть данных, отправляемых этим сервисом. Я устанавливаю millis для созданных / скопированных файлов и папок, чтобы проверить, нужно ли перезаписывать файл / папку.

Все работает, НО миллис, которые возвращаются из файловой системы, отличаются от установленных значений.

Я почти уверен, что с моим кодом что-то не так, но я не могу его найти.

Большое спасибо заранее. HJW

Ответы [ 5 ]

6 голосов
/ 31 августа 2011

Так что, может быть, я что-то упустил, но я вижу некоторые проблемы с вашим кодом выше.Ваша конкретная проблема может быть вызвана (как упомянул @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);
}
5 голосов
/ 20 июня 2013

Если все это не работает, попробуйте этот (безобразный) обходной путь, указанный в 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();
5 голосов
/ 21 декабря 2012

В Jelly Bean + все по-другому (в основном на устройствах Nexus и других, которые используют новый слой предохранителей для эмуляции / mnt / shell / emulated sdcard):

Это проблема с разрешениями VFS, syscall utimensat () завершается ошибкой с EPERM из-за неправильных разрешений (например, владения).

в платформе / системе / ядре / sdcard / sdcard.c:

/ * все файлы, принадлежащие root.sdcard * /
attr-> uid = 0;
attr-> gid = AID_SDCARD_RW;

Из справочной страницы по системному вызову utimensat ():

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.  

Старый FAT предлагает переопределение флага iattr-> valid через опцию монтирования, чтобы позволить кому-либо изменять временные метки, 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);

Я также добавил эту информацию к этой открытой ошибке .

1 голос
/ 16 сентября 2011

Работает на некоторых устройствах, но не на других.Не проектируйте решение, которое полагается на то, что оно работает.См. 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());
}
0 голосов
/ 14 апреля 2015

Если вы хотите изменить только дату / время каталога на текущую дату / время (т. Е. «Сейчас»), то вы можете создать какой-то временный файл внутри этого каталога, что-то записать в него, а затем немедленноудали это.Это приводит к изменению даты / времени lastModified () каталога на текущую дату / время.Однако это не сработает, если вы хотите изменить дату / время в каталоге на другое случайное значение и, очевидно, не можете быть применены к файлу.

...