如何获取 Java 资源的最后修改时间?

Posted

技术标签:

【中文标题】如何获取 Java 资源的最后修改时间?【英文标题】:How do I get the last modification time of a Java resource? 【发布时间】:2011-01-04 16:01:38 【问题描述】:

谁能告诉我一个可靠的方法来获取 Java 资源的最后修改时间?资源可以是文件或 JAR 中的条目。

【问题讨论】:

我什至不知道 JAR 中可能有时间戳,但鉴于它就像 ZIP,我并不完全感到惊讶。很有趣。 @Amigable Clark Kant - 只是一个注释,但 JAR 格式将在 Java 7 中得到更新,因此关于它是 ZIP 文件的假设可能不再成立。 Java 8 中仍然存在 :) 【参考方案1】:

如果你用“资源”表示可以通过 Class#getResource 或 ClassLoader#getResource 访问的东西,你可以通过 URLConnection 获取最后修改的时间戳:

URL url = Test.class.getResource("/org/jdom/Attribute.class");
System.out.println(new Date(url.openConnection().getLastModified()));

请注意,如果上次修改时间未知,getLastModified() 将返回 0,遗憾的是,这与读取“1970 年 1 月 1 日 0:00 UTC”的真实时间戳无法区分。

【讨论】:

适用于 Swing,但不适用于 android。在 Android 中,我总是得到 0,尽管可访问的 jarfile 有一个非零的最后修改日期。 @j4nbur53:您正在编译的 JAR 文件?那个在运行时不可用。不知道时间戳是否保留在 Android APK 文件中。即使语言相似,Android 运行时与 Java 运行时也有很大不同。 Android 上的 APK 文件也是一个 JAR 文件,您可以通过简单的 getResource() 调用获取条目的 URL。但是 Android 上的实现不同于 Swing 上的实现。 JarURLConnection 没有通过委托给底层 jar 文件来实现 getHeader() ,因此最终它在 Android 上不起作用。 (可以检查两个来源并找出实现的差异) "不幸的是,这无法与真正的时间戳区分开来" 除非您有一些 非常 旧文件放在周围,否则我认为很难区分真正的最后一个-修改日期和 1970 年 1 月 1 日 :) @jarnbjo 是的。但在实践中,这很少成为问题。不过有一个优势......这个神奇的 EPOCH 日期允许我在我不想提供个人详细信息的网站上填写 1/1/1970 作为生日,安全地知道在数据库中只有 @987654323 的值@ :)【参考方案2】:

url.openConnection().getLastModified() 的问题在于 FileURLConnection 上的getLastModified() 为该文件创建了一个 InputStream。因此,您必须在获得最后修改日期后致电urlConnection.getInputStream().close()。相反,JarURLConnection 在调用 getInputStream() 时创建输入流。

【讨论】:

那么让它打开或调用 getinputstream 然后关闭哪个更优化? @nullsector76 让流保持打开状态总是会导致资源泄漏。只能使用不打开任何流的api进行优化。【参考方案3】:

Apache Commons VFS 提供了一种与from different sources 文件交互的通用方式。 FileObject.getContent() 返回一个 FileContent 对象,该对象具有 retreiving the last modified time 的方法。

这是来自VFS website 的修改示例:

import org.apache.commons.vfs.FileSystemManager;
import org.apache.commons.vfs.FileObject;
...
FileSystemManager fsManager = VFS.getManager();
FileObject jarFile = fsManager.resolveFile( "jar:lib/aJarFile.jar" );
System.out.println( jarFile.getName().getBaseName() + " " + jarFile.getContent().getLastModifiedTime() );

// List the children of the Jar file
FileObject[] children = jarFile.getChildren();
System.out.println( "Children of " + jarFile.getName().getURI() );
for ( int i = 0; i < children.length; i++ )

    System.out.println( children[ i ].getName().getBaseName() + " " + children[ i ].getContent().getLastModifiedTime());

【讨论】:

听起来过于复杂。我最后使用了 java zip api,然后使用了最后修改的。我还对它们进行了迭代,然后比较了修改后的罐子中最有可能未修改的邮票。【参考方案4】:

我目前正在使用以下解决方案。解决方案是 与最初步骤中的大多数其他解决方案一样,即 一些 getResource(),然后是 openConnection()。

但是当我有连接时,我使用以下代码:

/**
 * <p>Retrieve the last modified date of the connection.</p>
 *
 * @param con The connection.
 * @return The last modified date.
 * @throws IOException Shit happens.
 */
private static long getLastModified(URLConnection con) throws IOException 
    if (con instanceof JarURLConnection) 
        return ((JarURLConnection)con).getJarEntry().getTime();
     else 
        return con.getLastModified();
    

上面的代码适用于安卓和非安卓,它返回 如果资源是,则 ZIP 内条目的最后修改日期 在档案中找到,否则它返回它从中获得的内容 连接。

再见

P.S.:代码还需要刷一些,有一些边框 getJarEntry() 为空的情况。

【讨论】:

【参考方案5】:

这是我获取 JAR 文件或编译类的最后修改时间的代码(使用 IDE 时)。

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.attribute.FileTime;
import java.text.DateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Locale;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

public class ProgramBuildTime

    private static String getJarName()
    
        Class<?> currentClass = getCurrentClass();
        return new File(currentClass.getProtectionDomain()
                .getCodeSource()
                .getLocation()
                .getPath())
                .getName();
    

    private static Class<?> getCurrentClass()
    
        return new Object() .getClass().getEnclosingClass();
    

    private static boolean runningFromJAR()
    
        String jarName = getJarName();
        return jarName.endsWith(".jar");
    

    public static String getLastModifiedDate() throws IOException, URISyntaxException
    
        Date date;

        if (runningFromJAR())
        
            String jarFilePath = getJarName();
            try (JarFile jarFile = new JarFile(jarFilePath))
            
                long lastModifiedDate = 0;

                for (Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements(); )
                
                    String element = entries.nextElement().toString();
                    ZipEntry entry = jarFile.getEntry(element);
                    FileTime fileTime = entry.getLastModifiedTime();
                    long time = fileTime.toMillis();

                    if (time > lastModifiedDate)
                    
                        lastModifiedDate = time;
                    
                

                date = new Date(lastModifiedDate);
            
         else
        
            Class<?> currentClass = getCurrentClass();
            URL resource = currentClass.getResource(currentClass.getSimpleName() + ".class");

            switch (resource.getProtocol())
            
                case "file":
                    date = new Date(new File(resource.toURI()).lastModified());
                    break;

                default:
                    throw new IllegalStateException("No matching protocol found!");
            
        

        DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US);
        return dateFormat.format(date);
    

【讨论】:

以上是关于如何获取 Java 资源的最后修改时间?的主要内容,如果未能解决你的问题,请参考以下文章

如何在文件系统中获取最后修改的日期和时间?

如何获取文件最后在 Python 中修改的时间? [复制]

java 如何获得一个文件夹的创建时间 具体点

如何在Filesystem中获取最后修改日期和时间?

如何获取联系人列表的最后修改日期(添加/删除/修改)

获取文件最后修改日期(资源管理器值不是 cmd 值)