Для определения размера файла в VB6 существует встроенная функция FileLen. Она возвращает длину файла в байтах (тип Long). Таким образом, максимальный размер файла, который может определить эта функция - 2 Гб, так как для переменной типа Long это максимально допустимое значение. При попытке передать в функцию путь к файлу большего, чем 2 Гб, размера, возвращается ошибка (-1). Как же получает размеры таких файлов ОС Windows? Она пользуется при этом функциями GetFileSize и GetFileSizeEx. Рассмотрим более удобную для нас функцию GetFileSizeEx. На языке C она объявляется так:
BOOL GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER lpFileSize);
Здесь lpFileSize - это указатель на объединение (Union) ULARGE_INTEGER, которое может представлять собой либо одно 64-битовое целое число, либо пользовательский тип, состоящий из двух 32-битовых переменных. Так как компилятор VB6 не поддерживает объединения, а также 64-битовые целые числа, выберем последний вариант.
Type ULARGE_INTEGER
LowPart As Long
HighPart As Long
End Type
Declare Function GetFileSizeEx Lib "kernel32" ( _
ByVal hFile As Long, lpFileSize As ULARGE_INTEGER) As Long
Открыть файл для чтения и получить его дескриптор можно с помощью великолепной функции CreateFile:
Declare Function CreateFile Lib "kernel32" _
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
Const OPEN_EXISTING = 3&
Const INVALID_HANDLE_VALUE = -1
Функция GetFileSizeEx в случае, если ей передан верный дескриптор, заполнит структуру ULARGE_INTEGER, но нам от этого не легче. Нас интересует численное значение размера файла. Как же нам прочитать его из невразумительной двухчастной структуры? К счастью, в VB6 есть тип данных Currency. Размер такой переменной как раз 8 байт, и этот тип поддерживает арифметические операции. Копируя 8 байт из ULARGE_INTEGER в переменную типа Currency с помощью функции CopyMemory, мы сможем прочитать размер файла в байтах (функция CopyMemory описана в статье LOWORD и HIWORD). Следует учесть, что Currency - это число с фиксированной запятой с точностью 4 знака, поэтому результат нужно будет умножить на 10000.
Напишем функцию для определения размера большого файла (разумеется, она будет работать и с маленькими):
Public Function GetBigFileSize(ByVal FilePath As String) As Currency
Dim uli As ULARGE_INTEGER, hFile As Long
Dim retVal As Currency, lret As Long
hFile = CreateFile(FilePath, 0&, 0&, ByVal 0&, _
OPEN_EXISTING, 0&, 0&)
If hFile = INVALID_HANDLE_VALUE Then
retVal = -1@
GoTo retLine
End If
lret = GetFileSizeEx(hFile, uli)
If hFile <> INVALID_HANDLE_VALUE Then CloseHandle hFile
If lret = 0 Then
retVal = -1@
GoTo retLine
End If
CopyMemory ByVal VarPtr(retVal), ByVal VarPtr(uli), 8
retVal = retVal * 10000
retLine:
GetBigFileSize = retVal
End Function
P. S. У некоторых снобов от программирования считается недостаточно изящным применение оператора GoTo. Цзяофани - люди простые, от земли, и они не гнушаются использовать этот удобный оператор. Представьте, насколько более непонятным сделался бы код вышеприведённой функции без него!
Автор - Цзяофань
|