Форум программистов, компьютерный форум CyberForum.ru

Максимально эфективное бинарное чтение из файла под Windows - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 17, средняя оценка - 5.00
Gepar
 Аватар для Gepar
1173 / 529 / 20
Регистрация: 01.07.2009
Сообщений: 3,512
14.12.2012, 02:50     Максимально эфективное бинарное чтение из файла под Windows #1
Задача: максимально эфективно (быстро) читать данные из файла. Каким это будет происходить образом - в виде си функции, с++ или винапи функции не имеет значения, имеет значение лишь результат.
Как мне известно размер странички в Windows = 4Кб так что быстрее всего по идее чтение должно происходить если читать по 4 кб, но как лучше всего это сделать?

Вообще в итоге я буду использоать 64битные значения после того как считаю кусок файла. Вот мой маленький набросок, который првда закончился фиаско потому что стандартная fread, как оказалось, имеет буфер под чтение меньше 4 кб так что нужно что-то другое быстрое
C++
1
2
3
4
5
6
7
    FILE* readFrom = fopen("input.bin","rb"); _ASSERT(readFrom);
    uint64_t bufferRead[64];//мой буффер на 4 кб
    size_t countBlocks;//считано блоков
 
        // вернёт 0 потому что fread не может считать 4096 байтиков
    countBlocks = fread(bufferRead,1,4096,readFrom);
    fclose(readFrom);
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
14.12.2012, 02:50     Максимально эфективное бинарное чтение из файла под Windows
Посмотрите здесь:

Бинарное чтение из файла с пoмощью функции fread() C++
Бинарное считывание с файла и бинарный вывод. C++
C++ как может корректно выполняющийся оператор >> (чтение из текстового файла) негативно влиять на открытие другого файла?
Чтение из файла. Повторное чтение файла C++
Найти сумму максимально отрицательного и максимально положительного элемента массива C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Vourhey
Почетный модератор
6468 / 2243 / 123
Регистрация: 29.07.2006
Сообщений: 12,635
14.12.2012, 03:24     Максимально эфективное бинарное чтение из файла под Windows #21
Gepar, потому что вызывать много раз операцию чтения с диска не даст никакого прироста к производительности.
Еще хорошо бы установить флаг FILE_FLAG_SEQUENTIAL_SCAN, чтобы упреждающее чтение работало лучше. Это тоже даст прирост.

Добавлено через 3 минуты
Gepar, и, конечно, это зависит от самого диска и и оси. Поэтому говорить, что 4к - это самый быстрый вариант - ошибка. Бери больше, и проверяй, а не верь плохим программистам.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Gepar
 Аватар для Gepar
1173 / 529 / 20
Регистрация: 01.07.2009
Сообщений: 3,512
14.12.2012, 03:24  [ТС]     Максимально эфективное бинарное чтение из файла под Windows #22
Ну ... если хапать по n мб то как тогда узнать сколько там оп свободно (чтобы при чтении не перестараться и не привести к перекачке данных в своп) ?
Vourhey
Почетный модератор
6468 / 2243 / 123
Регистрация: 29.07.2006
Сообщений: 12,635
14.12.2012, 03:29     Максимально эфективное бинарное чтение из файла под Windows #23
Цитата Сообщение от Gepar Посмотреть сообщение
то как тогда узнать сколько там оп свободно
Зачем узнавать? Компы с объемом меньше 1 гига уже редкость. А буфер в метр еще в своп никого не загонял.
MrGluck
Ворчун
Эксперт С++
 Аватар для MrGluck
4922 / 2665 / 243
Регистрация: 29.11.2010
Сообщений: 7,420
14.12.2012, 03:38     Максимально эфективное бинарное чтение из файла под Windows #24
Gepar, я к тому сказал, что память сейчас оперативная взлетает в объемах по експоненте и беспокоится о её нехватке бесмысленно.
Вот, что я предлагаю:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <stdlib.h>
 
int main(void)
{
    FILE* pFile;
    pFile = fopen ("test.txt" , "rb");
    if (pFile == NULL) exit(1);
    fseek (pFile , 0 , SEEK_END);
    unsigned long long size = ftell (pFile); // не знаю, существует ли он в С
    rewind (pFile);
    char *buf = (char *) malloc(sizeof(char) * size);
    if (buf == NULL) exit(2);
    size_t result = fread (buf, 1, size, pFile);
    if (result != size) exit (3);
    //printf("%s", buf);
    free(buf);
    fclose(pFile);
    return 0;
}
Добавлено через 3 минуты
Мегабайтный файл считывает за 0.004 секунды (на моем компе естественно)
activnaya
 Аватар для activnaya
255 / 45 / 2
Регистрация: 24.11.2012
Сообщений: 466
14.12.2012, 03:48     Максимально эфективное бинарное чтение из файла под Windows #25
Цитата Сообщение от Gepar Посмотреть сообщение
Vourhey, ну проаргументируй, тема то интересная.
можно я? какая скорость чтения с HDD и какая из RAM? Что мешает загружать в RAM по гигу или 2 и обрабатывать данные из оперативной памяти? Странный конечно подход... по 4Кб.
Цитата Сообщение от Gepar Посмотреть сообщение
MrGluck, ну блин, предлагаешь сразу хапонуть 2 гб в оперативе, пошифровать их там (использовав ещё + 100 мб) и потом записать?
очевидно же.
MrGluck
Ворчун
Эксперт С++
 Аватар для MrGluck
4922 / 2665 / 243
Регистрация: 29.11.2010
Сообщений: 7,420
14.12.2012, 04:04     Максимально эфективное бинарное чтение из файла под Windows #26
И я уж молчу про http://help.3l.com/3L/index.html?threads_thread_h.htm из С11
WhiteP
605 / 203 / 23
Регистрация: 20.11.2012
Сообщений: 419
14.12.2012, 09:50     Максимально эфективное бинарное чтение из файла под Windows #27
Самое эффективное - читать функцией ReadFile (winapi) большими блоками (>= 64 кб) с флагом FILE_FLAG_NO_BUFFERING. Это чтобы не было 100500 промежуточных буферов, как в случае с функами с и с++. Если время обработки довольно большое, то имеет смысл читать асинхронно и обрабатывать покусочно по мере поступения.
Gepar
 Аватар для Gepar
1173 / 529 / 20
Регистрация: 01.07.2009
Сообщений: 3,512
14.12.2012, 15:50  [ТС]     Максимально эфективное бинарное чтение из файла под Windows #28
WhiteP, а можно небольшой пример чтения ею бинарных данных (с правильным получением хендлера файла для этой функции), допустим для файла input.bin и буффера на 64 кб uint64_t[8192] ну и соответственно с получением информации сколько реально байт было считано (ато она я смотрю просто BOOL возвращает).
WhiteP
605 / 203 / 23
Регистрация: 20.11.2012
Сообщений: 419
14.12.2012, 17:32     Максимально эфективное бинарное чтение из файла под Windows #29
Вот как-то так. Естественно, чтобы был прирост скорости - нужно избавиться от частых вызовов тормозных потоков C++ (std::cout). Тут они только для наглядности.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <windows.h>
 
#define BUFSIZE 65536 //должен быть кратен размеру сектора (обычно 512, точнее - GetDiskFreeSpace)
 
int main()
{
    //буфер должен быть выровнен по границе сектора. VirtualAlloc выравнивает начало буфера
    //автоматически по адресу кратному 64.
    BYTE * pBuf = (PBYTE)VirtualAlloc(NULL, BUFSIZE, MEM_COMMIT, PAGE_READWRITE);
 
    if(!pBuf)
    {
        std::cout<<"VirtualAlloc error. Code: "<<GetLastError()<<std::endl;
        return -1;
    }
 
    std::cout<<"Memory successfully allocated. Address: "<<(int)pBuf<<std::endl;
        
    HANDLE hFile = CreateFileW(L"c:\\input.bin", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_NO_BUFFERING, 0);
    
    if(hFile == INVALID_HANDLE_VALUE)
    {
        std::cout<<"CreateFile error. Code: "<<GetLastError()<<std::endl;
        VirtualFree(pBuf, BUFSIZE, MEM_RELEASE);
        return -1;
    }
 
    std::cout<<"File successfully opened. Start reading."<<std::endl;
 
    DWORD readed = 0, fSize = 0, step = 1;
    BOOL isOk = 0;
 
    //двигать файловый указатель можно только по границам секторов!
    while(isOk = ReadFile(hFile, pBuf, BUFSIZE, &readed, 0))
    {
        std::cout<<"Step "<<step++<<". Readed bytes: "<<readed<<std::endl;
        fSize+=readed;
        if(readed < BUFSIZE)
            break;
    }
    if(isOk == FALSE)
        std::cout<<GetLastError()<<std::endl;
 
    std::cout<<" Total readed bytes: "<<fSize<<". FileSize is "<<GetFileSize(hFile, 0)<<std::endl;  
 
    CloseHandle(hFile);
    VirtualFree(pBuf, BUFSIZE, MEM_RELEASE);
 
    return 0;
}
Gepar
 Аватар для Gepar
1173 / 529 / 20
Регистрация: 01.07.2009
Сообщений: 3,512
17.12.2012, 01:13  [ТС]     Максимально эфективное бинарное чтение из файла под Windows #30
WhiteP, не получается у меня использовать этот твой винапи вариант - почему-то WriteFile нифига не пишет и чесно признаётся что записывает каждый раз 0 байт. Какого хрена оно так ?
Вот код где я его использую, вот почему он каждый раз нифигашеньки не запсывает WriteFile этот
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#define BUFSIZE 65536 //должен быть кратен размеру сектора (обычно 512, точнее - GetDiskFreeSpace)
 
void CryptoSaveFastHelper(Cryptographer* crypto,CryptoMode mode, uint64_t* keys, char* from, char* to)
{
    //буфер должен быть выровнен по границе сектора. VirtualAlloc выравнивает начало буфера
    //автоматически по адресу кратному 64.
    uint64_t * pBuf = (uint64_t*)VirtualAlloc(NULL, BUFSIZE, MEM_COMMIT, PAGE_READWRITE);
 
    if(!pBuf)
    {
        std::cout<<"VirtualAlloc error. Code: "<<GetLastError()<<std::endl;
        throw -1;
    }
 
    int* key; //ключ (и)
 
    //uint64_t bufferRead[512];//мой буффер на 4 кб
    uint64_t lastBlock = 0ULL;//последний блок который нужно будет дописать в конец файла
 
    HANDLE inputData = CreateFile(from, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_NO_BUFFERING|FILE_FLAG_SEQUENTIAL_SCAN, 0);
    HANDLE outputData = CreateFile(to, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL|FILE_FLAG_NO_BUFFERING, 0);
 
    DWORD readed = 0;//сколько байт считано
    DWORD writed = 0;//сколько байт записано
    BOOL isOk = 0;
 
    switch(mode)
    {
    case _DESEBC:
        {
            while(isOk = ReadFile(inputData, pBuf, BUFSIZE, &readed, 0))
            {
                //шифруем считанные блоки
                crypto->EnCrypt(pBuf,readed/8);
 
                _ASSERT(WriteFile(outputData,pBuf,readed-(readed%8),&writed,0)==0);//отрабатывает без ошибок, но нифига не пишеет!
                if(readed < BUFSIZE)
                    break;
            }
 
            //если число байтиков в файле делилось на 4 без остатка
            if(!(readed % 8))
            {
                lastBlock = crypto->EnCrypt(lastBlock);
                WriteFile(outputData,&lastBlock,(DWORD)8,&writed,0);
            }
            else//иначе добиваем нолями предпоследний а в последний пишем размер
            {
                lastBlock = readed%8;
                lastBlock = crypto->EnCrypt(lastBlock);
                char* ptr = (char*)(pBuf+(readed/8));
                ptr += (readed%8);
                for(int i=0;i<8-(readed%8); i++)
                    *ptr++=0;
 
                pBuf[(readed/8)] = crypto->EnCrypt(pBuf[(readed/8)]);
 
                WriteFile(outputData,&pBuf[readed/8],(DWORD)8,&writed,0);
                WriteFile(outputData,&lastBlock,(DWORD)8,&writed,0);
            }
        }
        break;
    }
    CloseHandle(inputData);
    CloseHandle(outputData);
}
ValeryS
Модератор
6376 / 4842 / 442
Регистрация: 14.02.2011
Сообщений: 16,045
17.12.2012, 01:24     Максимально эфективное бинарное чтение из файла под Windows #31
Gepar, если тебе нужна скорость, то почему ты не задействуешь файлы проецируемые в память
грубо говоря создается копия файла в озу
ты работаешь с этой копией (скорость обращения к памяти намного больше чем к винту) точно так же как с файлом
потом при закрытии он скидывается на диск

Добавлено через 3 минуты
вот вроде неплохая статейка
http://www.developing.ru/com/memory_..._files_01.html
Gepar
 Аватар для Gepar
1173 / 529 / 20
Регистрация: 01.07.2009
Сообщений: 3,512
17.12.2012, 01:47  [ТС]     Максимально эфективное бинарное чтение из файла под Windows #32
ValeryS, я почитаю сейчас, но почему WriteFile может писать по 0 байт? Не, ну хотябы мусор там какой-то писала или ещё чего, а так файл получается в 0 байт независимо от того сколько я пытался писать ею, почему же?
*Вообще я смотрю 98% времени таки тратиться на шифрование, даже если читать по 4 кб максимум так что я думаю на чтении файла не стоит совсем сильно заострять внимание, чтение через винапи функции без буферизации должно быть достаточно, но нужно исправить эту багу с WriteFile ...
ValeryS
Модератор
6376 / 4842 / 442
Регистрация: 14.02.2011
Сообщений: 16,045
17.12.2012, 02:22     Максимально эфективное бинарное чтение из файла под Windows #33
Цитата Сообщение от Gepar Посмотреть сообщение
но почему WriteFile может писать по 0 байт?
не может
это значит какая то ошибка при записи вызывай GetLastError.
http://vsokovikov.narod.ru/New_MSDN_..._writefile.htm
особенно посмотри раздел Замечания

Добавлено через 4 минуты
я кстати в коде не нашел проверки outputData
файл ведь может не открыться
Gepar
 Аватар для Gepar
1173 / 529 / 20
Регистрация: 01.07.2009
Сообщений: 3,512
17.12.2012, 03:00  [ТС]     Максимально эфективное бинарное чтение из файла под Windows #34
Цитата Сообщение от ValeryS Посмотреть сообщение
это значит какая то ошибка при записи вызывай GetLastError.
Отдаёт код 57 после записи файла (до записи 0, те ошибка была при записи). Как определить что произошло, я уже позабывал эти винапишные штучки, там вроде что-то было для этого.

Добавлено через 44 секунды
Цитата Сообщение от ValeryS Посмотреть сообщение
я кстати в коде не нашел проверки outputData
файл ведь может не открыться
Оно бы вываливалось тогда при записи, файл открывается, я в отладчике просто смотрел что хендлер получен корректный.
activnaya
 Аватар для activnaya
255 / 45 / 2
Регистрация: 24.11.2012
Сообщений: 466
17.12.2012, 03:09     Максимально эфективное бинарное чтение из файла под Windows #35
Цитата Сообщение от Gepar Посмотреть сообщение
Как определить что произошло
исключения же
ValeryS
Модератор
6376 / 4842 / 442
Регистрация: 14.02.2011
Сообщений: 16,045
17.12.2012, 03:14     Максимально эфективное бинарное чтение из файла под Windows #36
Цитата Сообщение от Gepar Посмотреть сообщение
Как определить что произошло,
Примерно так
C++
1
2
 if(!(WriteFile(outputData,&pBuf[readed/8],(DWORD)8,&writed,0))
      GetLastError();
потом в меню (в студии) сервис - поиск ошибки набиваешь номер и читаешь расшифровку

Цитата Сообщение от Gepar Посмотреть сообщение
Отдаёт код 57 после записи файла
аппаратная неисправность сетевой платы
а вот 0х57 уже ближе
Параметр задан неверно.
WhiteP
605 / 203 / 23
Регистрация: 20.11.2012
Сообщений: 419
17.12.2012, 08:20     Максимально эфективное бинарное чтение из файла под Windows #37
При записи файла, открытого с флагом FILE_FLAG_NO_BUFFERING нужно писать также как и читать - размером кратным размеру сектора (512 байт). Буфер для записи нужно выровнять (выделить память VirtualAlloc). В конце (если размер выходного файла не кратен 512) нужно вызвать SetEndOfFile. Имеет смысл формировать буфер как можно больший - т.к. чем меньше обращений к диску, тем лучше. Минимум, если размер файла позвоялет - 64Кб.
При чтении файлов с флагом FILE_FLAG_NO_BUFFERING и чтении файла через проекцию (FileMapping) - скорость первого примерно на 15%-30% выше.
Писать возможно и правда лучше и удобней в проецируемый файл.
Gepar
 Аватар для Gepar
1173 / 529 / 20
Регистрация: 01.07.2009
Сообщений: 3,512
17.12.2012, 12:27  [ТС]     Максимально эфективное бинарное чтение из файла под Windows #38
Цитата Сообщение от WhiteP Посмотреть сообщение
При записи файла, открытого с флагом FILE_FLAG_NO_BUFFERING нужно писать также как и читать - размером кратным размеру сектора (512 байт).
Так я же так и делаю - я записываю тот буфер полностью, те 64 кб, но после той записи в DWORD writed по прежнему 0, но почему ? Или оно не скинеться на диск пока я не вызову SetEndOfFile? Но тогда где оно держит по 50 мб которые я пытался шифровать, не в оп же, я же смотрел что моё приложение так много оп не жрёт. Можешь ещё раз посмотреть на мой код, может заметишь что не так. Вроде же всё просто: считал в буфер 64 кб, записал их в файл, если считал меньше 64 кб - поредактировал последний блок и снова записал в файл. По крайней мере первые же записи что по полных 64 кб должны писаться, но я отладчиком гоняю и writed постоянно = 0 и не меняется. Столько проблем с десом этим
ValeryS
Модератор
6376 / 4842 / 442
Регистрация: 14.02.2011
Сообщений: 16,045
17.12.2012, 14:31     Максимально эфективное бинарное чтение из файла под Windows #39
Цитата Сообщение от Gepar Посмотреть сообщение
я записываю тот буфер полностью, те 64 кб,
чей то я не увидел
Цитата Сообщение от Gepar Посмотреть сообщение
WriteFile(outputData,&lastBlock,(DWORD)8,&writed,0);
8 байт
64 кб это все таки 65536
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
17.12.2012, 14:45     Максимально эфективное бинарное чтение из файла под Windows
Еще ссылки по теме:

Преобразование текстового файла в двоичный и чтение исходных данных из двоичного файла. C++
Соединение двух программ в одну (бинарное сложение и бинарное сравнение) C++
C++ Считать из файла целочисленный массив C[N] и сформировать из него максимально возможную матрицу А [n x n]

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
WhiteP
605 / 203 / 23
Регистрация: 20.11.2012
Сообщений: 419
17.12.2012, 14:45     Максимально эфективное бинарное чтение из файла под Windows #40
C++
1
_ASSERT(WriteFile(outputData,pBuf,readed-(readed%8),&writed,0)==0);//отрабатывает без ошибок, но нифига не пишеет!
Если размер файла меньше 512 байт, например, то писать и не будет. Последний блок также может не записаться и в других случаях, т.к. не все то, что кратно 8 кратно 512.
Тут надо
C
1
2
#define ALIGN_UP(x, align) ((x)+((align)-1))&(~((align)-1))
WriteFile(outputData,pBuf,ALIGN_UP(readed, 512),&writed,0)
Запустил в студии вот такой код. Файл скопировался без проблем.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    
    HANDLE hFile = CreateFileW(L"c:\\input.bin", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_NO_BUFFERING, 0);
 
    HANDLE hOutFile = CreateFileW(L"d:\\out.bin", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_NO_BUFFERING, 0);
...
while(isOk = ReadFile(hFile, pBuf, BUFSIZE, &readed, 0))
    {
        //std::cout<<"Step "<<step++<<". Readed bytes: "<<readed<<std::endl;
        fSize+=readed;
 
        //WriteFile(hOutFile, pBuf, (ALIGN_UP(readed, 512)),&written, NULL);
        std::cout << written <<"bytes writed."<<std::endl;
 
        if(readed < BUFSIZE)
            break;
    }
Yandex
Объявления
17.12.2012, 14:45     Максимально эфективное бинарное чтение из файла под Windows
Ответ Создать тему
Опции темы

Текущее время: 17:04. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru