OPEN, PUT, GET при работе с файлами более 2-х гигов

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
Glyckmen
Обычный пользователь
Обычный пользователь
 
Сообщения: 72
Зарегистрирован: 30.04.2006 (Вс) 15:32
Откуда: Санкт-Петербург

OPEN, PUT, GET при работе с файлами более 2-х гигов

Сообщение Glyckmen » 03.10.2006 (Вт) 9:32

Есть программа которая читает файл с диска по блокам (блок небольшого размера и выбирается пользователем от 1Кб до 1 Мб) далее происходит работа с этим блоком и потом запись в другой файл и так до тех пор пока весь исходный файл не будет обработан, я в программе использую для чтения и записи OPEN Binary и соответственно операторы PUT и GET с указанием позиции по байту. Так вот не будет ли проблем при обработке таким способом большого файла (более 2-х гигов, до сих пор файлы были меньше, а тут попался большой файл), переменные для определения позиции соответственно я буду использовать Currency или все-же надо будет использовать API функции (например ReadFile и WriteFile со структурой OVERLAPPED), не хотелось-бы переделывать, а то очень уж много чего надо менять. :(
Зарание Спассибо!

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Сообщение Viper » 03.10.2006 (Вт) 9:48

По идее номер читаемого/записываемого байта определяется значением типа Long, посему боюсь ничего не получиться

З.Ы. Сам не проверял, истиной в последней инстанции прошу сей пост не считать

поправлена опечатка, Приношу всем извинения за введение в заблуждение этой опечаткой.
Последний раз редактировалось Viper 03.10.2006 (Вт) 13:12, всего редактировалось 1 раз.
Весь мир матрица, а мы в нем потоки байтов!

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 03.10.2006 (Вт) 10:09

Таки-да, ReadFile и WriteFile. Только OVERLAPPED не при чём.
Изображение

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Сообщение Antonariy » 03.10.2006 (Вт) 10:10

!Viper!, причем тут номер файла?
переменные для определения позиции соответственно я буду использовать Currency
Эээ... максимальное значение Currency 922,337,203,685,477.5807 - это примерно 858993 тб. Сомневаюсь, что даже такие хранилища существуют, не то что файлы.
Лучший способ понять что-то самому — объяснить это другому.

Glyckmen
Обычный пользователь
Обычный пользователь
 
Сообщения: 72
Зарегистрирован: 30.04.2006 (Вс) 15:32
Откуда: Санкт-Петербург

Сообщение Glyckmen » 03.10.2006 (Вт) 11:04

!Viper! писал(а):По идее номер читаемого/записываемого файла определяется значением типа Long, посему боюсь ничего не получиться

А мне нужен не номер файла, я работаю с двумя файлами( первый это чтение из файла, а второй запись в файл), а нужен номер байта в файле, так вот пройдет ли такой код:
Код: Выделить всё
' Здесь переменные pos as Currency, dlFile as Currency
'filebytes1 -это динамический массив, размерность массива равна переменной sizebuffer, тип массива Byte
'Длинну файла получаю с помощью API функции
'Declare Function GetFileSizeEx Lib "kernel32" (ByVal hFile As Long, lpFileSizeHigh As Currensy) As Long
'вызов GetFileSizeEx fPointer,dlFile
'Отрывок кода востановления первоночальных данных
sizebuffer = 32768 'Устанавливаем значение буфера
        GetFileSizeEx fPointer,dlFile
        dlFile =dlFile - 128 'Отбрасываем свой заголовок и получаем истинный размер оригинала
        ProgressBar1.Max = dlFile ' Устанавливаем прогресс
        If dlFile < sizebuffer Then sizebuffer = dlFile 'Если длинна файла меньше чем буфер
        ReDim filebytes1(sizebuffer - 1)
pos=1
filenum = FreeFile
        Open out_File For Binary Access Read As filenum
            filenum1 = FreeFile
            Open out_patch + ffi1 For Binary Access Write As filenum1
                Do
                    DoEvents 'На всякий случай что-бы не зависало
           
                    Get #filenum, pos + 128, filebytes1 ' читаем из файла
                   '... Здесь произвожу работу с прочтенными данными
                    Put #filenum1, pos, filebytes1 ' Записываю работу в другой файл
                    pos = pos + sizebuffer ' Устанавливаем следующую порцию из файла
           
                    If pos < dlFile Then ProgressBar1.Value = pos ' Заполняем прогресс
           
                    ' Вычисляем прошедшее время
                    EndTime = Timer
                    sek = EndTime - StartTime: sek2 = sek
                    chas = Int(sek / 3600): min = Int(sek / 60) - (chas * 60)
                    sek = sek - (chas * 60 + min) * 60
                    Form8.Label5.Caption = Format(Str$(chas) + ":" + Str$(min) + ":" + Str$(sek), "hh:mm:ss")
                    'Вычисляем оставшееся время
                    If (dlFile / pos) > 10 Then
                        Form8.Label7.Caption = "Время вычисляется."
                    Else
                        If vvn >= 8 Then
                            sek1 = Int((dlFile / pos) * sek2): sek1 = sek1 - sek2
                            chas1 = Int(sek1 / 3600): min1 = Int(sek1 / 60) - (chas1 * 60)
                            sek1 = sek1 - (chas1 * 60 + min1) * 60: vvn = 0
                            Form8.Label7.Caption = Format(Str$(chas1) + ":" + Str$(min1) + ":" + Str$(sek1), "hh:mm:ss")
                        Else
                            vvn = vvn + 1 ' Что-бы цыфры времени не слишком бысро обновлялись делаем небольшую задержку
                        End If
                    End If
           
                    If sto = 1 Then ' Если была нажата кнопка отмена
                        If MsgBox("Прервать выполнение?", vbQuestion + vbYesNo, "Внимание.") = vbYes Then
                            Close filenum1 ' Закрываем файл для записи
                            Close filenum 'Закрываем файл для чтения
                            Kill out_patch + ffi1 ' Удаляем незавершенный файл
                            Unload Me   ' Выгружаемся
                            Exit Sub
                        End If
                    End If
                Loop Until (pos + sizebuffer) > dlFile ' Если подошли к концу файла то выходим из цыкла
                If pos = dlFile + 1 Then GoTo en ' Если все-же был достигнут конец файла то завершаемся
                sizebuffer = dlFile - pos ' Изменяем буфер равный остатку
                ReDim filebytes1(sizebuffer) ' Изменяем массив
                Get #filenum, pos + 128, filebytes1 ' Читаем остатки
                '... Здесь произвожу работу с прочтенными данными
                Put #filenum1, pos, filebytes1 ' Записываем остатки
en:
            Close filenum1 ' Все закрываем
        Close filenum


Не хотелось бы полностью менять, таких похожих кодов в программе около десятка.
Во блин пока писал еще ответы появились.

tyomitch писал(а):Таки-да, ReadFile и WriteFile. Только OVERLAPPED не при чём.
Не совсем согласен, при асихронном вводе-выводе используется структура OVERLAPPED, определяющая точку начала чтения, хотя это можно заменить на API функцию SetFilePointer которая так-же устанавливает начальную точку чтения.

Antonariy писал(а): максимальное значение Currency 922,337,203,685,477.5807 - это примерно 858993 тб. Сомневаюсь, что даже такие хранилища существуют, не то что файлы.
Хорошо тогда подскажи мне тип переменной в VB6 который можно использовать для работы с файлами более 2-х Гб

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Сообщение Antonariy » 03.10.2006 (Вт) 11:07

:scratch: А Currency недостаточно?
Лучший способ понять что-то самому — объяснить это другому.

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 03.10.2006 (Вт) 11:16

Glyckmen писал(а):
tyomitch писал(а):Таки-да, ReadFile и WriteFile. Только OVERLAPPED не при чём.
Не совсем согласен, при асихронном вводе-выводе используется структура OVERLAPPED, определяющая точку начала чтения

Асинхронность-то зачем?
Изображение

Glyckmen
Обычный пользователь
Обычный пользователь
 
Сообщения: 72
Зарегистрирован: 30.04.2006 (Вс) 15:32
Откуда: Санкт-Петербург

Сообщение Glyckmen » 03.10.2006 (Вт) 12:10

tyomitch В примере что выше у меня чтение идет со смещением в 128 байт и мне надо сначала установить указатель на 129-й байт, а уже потом читать по порядку (синхронно), с записью там все в синхронном режиме с первого байта. Или есть другие предложения для чтения со 129-го байта без структуры или без функции SetFilePointer ? (Предвижу ответ: сначала прочитать первые 128 байт и указатель сам встанет на нужное место.)

Antonariy
А Currency недостаточно?
А я знаю что его с лихвой хватит, но только ты своим выражением
Antonariy писал(а):Сомневаюсь, что даже такие хранилища существуют, не то что файлы.
Подверг сомнению мой выбор Currency, вот я и написал что может быть есть другой тип о котором я и не догадывался.

Но все-же хочется услышать конкретный ответ PUT и GET будут работать или нет с файлами более 2-х Гб? (Сам проверить не могу, сейчас нет таких файлов на рабочем компе)

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Сообщение Antonariy » 03.10.2006 (Вт) 12:31

Put и Get это обертки для соответствующих апишек, так что по идее должны.
Лучший способ понять что-то самому — объяснить это другому.

Glyckmen
Обычный пользователь
Обычный пользователь
 
Сообщения: 72
Зарегистрирован: 30.04.2006 (Вс) 15:32
Откуда: Санкт-Петербург

Сообщение Glyckmen » 03.10.2006 (Вт) 13:08

Ладно сейчас в программе изменю тип данных, а дома испытаю, после чего отпишусь получилось или нет.

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 03.10.2006 (Вт) 13:18

Antonariy писал(а):Put и Get это обертки для соответствующих апишек, так что по идее должны.

Если в обертке параметр имеет тип Long, то больше Long он получить (а затем и передать) не сможет.
Правда я не проверял практикой. Но мне кажется, что в Get/Put действительно Long.
Lasciate ogni speranza, voi ch'entrate.

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Сообщение Viper » 03.10.2006 (Вт) 13:33

В Get/Put на самом деле Variant, но из справки следует, что в качестве аргумента предполагается именно Long. Так что навряд ли там Currency можно использовать.

З.Ы. В первый мой пост в этом топике закралась очень неприятная опечатка, естественно, имелся ввиду номер байта, а не файла.
Весь мир матрица, а мы в нем потоки байтов!

Glyckmen
Обычный пользователь
Обычный пользователь
 
Сообщения: 72
Зарегистрирован: 30.04.2006 (Вс) 15:32
Откуда: Санкт-Петербург

Сообщение Glyckmen » 03.10.2006 (Вт) 15:27

Только что проверил (пришлось заархивировать пол винчестера что-бы получить файл размером около 3 гб :lol: ), так вот все идет нормально пока позиция соответствует размеру LONG, как только номер позиции в файле превышает 2147483647 вылетает ошибка "63 Bad record number" (Неверный номер записи ), а вот прогрессбар съел размер (хоть это радует), ну ладно буду переделывать на API ReadFile и WriteFile :( ,хотя ох как не хочется.
Все вопрос закрыт!

Glyckmen
Обычный пользователь
Обычный пользователь
 
Сообщения: 72
Зарегистрирован: 30.04.2006 (Вс) 15:32
Откуда: Санкт-Петербург

Сообщение Glyckmen » 04.10.2006 (Ср) 12:27

Вот вчера мучался с функциями API которые заменют PUT и GET, и решил открыть вопрос по поводу использования функций ReadFile и WriteFile.
Проблема в том что функции ReadFile и WriteFile выдают ошибку несоответствия типов (пытаюсь прочитать из файла в байтовый массив) для наглядности привожу код с которым у меня ничего не получается:

Код модуля:
Код: Выделить всё

'*******************Объявление функция для работы с файлами******************
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
Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Any) As Long
Declare Function SetFilePointer Lib "kernel32" (ByVal hFile As Long, ByVal lDistanceToMove As Long, lpDistanceToMoveHigh As Long, ByVal dwMoveMethod As Long) As Long
Declare Function GetFileSizeEx Lib "kernel32" (ByVal hFile As Long, lpFileSizeHigh As Currency) As Long
Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As Any) As Long

'************************Объявление констант для работы с файлами**********
Public Const GENERIC_READ = &H80000000
Public Const GENERIC_WRITE = &H40000000
Public Const FILE_SHARE_READ = &H1
Public Const FILE_SHARE_WRITE = &H2
Public Const CREATE_NEW = 1
Public Const CREATE_ALWAYS = 2
Public Const OPEN_ALWAYS = 4
Public Const OPEN_EXISTING = 3
Public Const TRUNCATE_EXISTING = 5
Public Const FILE_ATTRIBUTE_ARCHIVE = &H20
Public Const FILE_ATTRIBUTE_HIDDEN = &H2
Public Const FILE_ATTRIBUTE_NORMAL = &H80
Public Const FILE_ATTRIBUTE_READONLY = &H1
Public Const FILE_ATTRIBUTE_SYSTEM = &H4
Public Const FILE_FLAG_DELETE_ON_CLOSE = &H4000000
Public Const FILE_FLAG_NO_BUFFERING = &H20000000

А теперь код формы:
Код: Выделить всё

'В начале процедуры объявляются все необходимые переменные для работы
Dim filebytes1() As Byte 'Динамический массив
hFile = CreateFile(out_File, GENERIC_READ, FILE_SHARE_READ, ByVal CLng(0), OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, 0)
        If hFile = -1 Then
            MsgBox "Немогу открыть файл.", vbCritical + vbOKOnly, "Ошибка!"
        Exit Sub  ' Выход из процедуры
        End If
        GetFileSizeEx hFile, dlFile 'Определяем размер файла
        dlFile = dlFile * 10000 'Сдвигаем запятую
        ProgressBar1.Max = dlFile 'Устанавливаем прогресс
        If dlFile < sizebuffer Then sizebuffer = dlFile 'Если буфер больше чем длинна файла то приравниваем буфер длинне
        ReDim filebytes1(sizebuffer - 1) 'Изменяем размер массива
        If SfxCrypt = True Then 'Устанавливаем имя получаемого файла
            writfil = out_patch + ffi2 + ".exe"
        Else
            writfil = out_patch + ffi2 + ".crc"
        End If

        'Открываем файл для записи (файл уже создан)
        hFile1 = CreateFile(writfil, GENERIC_WRITE, FILE_SHARE_READ, ByVal CLng(0), CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, ByVal CLng(0))
         SetFilePointer hFile1, 0, highbyte, FILE_END 'Устанавливаем указатель в конец получаемого файла (мы его будем дописывать)
                Do ' Начало цикла
                    DoEvents ' На всякий случай что-бы не зависало
                    retval = ReadFile(hFile, filebytes1, sizebuffer, numread, ByVal CLng(0)) ' Читаем часть файла в массив filebytes1
                    RC4 filebytes1, cod 'Шифруем часть файла
                    retval = WriteFile(hFile1, filebytes1, sizebuffer, numread, ByVal CLng(0)) 'Записываем зашифрованное в файл

' Дальше код не имеет значения


В этом коде происходит ошибка "Type mismatch" на строчке
Код: Выделить всё
retval = ReadFile(hFile, filebytes1, sizebuffer, numread, ByVal CLng(0)) ' Читаем часть файла в массив filebytes1
при этом выделяется слово filebytes1

При том что если я поменяю динамический массив на строковую переменную то все проходит нормально, но мне надо что-бы данные сразу читались в массив (лишние действия-лишние тормоза) оператор GET сразу читал в массив, а ReadFile не хочет, ругается на несоответствие типов. Подскажите как решить проблему?

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 04.10.2006 (Ср) 12:39

Массивы передаются не так. Пиши filebytes1(0) (или 1, какой у тебя там первый индекс?).
Lasciate ogni speranza, voi ch'entrate.

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Сообщение Viper » 04.10.2006 (Ср) 13:00

И вдогонку, а какой тип у остальных передаваемых в функцию значений?

З.Ы. Вместо ByVal CLng(0) лучше передавать ByVal 0&
Последний раз редактировалось Viper 04.10.2006 (Ср) 13:22, всего редактировалось 1 раз.
Весь мир матрица, а мы в нем потоки байтов!

Glyckmen
Обычный пользователь
Обычный пользователь
 
Сообщения: 72
Зарегистрирован: 30.04.2006 (Вс) 15:32
Откуда: Санкт-Петербург

Сообщение Glyckmen » 04.10.2006 (Ср) 14:06

!Viper! писал(а):И вдогонку, а какой тип у остальных передаваемых в функцию значений?
Остальные значения LONG
alibek Н-да я пробовал ставить просто скобки, но не догадался еще и указывать начальный индекс массива, короче я стормозил :oops:


И еще есть вопрос как разделить на старшие и младшие биты в типе Currensy например в числе 3 220 697 256 , это надо для функции SetFilePointer где в параметрах надо указывать lDistanceToMove
Младшее слово 64-битного числа, указывающее на число байт, на которое необходимо передвинуть указатель файла и lpDistanceToMoveHigh
Переменная, содержащаея старшее слово 64-битного числа, указывающее на число байт, на которое необходимо передвинуть указатель файла.

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 04.10.2006 (Ср) 16:03

Можно делать CopyMemory, либо в байтовый массив, либо в массив Long из двух элементов, либо в структуру типа такой:
Type QWORD
HiDWORD As Long
LoDWORD As Long
End Type

Можно и вовсе без API, выравниванием (LSet).
С помощью логических операций было бы правильнее, но есть сомнения. Во всяком случае And &hFFFFFFFF00000000 ты выполнить не сможешь.
Lasciate ogni speranza, voi ch'entrate.


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: Google-бот и гости: 62

    TopList