java file.lastModified() 从来不是用 file.setLastModified() 设置的

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6633748/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 16:43:30  来源:igfitidea点击:

file.lastModified() is never what was set with file.setLastModified()

javaandroiddatemilliseconds

提问by Harald Wilhelm

I do have a problem with millis set and read on Android 2.3.4 on a Nexus One. This is the code:

我在 Nexus One 上的 Android 2.3.4 设置和读取时确实遇到了问题。这是代码:

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

In this small test I write 1310198774 but the result that is returned from lastModified() is 1310199771000.

在这个小测试中,我写了 1310198774,但从 lastModified() 返回的结果是 1310199771000。

Even if I cut the trailing "000" there's a difference of several minutes.

即使我切断了尾随的“000”,也有几分钟的差异。

I need to sync files between a webservice and the Android device. The lastmodification millis are part of the data sent by this service. I do set the millis to the created/copied files and folders to check if the file/folder needs to be overwritten.

我需要在网络服务和 Android 设备之间同步文件。lastmodification 毫秒是此服务发送的数据的一部分。我确实将毫秒设置为创建/复制的文件和文件夹,以检查是否需要覆盖文件/文件夹。

Everything is working BUT the millis that are returned from the filesystem are different from the values that were set.

一切正常,但从文件系统返回的毫秒数与设置的值不同。

I'm pretty sure there's something wrong with my code - but I can't find it.

我很确定我的代码有问题 - 但我找不到它。

Many thanks in advance. HJW

提前谢谢了。华建华

采纳答案by Gray

So maybe I'm missing something but I see some problems with your code above. Your specific problem may be due (as @JB mentioned) to Android issues but for posterity, I thought I'd provide an answer.

所以也许我遗漏了一些东西,但我发现上面的代码存在一些问题。您的具体问题可能是由于(如@JB 提到的)Android 问题造成的,但对于后代,我想我会提供一个答案。

First off, File.setLastModified()takes the time in milliseconds. Here are the javadocs. You seem to be trying to set it in seconds. So your code should be something like:

首先,File.setLastModified()需要以毫秒为单位的时间。这是javadocs。你似乎试图在几秒钟内设置它。所以你的代码应该是这样的:

fileFolder.setLastModified(1310198774000L);

As mentioned in the javadocs, many filesystems only support seconds granularity for last-modification time. So if you need to see the same modification time in a file then you should do something like the following:

正如 javadocs 中提到的,许多文件系统只支持上次修改时间的秒粒度。因此,如果您需要在文件中看到相同的修改时间,那么您应该执行以下操作:

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

回答by ce4

On Jelly Bean+, it's different (mostly on Nexus devices yet, and others that use the new fuse layer for /mnt/shell/emulated sdcard emulation):

在 Jelly Bean+ 上,它是不同的(主要在 Nexus 设备上,以及其他使用新保险丝层进行 /mnt/shell/emulated sdcard 模拟的设备):

It's a VFS permission problem, the syscall utimensat() fails with EPERM due to inappropriate permissions (e.g. ownership).

这是一个 VFS 权限问题,由于权限不当(例如所有权),系统调用 utimensat() 因 EPERM 失败。

in platform/system/core/sdcard/sdcard.c:

在平台/系统/核心/sdcard/sdcard.c:

/* all files owned by root.sdcard */
attr->uid = 0;
attr->gid = AID_SDCARD_RW;

/* root.sdcard 拥有的所有文件 */
attr->uid = 0;
attr->gid = AID_SDCARD_RW;

From utimensat()'s syscall man page:

从 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.  

Old FAT offers an override of the iattr->valid flag via a mount option to allow changing timestamps to anyone, FUSE+Android's sdcard-FUSE don't do this at the moment (so the 'inode_change_ok() call fails) and the attempt gets rejected with -EPERM. Here's FAT's ./fs/fat/file.c:

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

I also added this info to this open bug.

我还将此信息添加到此打开的错误中

回答by arne.jans

If this all doesn't work try this (ugly) workaround quoted from https://code.google.com/p/android/issues/detail?id=18624:

如果这一切都不起作用,请尝试从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();

回答by Hayes Haugen

Works on some devices but not on others. Do not design a solution that relies on it working. See https://code.google.com/p/android/issues/detail?id=18624#c29

适用于某些设备,但不适用于其他设备。不要设计依赖于它工作的解决方案。见https://code.google.com/p/android/issues/detail?id=18624#c29

Here is a simple test to see if it works.

这是一个简单的测试,看看它是否有效。

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

回答by DDSports

If you only want to change the date/time of a directory to the current date/time (i.e., "now"), then you can create some sort of temporary file inside that directory, write something into it, then immediately delete it. This has the effect of changing the 'lastModified()' date/time of the directory to the present date/time. This won't work though, if you want to change the directory date/time to some other random value, and can't be applied to a file, obviously.

如果您只想将目录的日期/时间更改为当前日期/时间(即“现在”),那么您可以在该目录中创建某种临时文件,向其中写入一些内容,然后立即将其删除。这具有将目录的“lastModified()”日期/时间更改为当前日期/时间的效果。但是,如果您想将目录日期/时间更改为其他一些随机值,并且显然不能应用于文件,这将不起作用。