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

Подсчет строк в гигантском текстовом файле > 4 Гб - C++

Восстановить пароль Регистрация
 
jkchief
0 / 0 / 0
Регистрация: 19.02.2013
Сообщений: 8
19.02.2013, 01:25     Подсчет строк в гигантском текстовом файле > 4 Гб #1
Всем привет, я новичок в С++, но очень стараюсь. Прочитал Дейтелов и теперь хочу сделать что-то практическое и полезное.

Сам занимаюсь этическим хакингом , есть небольшая практическая цель - написать прогу, которая бы обьединяла N текстовых файлов - словарей для брутфорса в один гигантский, при этом бы сортировала слова и удаляла повторяющиеся. И при этом бы не жрала память.

Начало было положено с написания кода, который выполнял подсчет строк в файле с помощью std::getline(), но к сожалению гетлайн не подходит для работы с большими файлами, и считает долго. Гигантский файл в память не загрузишь.

Второй итерацией был написан код, представленный чуть ниже, в нем использовал принцим File memory mapping. И чтение файла ведется порциями по 1 МБ.
Написано в VS2012 С++.
Все работает чудесно, но уперся в ограничение 32 битов unsigned long.... обрабатывает файлы до 4 гб.
А у меня на винте лежит словарик в 24 Гб....хотелось бы его посчитать.
Подскажите ответ на 2 вопроса:
1) можно ли побороть проблемму на 32 битной системе
2) куда копать чтобы реализовать на 64 битах?

Реально первая прога, которую написал не по учебнику, был бы также рад услышать конструктивную критику если заметите признаки говнокода.
Код:
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include "stdafx.h"
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
using std::cerr;
#include <string>
using std::string;
#include <fstream>
using std::ifstream;
#include <Windows.h>
 
 
string man = "This is programm to count number of lines in text file.\nTo use program type:\ncounter.exe \"filename\"\n\n";
static int numlines=1;
DWORD BUFFERSIZE = 1048576;//buffer size for memory mapping. 1 Mb by default. You can change it to play with performance.
HANDLE hMapFile;      // handle for the file's memory-mapped region
HANDLE hFile;         // the file handle
DWORD dwFileSize;     // temporary storage for file sizes
LPVOID lpMapAddress;  // pointer to the base address of the memory-mapped region
SYSTEM_INFO SysInfo;  // system information; used to get granularity
DWORD dwSysGran;      // system allocation granularity
char * pData;         // pointer to the data
DWORD dwi=0;          // loop counter
BOOL bFlag;           // a result holder
DWORD dwMapViewSize;  // number of bytes to map
DWORD dwCurrentPosition; //position where to start mapping of the file
DWORD dwIterationTimes; //number of iterations to mat the file to the memory
DWORD dwFileMapSize;   // size of the file mapping
 
 
 
int _tmain(int argc, _TCHAR* argv[])
{
    //we accept only one file name
    if (argc != 2 ){cout << man; 
    exit(1);}
     _tprintf(TEXT("Open file \"%s\" for line counting.\n"), argv[1]);
 
// Open the file 
  hFile = CreateFile(argv[1],
                     GENERIC_READ,
                     0,
                     NULL,
                     OPEN_EXISTING,
                     FILE_ATTRIBUTE_NORMAL,
                     NULL);
 
  if (hFile == INVALID_HANDLE_VALUE)
  {_tprintf(TEXT("Target file \"%s\" does not exist. Try to check spelling.\n"), argv[1]);
    exit(1);};
 
 
    //Now we will count some variables ************************************
    //Gety file size.
    dwFileSize = GetFileSize(hFile,  NULL);
    _tprintf(TEXT("File size is: %3d bites\n"), dwFileSize); 
 
    // Get the system allocation granularity.
    GetSystemInfo(&SysInfo);
    dwSysGran = SysInfo.dwAllocationGranularity;
    //_tprintf(TEXT("system allocation granularity is: %d\n"), dwSysGran);
 
    //Calculate number iterations to read all file maps
    
    if (dwFileSize <= BUFFERSIZE) {dwIterationTimes = 1;};
            if (dwFileSize > BUFFERSIZE) {
                DWORD dba = dwFileSize % BUFFERSIZE ;
                if ( dba == 0)  {dwIterationTimes = dwFileSize / BUFFERSIZE;};
                if (dba > 0)  {dwIterationTimes = (dwFileSize / BUFFERSIZE)+1;};
            };
        //_tprintf(TEXT("Iterations: %3d\n"), dwIterationTimes);
 
 
        // now we count some changing variables for cycle
        for  (DWORD c=0 ; c < dwIterationTimes; c=c+1 ) {
                //Count file mapping size and wiev size size for NOT last itteration
                if (c < dwIterationTimes-1){
                    dwMapViewSize=BUFFERSIZE;
                    dwFileMapSize = (c * BUFFERSIZE)  + BUFFERSIZE; //file mapping size
                    //_tprintf (TEXT("The middle file mapping object is %ld bytes large for %ld itteration\n"),dwFileMapSize, c+1);
                    };
 
                ///Count file mapping size and wiev size for last itteration itteration
                if (c == dwIterationTimes-1){
                    DWORD d = (dwFileSize - (c * BUFFERSIZE));//length of last part (less than buffersize)
                    //_tprintf (TEXT("Current offset is %ld, Length of last part of file is %ld \n"),(c * BUFFERSIZE), d);
                    dwMapViewSize = d;
                    dwFileMapSize = dwFileSize;
                    //_tprintf (TEXT("The LAST file mapping object is %ld bytes large for %ld itteration\n"),dwFileMapSize, c+1);
                };//if it is last operation we do not need to allocate all buffer size
        
        
                // Create a file mapping object for the file
                hMapFile = CreateFileMapping( hFile,          // current file handle
                    NULL,           // default security
                    PAGE_READONLY,  // read permission
                    0,              // size of mapping object, high
                    dwFileMapSize,  // size of mapping object, low
                    NULL);          // name of mapping object
                //That it is a good idea to ensure the file size is not zero
                if (hMapFile == NULL)
                    {
                    _tprintf(TEXT("hMapFile is NULL\n"));
                    exit(2);
                    };
 
                // Map the view and test the results.       
                lpMapAddress = MapViewOfFile(hMapFile,            // handle to mapping object
                               FILE_MAP_READ,       // read/write
                               0,                   // high-order 32 bits of file offset
                               (c * BUFFERSIZE),    // low-order 32 bits of file offset
                               dwMapViewSize);      
                if (lpMapAddress == NULL)
                {
                _tprintf(TEXT("lpMapAddress is NULL: last error: %d\n"), GetLastError());
                exit(1);
                }
                else {
                //  _tprintf(TEXT("lpMapAddress is: %d\n"), lpMapAddress);
                };
 
 
                //pointer to the data.
                pData = (char *) lpMapAddress ;
 
                // At last!!! Data processing.************************************************* 
  
                for (dwi=0; dwi < dwMapViewSize ; dwi=dwi+1) {
                if (pData[dwi] == '\n'){numlines++;};
                };
                
 
                // Close the file mapping object and the open file
                 bFlag = UnmapViewOfFile(lpMapAddress);
                 bFlag = CloseHandle(hMapFile); // close the file mapping object
                 if(!bFlag) { _tprintf(TEXT("\nError %ld occurred closing the mapping object!"), GetLastError());}
 
        };//end of for
 
        bFlag = CloseHandle(hFile);   // close the file itself
        if(!bFlag) { _tprintf(TEXT("\nError %ld occurred closing the file!"), GetLastError());}
        
        
        cout << "Number of lines in our file is: " << numlines << endl;
    return 0;
}
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
19.02.2013, 01:25     Подсчет строк в гигантском текстовом файле > 4 Гб
Посмотрите здесь:

C++ Алгоритм поиска строк в текстовом файле
C++ Центрирование строк в текстовом файле
C++ Найти количество строк в текстовом файле
Подсчет символов пробелов и строк в файле C++
C++ Подсчет строк в файле
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 50
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
19.02.2013, 04:33     Подсчет строк в гигантском текстовом файле > 4 Гб #2
Есть ведь 64 битный тип long long int в новом стандарте. Так же есть тип std::size_t, который в 64 битной программе так же 64 битный.
WhiteP
605 / 203 / 23
Регистрация: 20.11.2012
Сообщений: 419
19.02.2013, 09:07     Подсчет строк в гигантском текстовом файле > 4 Гб #3
Цитата Сообщение от jkchief Посмотреть сообщение
1) можно ли побороть проблемму на 32 битной системе
// high-order 32 bits of file offset
в MapViewOfFile и соответствующие максимумы в CreateFileMapping для чего по твоему?
Нужно двигать отображение. Смапил кусок, обработал, анмап. Смапил следующий кусок, обработал, анмап.
И не нужно закрывать хэндл FileMappingObject'a каждую итерацию и создавать снова для одного и того же файла.
jkchief
0 / 0 / 0
Регистрация: 19.02.2013
Сообщений: 8
19.02.2013, 14:10  [ТС]     Подсчет строк в гигантском текстовом файле > 4 Гб #4
Цитата Сообщение от WhiteP Посмотреть сообщение
в MapViewOfFile и соответствующие максимумы в CreateFileMapping для чего по твоему?
Нужно двигать отображение. Смапил кусок, обработал, анмап. Смапил следующий кусок, обработал, анмап.
И не нужно закрывать хэндл FileMappingObject'a каждую итерацию и создавать снова для одного и того же файла.
Про хендл понял, вынесу за цикл, спасибо.
А вот с остальным как-то не очень.В мануалах и примерах не нашел пример использования... уж не забросайте помидорами.
Я не совсем понимаю как игратся с єтими
// size of mapping object, high
// size of mapping object, low

// high-order 32 bits of file offset
// low-order 32 bits of file offset

Какие мне DWORD значения в 32 битном приложении нужно подставить чтобы прочитать из файла размером > 40GB
Скажем, начиная с офсета в 42 949 672 960 B байта (40Gb) до 42 950 721 536 байта (40Gb + 1 Mb).


C++
1
2
3
4
5
6
7
8
9
10
11
12
hMapFile = CreateFileMapping( hFile,          // current file handle
                    NULL,           // default security
                    PAGE_READONLY,  // read permission
                    ??????,              // size of mapping object, high
                    ??????, // size of mapping object, low
                    NULL);          // name of mapping object
 
lpMapAddress = MapViewOfFile(hMapFile,            // handle to mapping object
                               FILE_MAP_READ,       // read/write
                               ??????,                   // high-order 32 bits of file offset
                               ??????// low-order 32 bits of file offset
                               dwMapViewSize);
WhiteP
605 / 203 / 23
Регистрация: 20.11.2012
Сообщений: 419
19.02.2013, 14:53     Подсчет строк в гигантском текстовом файле > 4 Гб #5
Ну вот. А вообще используй long long или int64
Миниатюры
Подсчет строк в гигантском текстовом файле > 4 Гб  
jkchief
0 / 0 / 0
Регистрация: 19.02.2013
Сообщений: 8
19.02.2013, 16:30  [ТС]     Подсчет строк в гигантском текстовом файле > 4 Гб #6
Ответ не до конца понятен.
CreateFileMapping и MapViewOfFile принимают значения DWORD. (typedef unsigded long DWORD)....32 бита на сколько я понимаю. Разве я могу скармливать им long long? Или мне нужно дополнительно какой-то функцией распарсить побитно long long на два DWORDа и скармливать отдельно старшую и младшую часть?

Тоесть применимо к моему вопросу будет ли работатьзначения подставленные ниже?

Есть ли вобще смысл заморачиватся и высчитывать CreateFileMapping размеры, я так понимаю можно подставить нули и смапится тогда весь файл.
Ведь эта функция не жрет память?
CreateFileMapping //
0 // size of mapping object, high
0 // size of mapping object, low


MapViewOfFile
10 // high-order 32 bits of file offset 0000 0000 0000 0000 0000 0000 0000 1010
0 // low-order 32 bits of file offset 0000 0000 0000 0000 0000 0000 0000 0000
1048576// number of bytes to map (1 MB)

Добавлено через 8 минут
А как получить размер большого файла для 32 бит приложения, или мне неменуемо нужно переезджать на 64?
WhiteP
605 / 203 / 23
Регистрация: 20.11.2012
Сообщений: 419
19.02.2013, 16:34     Подсчет строк в гигантском текстовом файле > 4 Гб #7
Цитата Сообщение от jkchief Посмотреть сообщение
дополнительно какой-то функцией распарсить побитно long long на два DWORDа и скармливать отдельно старшую и младшую часть?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <windows.h>
 
int main()
{
    __int64 x = 42949672960;
    DWORD low = (DWORD)x;
    DWORD high = (DWORD)(x>>32);
 
    std::cout<<x<<std::endl;
    std::cout<<low<<std::endl;
    std::cout<<high<<std::endl;
 
 
    return 0;
}
Добавлено через 3 минуты
Цитата Сообщение от jkchief Посмотреть сообщение
А как получить размер большого файла для 32 бит приложения, или мне неменуемо нужно переезджать на 64?
GetFileSize(обрати внимание на второй параметр)
http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx
jkchief
0 / 0 / 0
Регистрация: 19.02.2013
Сообщений: 8
20.02.2013, 13:09  [ТС]     Подсчет строк в гигантском текстовом файле > 4 Гб #8
Переделал все с учетом работы с большими файлами, намучался с этими типами данных...но теперь как-то криво работать начало. Вроде считает строки, но для разных размеров буфера памяти выдает разные результаты.
Для примера скормил словарь обьемом в 835Мб своей проге и сторонней, выдаются разные варианты.
Скорей всего логическая ошибка, помогите выявить.
Подсчет строк в гигантском текстовом файле > 4 Гб

Сам код вот какой теперь:

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include "stdafx.h"
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
using std::cerr;
#include <string>
using std::string;
#include <Windows.h>
#include <time.h>
 
 
string man = "This is programm to count number of lines in text file.\nTo use program type:\ncounter.exe \"filename\"\n\n";
static int numlines=1;
LARGE_INTEGER liBufferSize; //buffer size for memory mapping. 1 Mb by default. You can change it to play with performance.
HANDLE hMapFile;      // handle for the file's memory-mapped region
HANDLE hFile;         // the file handle
LARGE_INTEGER liFileSize; // temporary storage for file sizes for big files
LPVOID lpMapAddress;  // pointer to the base address of the memory-mapped region
SYSTEM_INFO SysInfo;  // system information; used to get granularity
DWORD dwSysGran;      // system allocation granularity
char * pData;         // pointer to the data
int inti=0;          // loop counter for data manipulation
BOOL bFlag;           // a result holder
int intIterationTimes; //number of iterations to mat the file to the memory
LARGE_INTEGER liMapViewSize;  // number of bytes to map
LARGE_INTEGER liOffset; //current position holder
 
 
 
int _tmain(int argc, _TCHAR* argv[])
{
    clock_t tStart = clock();
    liBufferSize.LowPart = 1048576;// 1 Mb by default. You can change it to play with performance.
    
    //we accept only one file name
    if (argc != 2 ){cout << man; 
    exit(1);}
     _tprintf(TEXT("Open file \"%s\" for line counting.\n"), argv[1]);
 
// Open the file 
  hFile = CreateFile(argv[1],
                     GENERIC_READ,
                     0,
                     NULL,
                     OPEN_EXISTING,
                     FILE_ATTRIBUTE_NORMAL,
                     NULL);
 
    if (hFile == INVALID_HANDLE_VALUE)
    {_tprintf(TEXT("Target file \"%s\" does not exist. Try to check spelling.\n"), argv[1]);
    exit(1);
    };
 
 
    //Now we will count some variables ************************************
    //Gety file size.
    GetFileSizeEx(hFile, &liFileSize);
    _tprintf(TEXT("File size is: %I64d bites\n"), liFileSize.QuadPart); 
    
    // Get the system allocation granularity.
    GetSystemInfo(&SysInfo);
    dwSysGran = SysInfo.dwAllocationGranularity;
    _tprintf(TEXT("system allocation granularity is: %d\n"), dwSysGran);
 
    //Calculate number iterations to read all file maps
    if (liFileSize.QuadPart <= liBufferSize.QuadPart) {intIterationTimes = 1;};
    if (liFileSize.QuadPart > liBufferSize.QuadPart) {
                LONGLONG dba = liFileSize.QuadPart % liBufferSize.QuadPart ;
                if ( dba == 0)  {intIterationTimes = (int)(liFileSize.QuadPart / liBufferSize.QuadPart);};
                if (dba > 0)  {intIterationTimes = (int)((liFileSize.QuadPart / liBufferSize.QuadPart)+1);};
    };
    _tprintf(TEXT("Iterations: %u \n"), intIterationTimes);
 
    // Create a file mapping object for the file
    hMapFile = CreateFileMapping( hFile,          // current file handle
            NULL,           // default security
            PAGE_READONLY,  // read permission
            (DWORD)liFileSize.HighPart,  // size of mapping object, high
            liFileSize.LowPart, // size of mapping object, low
            NULL);          // name of mapping object
    //That it is a good idea to ensure the file size is not zero
    if (hMapFile == NULL){
        _tprintf(TEXT("hMapFile is NULL\n"));
        exit(2);
    };
 
 
    // now we count some changing variables for cycle
    for  (int intc=0 ; intc < intIterationTimes; intc++ ) {
        //Count  map wiev size  for NOT last itteration
        if (intc < intIterationTimes-1){
            liMapViewSize.LowPart=liBufferSize.LowPart;
        //  _tprintf (TEXT("The middle file mapping view is %I64d bytes large for %i itteration\n"),liMapViewSize.QuadPart, (intc+1));
            };
 
        ///Count file wiev size and current offset for last itteration 
        if (intc == intIterationTimes-1){
            liMapViewSize.QuadPart = (liFileSize.QuadPart - (   (LONGLONG)intc * liBufferSize.QuadPart)  );//length of last part (less than liBufferSize)
            liOffset.QuadPart= (LONGLONG)intc * liBufferSize.QuadPart;
            _tprintf (TEXT("Current offset is %I64d, Length of last part of view is %I64d \n"),liOffset.QuadPart, liMapViewSize.QuadPart);
            };//if it is last operation we do not need to allocate all buffer size
        
 
        // Map the view and test the results.       
        lpMapAddress = MapViewOfFile(
                hMapFile,               // handle to mapping object
                FILE_MAP_READ,          // read/write
                liOffset.HighPart,      // high-order 32 bits of file offset
                liOffset.LowPart ,      // low-order 32 bits of file offset
                liMapViewSize.LowPart);  //length of the view    
        
        if (lpMapAddress == NULL){
            _tprintf(TEXT("lpMapAddress is NULL: last error: %d\n"), GetLastError());
            exit(1);}
        else {
            //_tprintf(TEXT("lpMapAddress is: %d\n"), lpMapAddress);
        };
 
 
        //pointer to the data.
        pData = (char *) lpMapAddress ;
 
        // At last!!! Data processing.************************************************* 
        for (inti=0; (DWORD)inti < liMapViewSize.LowPart ; inti++) {
                if (pData[inti] == '\n'){numlines++;};
                };
                
 
        // Close the file mapping object and the open file
         bFlag = UnmapViewOfFile(lpMapAddress);
                
    };//end of for
 
    bFlag = CloseHandle(hMapFile); // close the file mapping object
    if(!bFlag)  { _tprintf(TEXT("\nError %ld occurred closing the mapping object!"), GetLastError());}
    bFlag = CloseHandle(hFile);   // close the file itself
    if(!bFlag) { _tprintf(TEXT("\nError %ld occurred closing the file!"), GetLastError());}
        
    //now we cout the reults
    cout << "Number of lines in our file is: " << numlines << endl;
    printf("Time taken: %.2fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC);
 
    return 0;
}
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
20.02.2013, 14:45     Подсчет строк в гигантском текстовом файле > 4 Гб
Еще ссылки по теме:

Сделать подсчет частоты встречаемости последовательности символов АБВ в текстовом файле C++
C++ Подсчет количества строк в файле в С++ (fstream)
C++ Подсчет количества символов русского алфавита в текстовом файле

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

Или воспользуйтесь поиском по форуму:
jkchief
0 / 0 / 0
Регистрация: 19.02.2013
Сообщений: 8
20.02.2013, 14:45  [ТС]     Подсчет строк в гигантском текстовом файле > 4 Гб #9
Все, сам нашел, забыл вставить вычисление офсета для всех непоследних итерраций... строки считались постоянно для нулевого офсета
Yandex
Объявления
20.02.2013, 14:45     Подсчет строк в гигантском текстовом файле > 4 Гб
Ответ Создать тему
Опции темы

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