Получить дату последнего изменения файла с помощью MILLISECONDS?

Я пытаюсь получить дату и время (последнее изменение) некоторых файлов из папки. Мне удалось получить дату и часы/минуты/секунды, но я не могу получить миллисекунды.

Я уже пробовал форматировать столбец всеми возможными способами. Я получаю только 0 за миллисекунды.

Мой код до сих пор:

  • пользователь выбирает папку

  • код отображает в столбце A все найденные имена файлов, а в столбце B - дату, часы, минуты и секунды (дата/время последнего изменения)

Что мне делать с текущим кодом, чтобы получить миллисекунды?

Это мой код:

Private Function GetAllFiles(ByVal strPath As String, _
    ByVal intRow As Integer, ByRef objFSO As Object) As Integer
    Dim objFolder As Object
    Dim objFile As Object
    Dim i As Integer
    i = intRow - ROW_FIRST + 1
    Set objFolder = objFSO.GetFolder(strPath)
    For Each objFile In objFolder.Files
        'print file name
        Cells(i + ROW_FIRST + 2, 1) = objFile.Name
        'print file path
        Cells(i + ROW_FIRST + 2, 2) = objFile.DateLastModified
        i = i + 1
    Next objFile
    GetAllFiles = i + ROW_FIRST - 1
End Function

person MisterA    schedule 04.04.2018    source источник
comment
Ваша файловая система FAT или NTFS?   -  person ashleedawg    schedule 04.04.2018
comment
нтфс, виндовс 7, 64 бита   -  person MisterA    schedule 04.04.2018
comment
хорошо, я тоже. Я составлю ответ... но могу я сначала спросить, что вы планируете с этим делать и почему вам требуется такой уровень детализации? (Кроме того, тип VBA Date имеет разрешение только 1 секунду, поэтому ему придется использовать другой тип данных.) То, как вы собираетесь его использовать, может повлиять на ответ.   -  person ashleedawg    schedule 04.04.2018
comment
Короче говоря, речь идет о сортировке отсканированных или разделенных документов (pdf). Я уже сделал код переименования и все. Проблема в том, что когда я разбиваю PDF-файл на 100 страниц, это будут части 1, 2, 3, 4, 5 и так далее. Vba получает дату последнего изменения и сортирует после нее. Только он не может их правильно отсортировать, если они имеют одинаковое время и секунды создания. Так что мне нужны миллисекунды (проводник правильно их сортирует). Я бы нашел другие решения (извлечение числа из части 1 2 3), но этот код будет сортировать другие виды pdf со сканера и т. д., и отображение миллисекунд будет идеальным.   -  person MisterA    schedule 04.04.2018
comment
Мой английский далек от совершенства. Итак, vba читает содержимое папки. Получает в excel дату последнего изменения файлов из папки. Сортирует их после даты чч, мм, сс. С этого момента другая часть vba берет на себя вставку из другой таблицы новых имен для этих файлов. Новые имена уже размещены в порядке отсканированных документов или в том порядке, в котором они отображаются в разбитом PDF-файле. Порядок должен соответствовать.   -  person MisterA    schedule 04.04.2018
comment
ну ладно, какое-то странное требование. Вы правы, извлечь число из имени файла было бы гораздо проще (1 строка кода вместо 100). Но вы видели миллисекунды? Откуда вы знаете, что Windows сортирует по этому?   -  person ashleedawg    schedule 04.04.2018
comment
пойдем поболтаем   -  person ashleedawg    schedule 04.04.2018
comment
Давайте продолжим обсуждение в чате.   -  person ashleedawg    schedule 04.04.2018
comment
Похоже на проблему XY. Я не думаю, что получение времени в миллисекундном масштабе является надежным решением вашей проблемы.   -  person John Coleman    schedule 04.04.2018


Ответы (1)


Следующий модуль извлечет создание файла Windows, изменение или доступ к дате и времени, включая миллисекунды, с помощью вызова Windows API.

Однако следует отметить, что существует ряд потенциальных проблем. Большой из них заключается в том, что тип данных VBA Date имеет разрешение 1 секунду, поэтому дату и время необходимо возвращать в виде строки или сохранять в другом типе данных (Currency — правильный размер).

Option Explicit

Declare Function GetFileTime Lib "kernel32.dll" (ByVal hFile As Long, _
    lpCreationTime As FILETIME, lpLastAccessTime As FILETIME, _
    lpLastWriteTime As FILETIME) As Long

Declare Function CreateFile Lib "kernel32.dll" Alias "CreateFileA" _
    (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, _
    ByVal dwShareMode As Long, lpSecurityAttributes As Any, _
    ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, _
    ByVal hTemplateFile As Long) As Long

Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long

Declare Function FileTimeToSystemTime Lib "kernel32.dll" _
    (lpFileTime As FILETIME, lpSystemTime As SYSTEMTIME) As Long

Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type

Type SYSTEMTIME
wYear As Integer
wMonth As Integer
wDayOfWeek As Integer
wDay As Integer
wHour As Integer
wMinute As Integer
wSecond As Integer
wMilliseconds As Integer
End Type


Const GENERIC_READ = &H80000000
Const GENERIC_WRITE = &H40000000
Const FILE_SHARE_READ = &H1
Const FILE_SHARE_WRITE = &H2
Const CREATE_ALWAYS = 2
Const CREATE_NEW = 1
Const OPEN_ALWAYS = 4
Const OPEN_EXISTING = 3
Const TRUNCATE_EXISTING = 5
Const FILE_ATTRIBUTE_ARCHIVE = &H20
Const FILE_ATTRIBUTE_HIDDEN = &H2
Const FILE_ATTRIBUTE_NORMAL = &H80
Const FILE_ATTRIBUTE_READONLY = &H1
Const FILE_ATTRIBUTE_SYSTEM = &H4
Const FILE_FLAG_DELETE_ON_CLOSE = &H4000000
Const FILE_FLAG_NO_BUFFERING = &H20000000
Const FILE_FLAG_OVERLAPPED = &H40000000
Const FILE_FLAG_POSIX_SEMANTICS = &H1000000
Const FILE_FLAG_RANDOM_ACCESS = &H10000000
Const FILE_FLAG_SEQUENTIAL_SCAN = &H8000000
Const FILE_FLAG_WRITE_THROUGH = &H80000000

Function GetDateValue(fName As String) As String
'returns UTC (GMT) file time for specified file

    Dim hFile As Long ' handle to the opened file
    Dim ctime As FILETIME ' receives time of creation
    Dim atime As FILETIME ' receives time of last access
    Dim mtime As FILETIME ' receives time of last modification
    Dim Thetime As SYSTEMTIME ' used to manipulate the time
    Dim retval As Long ' return value

    hFile = CreateFile(fName, GENERIC_READ, FILE_SHARE_READ, _
        ByVal CLng(0), OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, 0)

    retval = GetFileTime(hFile, ctime, atime, mtime)

    'Choose which date to return: creation, modify or access date
    'retval = FileTimeToSystemTime(ctime, Thetime) 'extract creation datetime
    retval = FileTimeToSystemTime(mtime, Thetime) 'extract modified datetime
    'retval = FileTimeToSystemTime(atime, Thetime) 'extract accessed datetime

    retval = CloseHandle(hFile)

    With Thetime
        GetDateValue = .wYear & Format(.wMonth, "\-00") & _
            Format(.wDay, "\-00") & " " & Format(.wHour, "00") & _
            Format(.wMinute, "\:00") & Format(.wSecond, "\:00") & _
            Format(.wSecond, "\.000")
    End With
End Function

Sub test()
    MsgBox GetDateValue("c:\logfile.txt") 
    'returns a string like "2018-03-31 16:13:52.052"
End Sub

Я просто вставляю это здесь, это не идеально, но работает и может быть настроено в соответствии с вашими индивидуальными потребностями. Обратите внимание, что вам нужно вручную раскомментировать строку для какой даты и времени, которую вы хотите вернуть функцией.

Обязательно прочитайте, прежде чем использовать это для чего-то важного, потому что существуют ограничения, зависящие от вашей файловой системы и многого другого. Например, NTFS часто заканчивает запись файла после того, как вы «думаете», что он закончен ... до 1 часа позже.


Больше информации:

person ashleedawg    schedule 04.04.2018
comment
WSeconds используется вместо wMiliseconds - person Markos; 12.07.2019