Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.97/35: Рейтинг темы: голосов - 35, средняя оценка - 4.97
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22

Скорость чтения csv с разных носителей

21.05.2020, 23:27. Показов 9957. Ответов 148
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день, джентльмены.
На днях набросал простой код поиска нужной строки в CSV-файле, см. под спойлером
Кликните здесь для просмотра всего текста
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
extern "C" __declspec(dllexport) LPXLOPER12  WINAPI FindInCSV(char *  arg1, char *  arg2, wchar_t *  arg3)
{
    LPXLOPER12 OperOut = new XLOPER12;
    OperOut->xltype = xltypeStr | xlbitDLLFree;
    OperOut->val.str = new XCHAR[32767 + 2]; //+1 под размер + 1 под нуль-терминатор
    OperOut->val.str[0] = 0;
    OperOut->val.str[1] = '\0';
    std::filebuf fb;
    if (fb.open(arg1, std::ios::in | std::ios::binary))
    {
        int x = 0;
        int lenStrOut = 0; //0й элемент - размер строки
        int lenArg3 = wcslen(arg3);
        bool overflow = false;
        std::string str;
        std::istream is(&fb);
        XCHAR* strTmp= OperOut->val.str + 1;
 
        while (is) 
        {
            std::getline(is, str);
            size_t found = str.find(arg2);
            if (found != std::string::npos)
            {
                x++;
                if (lenArg3 > 0 && x > 1)
                {
                    if (lenStrOut + lenArg3 > 32767) { overflow = true;  goto end_; }
                    wcscpy(strTmp + lenStrOut, arg3);
                    lenStrOut = lenStrOut + lenArg3;
 
                    if (lenStrOut + str.length() > 32767) { overflow = true;  goto end_; }
                    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str.c_str(), -1, strTmp + lenStrOut, str.length() + 1);
                    lenStrOut = lenStrOut + str.length();
                }
                else if (lenArg3 > 0)
                {
                    if (lenStrOut + str.length() > 32767) { overflow = true;  goto end_; }
                    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str.c_str(), -1, strTmp + lenStrOut, str.length() + 1);
                    lenStrOut = lenStrOut + str.length();
                }
                else
                {
                    if (lenStrOut + str.length() > 32767) { overflow = true;  goto end_; }
                    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str.c_str(), -1, strTmp + lenStrOut, str.length() + 1);
                    lenStrOut = lenStrOut + str.length();
                    goto end_ ;
                }
            };
        }
    end_:
        if (overflow) {
            wcscpy(strTmp, L"Qverflow. Max char 32767\0");
            OperOut->val.str[0] = 24;
        }
        else
        {
            OperOut->val.str[0] = lenStrOut;
        }
        fb.close();
    }
    return OperOut;
}

Сегодня протестировал работу на з-х накопителях:
HDD WDC WD10EACS-00ZJB0 (1000 ГБ, SATA-II)
HDD WDC WD5000AAKX-001CA0 (500 ГБ, 7200 RPM, SATA-III)
SSD KINGSTON SV300S37A120G (120 ГБ, SATA-III)

В итоге время обработки CSW-файла размером 1ГБ у всех примерно одинаковое, что стало для меня откровением. Я предполагал, что в данном коде узкое место скорость чтения с накопителя. Чем можно объяснить такой результат теста?
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
21.05.2020, 23:27
Ответы с готовыми решениями:

Скорость записи и чтения данных с разных источников - из реестра и Json
Всем привет. Возникла необходимость где то хранить данные приложения. Было выбрано два варианта: Реестр JSON Из какого...

Создание тестов на скорость чтения и скорость записи
Проблемка такая - пишу простенький тест на скорость записи и скорость чтения, локальных и съемных дисков. Как написать тесты вроде...

Так ли важна в реальной жизни скорость записи SSD, или смотреть надо только на скорость чтения, а на запись пофигу
https://www.citilink.ru/catalog/computers_and_notebooks/hdd/ssd_in/420250/ вот у него скорость записи низкая, но он самый популярный

148
Эксперт С++
 Аватар для Avazart
8489 / 6156 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
08.06.2020, 19:19
Студворк — интернет-сервис помощи студентам
Это очевидная вещь, говорящая еще раз что Ваш код не к черту.

Есть смысл дочитывать данные при обнаружении частичного совпадения, примерно так как я делал тут для реализации построчного чтения
0
Just Do It!
 Аватар для XLAT
4219 / 2680 / 656
Регистрация: 23.09.2014
Сообщений: 9,235
Записей в блоге: 3
08.06.2020, 19:56
поигрался ещё с тестом на предмет выкинуть char*

в 6-ом подтесте заменил на вектор
в 7-ом на стринг

причём в 7-ом хз на стандарт вот такое:
is.read((char*)str.data(), size);


зато результат зашкалил:


весь код:

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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
#include <string>
#include <vector>
#include <fstream>
#include <ctime>
#include <iostream>
#include <exception>
#include <stdio.h>
 
#include <windows.h>
 
#define LOG(v) std::cout << #v << " = " << v << "\n";
 
int FindInCSVansi(PCTSTR path, const char* findStr, bool multiLine,
                  bool NO_BUFFERING)
{   const DWORD  nNumberOfBytesToRead =
        33554432; //16777216;//8388608;//читаем в буфер байты
    char* notAlignBuf = new char[nNumberOfBytesToRead + 4096]; //буфер
    char* buf = notAlignBuf; //буфер
    if (size_t(buf) % 4096)
    {   buf += 4096 - (size_t(buf) %
                       4096);    //адрес принимающего буфера тоже должен быть выровнен по размеру сектора/страницы
    }
 
    char* notAlignBufBufWork = new
    char[nNumberOfBytesToRead + 4096 + 1]; //буфер Рабочий
    char* bufWork = notAlignBufBufWork; //буфер
    if (size_t(bufWork) % 4096)
    {   bufWork += 4096 - (size_t(bufWork) %
                           4096);    //адрес рабочего буфера тоже выровнял по размеру сектора/страницы
    }
 
    bufWork[0] = '\0';//добавим нуль-терминатор
    bufWork[nNumberOfBytesToRead] = '\0';//добавим нуль-терминатор
    char* find;// указатель для поиска
    size_t strCount = 1; //счетчик строк
    std::string strOut; //итоговая строка
    DWORD  dwBytesReadWork;
    DWORD findStatus = 0; //статус поиска
    ULONGLONG ignoreOffset=0; //для расчета холостых циклов
    bool ERR_HANDLE_EOF = false; //метка конца файла
 
// создаем события с автоматическим сбросом
    HANDLE hEndRead = CreateEvent(NULL, FALSE, FALSE, NULL);// дескриптор события
    if (hEndRead == NULL)
    {   return GetLastError();
    }
 
    _ULARGE_INTEGER
    ui; //Представляет 64-разрядное целое число без знака обединяя два 32-х разрядных
    ui.QuadPart = 0;
 
    OVERLAPPED
    ovl;   // структура управления асинхронным доступом к файлу// инициализируем структуру OVERLAPPED
    ovl.Offset = 0;         // младшая часть смещения равна 0
    ovl.OffsetHigh = 0;      // старшая часть смещения равна 0
    ovl.hEvent = hEndRead;   // событие для оповещения завершения чтения
 
// открываем файл для чтения
    HANDLE hFile = CreateFile(  // дескриптор файла
                       path,   // имя файла
                       GENERIC_READ,          // чтение из файла
                       FILE_SHARE_READ,       // совместный доступ к файлу
                       NULL,                  // защиты нет
                       OPEN_EXISTING,         // открываем существующий файл
                       FILE_FLAG_OVERLAPPED | (NO_BUFFERING ? FILE_FLAG_NO_BUFFERING :
                               FILE_FLAG_RANDOM_ACCESS),// асинхронный ввод//отключаем системный буфер
                       NULL                   // шаблона нет
                   );
// проверяем на успешное открытие
    if (hFile == INVALID_HANDLE_VALUE)
    {   CloseHandle(hEndRead);
        delete[] notAlignBuf;
        delete[] notAlignBufBufWork;
        return -1;
    }
// читаем данные из файла
    for (;;)
    {   DWORD  dwBytesRead;
        DWORD  dwError;
        find = buf; //буфер
        // читаем одну запись
        if (!ReadFile(
                    hFile,           // дескриптор файла
                    buf,             // адрес буфера, куда читаем данные
                    nNumberOfBytesToRead,// количество читаемых байтов
                    &dwBytesRead,    // количество прочитанных байтов
                    &ovl             // чтение асинхронное
                ))
        {   switch (dwError = GetLastError())// решаем что делать с кодом ошибки
            {       //эти ошибки смотрм после завершения асинхронной операции чтения, для возможности обработать рабочий буфер
                case ERROR_IO_PENDING:
                    {   break;    // асинхронный ввод-вывод все еще происходит // сделаем кое-что пока он идет
                    }
                case ERROR_HANDLE_EOF:
                    {   ERR_HANDLE_EOF = true;    // мы достигли конца файла читалкой ReadFile
                        break;
                    }
                default:
                    {   goto return1;    // другие ошибки
                    }
            }
        }
        //работаем асинхронно, выполняем код, пока ждем чтение с диска//
        if (ui.QuadPart !=
                ignoreOffset)//игнорируем первую итерацию и этерации прошедшие следующим буфером, когда нужно было вернутся в предыдущий буфер
        {   bufWork[dwBytesReadWork] = '\0';//добавим нуль-терминатор
            find = bufWork; //новый буфер
        go_1:
            char* strStart = bufWork;
            char* strEnd = NULL;
 
            if (findStatus == 0)//goFind
            {   find = strstr(find, findStr);
                if (find != NULL) //если нужная подстрока найдена
                {
 
                    for (strStart = find; strStart >= bufWork; strStart--)
                    {   if (*strStart == '\n')
                        {   break;    //если нашли начало строки
                        }
                    }
                    strStart++;
                    if (ui.QuadPart == nNumberOfBytesToRead
                            || strStart != bufWork)//если первый буфер или найдено начало строки
                    {   strEnd = strchr(find, '\n');
                        if (strEnd != NULL) //если нашли конец строки
                        {   strOut = strOut + std::string(strStart, strEnd - strStart + 1);
                            if (!multiLine)
                            {   goto return0;
                            }
                            else//поиск в следующей строке начинаем с конца предыдущей
                            {   find = strEnd++;
                                findStatus = 0;
                                goto go_1;
                            }
                        }
                        else//если конец строки в следующем буфере или конец файла
                        {   strOut = strOut + std::string(strStart);
                            findStatus = 1;
                        }
                    }
                    else //если начало строки не найдено и это не первый буфер смотрим предыдущий буфер
                    {   findStatus = 2;
                        ui.QuadPart -= nNumberOfBytesToRead * 3;
                        ignoreOffset = ui.QuadPart + nNumberOfBytesToRead;
                    }
                } //если нужная подстрока найдена
            }
            else if (findStatus == 1)//goBuf
            {   strEnd = strchr(find, '\n');
                if (strEnd != NULL) //если нашли конец строки
                {   strOut = strOut + std::string(find, strEnd - find+1);
                    findStatus = 0;
                    if (!multiLine)
                    {   goto return0;
                    }
                    else//поиск в следующей строке начинаем с конца предыдущей
                    {   find = strEnd++;
                        findStatus = 0;
                        goto go_1;
                    }
                }
                else//если конец строки в следующем буфере или конец файла
                {   strOut = strOut + std::string(find);
                }
            }
            else if (findStatus == 2)//goBackBuf
            {
 
                for (strStart = bufWork + dwBytesReadWork; strStart >= bufWork; strStart--)
                {   if (*strStart == '\n')
                    {   break;    //если нашли начало строки
                    }
                }
                strStart++;
                if (ui.QuadPart == nNumberOfBytesToRead
                        || strStart != bufWork)//если первый буфер или найдено начало строки
                {   find = strStart++;
                    findStatus = 1;
                    goto go_1;
                }
                else
                {   ui.QuadPart -= nNumberOfBytesToRead *
                                   3;//если начало строки не найдлено смотрим предыдущий буфер
                    ignoreOffset = ui.QuadPart + nNumberOfBytesToRead;
                }
 
            }
        }
        if (ERR_HANDLE_EOF)
        {   if (findStatus != 2) goto return0;
        }
        //работаем асинхронно, выполняем код, пока ждем чтение с диска//
 
        // ждем, пока завершится асинхронная операция чтения
        WaitForSingleObject(hEndRead, INFINITE);
 
        // проверим результат работы асинхронного чтения // если возникла проблема ...
        if (!GetOverlappedResult(hFile, &ovl, &dwBytesRead, FALSE))
        {   switch (dwError = GetLastError())// решаем что делать с кодом ошибки
            {   case ERROR_HANDLE_EOF:
                    {   if (findStatus != 2) goto return0;
                        break;//если конец файла. но мы должны вернутся найти начало строки.
                    }// мы достигли конца файла в ходе асинхронной операции
                default:
                    {   goto return1;    // другие ошибки
                    }
            }// конец процедуры switch (dwError = GetLastError())
        }
 
        //синхронно копируем данные из буфера в рабочий буфер, далее с ним работаем асинхронно
        memcpy(bufWork, buf, nNumberOfBytesToRead);
 
        // увеличиваем смещение в файле
        dwBytesReadWork = dwBytesRead;//кол-во считанных байт
        ui.QuadPart += nNumberOfBytesToRead; //добавляем смещение к указателю на файл
        ovl.Offset = ui.LowPart;// вносим смещение в младшее слово
        ovl.OffsetHigh = ui.HighPart;// вносим смещение в старшеее слово
    }
 
return0:
// закрываем дескрипторы, освобождаем память
    //std::cout << "String Find " << strOut;
    CloseHandle(hFile);
    CloseHandle(hEndRead);
    delete[] notAlignBuf;
    delete[] notAlignBufBufWork;
    return 0;
return1:
    CloseHandle(hFile);
    CloseHandle(hEndRead);
    delete[] notAlignBuf;
    delete[] notAlignBufBufWork;
    return -1;
}
 
const char* const NAMEFILE = "N1GB.txt";
 
///----------------------------------------------------------------------------|
/// Генератор файла большого размера.
///----------------------------------------------------------------------------:
void generator_testfile()
{   std::ifstream inf(NAMEFILE);
    if(inf.is_open())
    {   inf.close();
        std::cout << "file exist...\n\n";
        return;
    }
    inf.close();
    
    std::cout << "generator_testfile() work now...\n\n";
    std::ofstream f(NAMEFILE);
 
    const int N1GB = 1024*1024*4;
    const char* s =
        "qwerty1234567890qwerty1234567890qwerty1234567890qwerty1234567";
 
    for    (int i = 0; i < N1GB; i++)
    {   f << s << s << s << s << "\n";
    }
    f << "........................ASD123FGH456.........................\n";
    f.close();
}
 
int main()
{   setlocale(0, "");
    generator_testfile();
 
    clock_t t1;
 
    {   ///-------------------------------------|
        /// bedvit                              |
        ///-------------------------------------:
        std::cout << "1: ";/////////////////////////////////////////////////---1
        t1 = clock();
        int        x;
        if(x = FindInCSVansi("N1GB.txt", "ASD123FGH456", 0, 0))
        {
        }
        printf("bedvit                  : Time = %f\n\n",
               (clock() - t1 + .0) / CLOCKS_PER_SEC); // время отработки
    }
 
    {   ///-------------------------------------|
        /// bedvit                              |
        ///-------------------------------------:
        std::cout << "2: ...\n\n";//////////////////////////////////////////---2
    }
 
    {   std::cout << "3: ";////////////////////////////////////////////////---3!
        t1 = clock();
        std::ifstream is(NAMEFILE, std::ios::in | std::ios::binary);
        
        is.seekg (0, std::ios::end);
        size_t size = is.tellg()+1;
        is.seekg (0, std::ios::beg);
        
        char* p = new char[size];
        std::string s("ASD123FGH456");
        while (is)
        {   is.read(p, size);
 
            std::string str(std::move(p));
            size_t found = str.find(s);
            if (found != std::string::npos)
            {   std::cout << "Find OK: " << std::endl;
            };
        }
        printf("   read + Find             : Time = %f(школа)\n\n",
               (clock() - t1 + .0) / CLOCKS_PER_SEC); // время отработки
        is.close();
        delete[] p;
    }
 
    {   std::cout << "4: ";/////////////////////////////////////////////////---4
        t1 = clock();
        std::ifstream is(NAMEFILE, std::ios::in | std::ios::binary);
 
        is.seekg (0, std::ios::end);
        size_t size = is.tellg();
        is.seekg (0, std::ios::beg);
 
        char* p = new char[size];
        while (is)
        {   is.read(p, size);
        }
        printf("read(без поиска)        : Time = %f(школа)\n\n",
               (clock() - t1 + .0) / CLOCKS_PER_SEC); // время отработки
        is.close();
        delete[] p;
    }
 
    {   ///-------------------------------------|
        /// Небольшая школьная оптимизация!     |
        ///-------------------------------------:
        std::cout << "5: ";/////////////////////////////////////////////////---5
        t1 = clock();
        std::ifstream is(NAMEFILE);
        std::string str;
        str.reserve(1024);
        std::string s("ASD123FGH456");
        while(is)
        {   std::getline(is, str);
            size_t found = str.find(s);
            if (found != std::string::npos)
            {   std::cout << "Find OK: " << std::endl;
            };
        }
        printf("   getline + reserve(1024) : Time = %f(школа)\n\n",
               (clock() - t1 + .0) / CLOCKS_PER_SEC); // время отработки
        is.close();
    }
    
    {   std::cout << "6: ";/////////////////////////////////////////////////---6
        t1 = clock();
        std::ifstream is(NAMEFILE, std::ios::in | std::ios::binary);
        
        size_t size = 64000000;
        std::vector<char> v(size);
        
        std::string s("ASD123FGH456");
        std::streamoff offset = -s.size();
        
        while (is)
        {   is.read(&v[0], size);
            is.seekg (offset, std::ios::cur);
            
            std::string str(std::move(&v[0]));
            size_t found = str.find(s);
            if (found != std::string::npos)
            {   std::cout << "Find OK: ";
                std::cout << str.substr(found, s.size()) << std::endl;
            };
        }
        printf("   read + Find + seekg     : Time = %f(школа)\n\n",
               (clock() - t1 + .0) / CLOCKS_PER_SEC); // время отработки
        is.close();
    }
    
    {   std::cout << "7: ";/////////////////////////////////////////////////---7
        t1 = clock();
        std::ifstream is(NAMEFILE, std::ios::in | std::ios::binary);
        
        size_t size = 64000000;
        std::string str; str.assign(size, ' ');
        
        std::string s("ASD123FGH456");
        std::streamoff offset = -s.size();
        
        while (is)
        {   is.read((char*)str.data(), size);
            is.seekg (offset, std::ios::cur);
            
            size_t found = str.find(s);
            if (found != std::string::npos)
            {   std::cout << "Find OK: ";
                std::cout << str.substr(found, s.size()) << std::endl;
            };
        }
        printf("   read + Find + seekg     : Time = %f(школа)\n\n",
               (clock() - t1 + .0) / CLOCKS_PER_SEC); // время отработки
        is.close();
    }
 
    std::cout << "\n\n";
    system("pause");
    return 0;
}


но с вектором ещё не всё, можно выкинуть оттуда стринг ...
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
08.06.2020, 20:36  [ТС]
XLAT, протестировал ваш последний вариант. Тайминг лучше, но найденная строка не выводится, только строка для поиска.
Миниатюры
Скорость чтения csv с разных носителей  
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
08.06.2020, 20:38  [ТС]
А так не совсем корректно сравнивать. Ведь я формирую строку, причем она может начинаться в предыдущем буфере, а это время.
0
Just Do It!
 Аватар для XLAT
4219 / 2680 / 656
Регистрация: 23.09.2014
Сообщений: 9,235
Записей в блоге: 3
08.06.2020, 22:04
Цитата Сообщение от bedvit Посмотреть сообщение
А так не совсем корректно сравнивать
ну, я конеш подозревал что вы придеретесь по этому поводу,
поэтому уже морально был готов дописать эту часть.
заняло 10 минут,
но желательно написать для этой фичи специальный тест на границы,
я тестить не буду, так как я ленив.

весь код:

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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
#include <string>
#include <vector>
#include <fstream>
#include <ctime>
#include <iostream>
#include <exception>
#include <stdio.h>
 
#include <windows.h>
 
#define LOG(v) std::cout << #v << " = " << v << "\n";
 
int FindInCSVansi(PCTSTR path, const char* findStr, bool multiLine,
                  bool NO_BUFFERING)
{   const DWORD  nNumberOfBytesToRead =
        33554432; //16777216;//8388608;//читаем в буфер байты
    char* notAlignBuf = new char[nNumberOfBytesToRead + 4096]; //буфер
    char* buf = notAlignBuf; //буфер
    if (size_t(buf) % 4096)
    {   buf += 4096 - (size_t(buf) %
                       4096);    //адрес принимающего буфера тоже должен быть выровнен по размеру сектора/страницы
    }
 
    char* notAlignBufBufWork = new
    char[nNumberOfBytesToRead + 4096 + 1]; //буфер Рабочий
    char* bufWork = notAlignBufBufWork; //буфер
    if (size_t(bufWork) % 4096)
    {   bufWork += 4096 - (size_t(bufWork) %
                           4096);    //адрес рабочего буфера тоже выровнял по размеру сектора/страницы
    }
 
    bufWork[0] = '\0';//добавим нуль-терминатор
    bufWork[nNumberOfBytesToRead] = '\0';//добавим нуль-терминатор
    char* find;// указатель для поиска
    size_t strCount = 1; //счетчик строк
    std::string strOut; //итоговая строка
    DWORD  dwBytesReadWork;
    DWORD findStatus = 0; //статус поиска
    ULONGLONG ignoreOffset=0; //для расчета холостых циклов
    bool ERR_HANDLE_EOF = false; //метка конца файла
 
// создаем события с автоматическим сбросом
    HANDLE hEndRead = CreateEvent(NULL, FALSE, FALSE, NULL);// дескриптор события
    if (hEndRead == NULL)
    {   return GetLastError();
    }
 
    _ULARGE_INTEGER
    ui; //Представляет 64-разрядное целое число без знака обединяя два 32-х разрядных
    ui.QuadPart = 0;
 
    OVERLAPPED
    ovl;   // структура управления асинхронным доступом к файлу// инициализируем структуру OVERLAPPED
    ovl.Offset = 0;         // младшая часть смещения равна 0
    ovl.OffsetHigh = 0;      // старшая часть смещения равна 0
    ovl.hEvent = hEndRead;   // событие для оповещения завершения чтения
 
// открываем файл для чтения
    HANDLE hFile = CreateFile(  // дескриптор файла
                       path,   // имя файла
                       GENERIC_READ,          // чтение из файла
                       FILE_SHARE_READ,       // совместный доступ к файлу
                       NULL,                  // защиты нет
                       OPEN_EXISTING,         // открываем существующий файл
                       FILE_FLAG_OVERLAPPED | (NO_BUFFERING ? FILE_FLAG_NO_BUFFERING :
                               FILE_FLAG_RANDOM_ACCESS),// асинхронный ввод//отключаем системный буфер
                       NULL                   // шаблона нет
                   );
// проверяем на успешное открытие
    if (hFile == INVALID_HANDLE_VALUE)
    {   CloseHandle(hEndRead);
        delete[] notAlignBuf;
        delete[] notAlignBufBufWork;
        return -1;
    }
// читаем данные из файла
    for (;;)
    {   DWORD  dwBytesRead;
        DWORD  dwError;
        find = buf; //буфер
        // читаем одну запись
        if (!ReadFile(
                    hFile,           // дескриптор файла
                    buf,             // адрес буфера, куда читаем данные
                    nNumberOfBytesToRead,// количество читаемых байтов
                    &dwBytesRead,    // количество прочитанных байтов
                    &ovl             // чтение асинхронное
                ))
        {   switch (dwError = GetLastError())// решаем что делать с кодом ошибки
            {       //эти ошибки смотрм после завершения асинхронной операции чтения, для возможности обработать рабочий буфер
                case ERROR_IO_PENDING:
                    {   break;    // асинхронный ввод-вывод все еще происходит // сделаем кое-что пока он идет
                    }
                case ERROR_HANDLE_EOF:
                    {   ERR_HANDLE_EOF = true;    // мы достигли конца файла читалкой ReadFile
                        break;
                    }
                default:
                    {   goto return1;    // другие ошибки
                    }
            }
        }
        //работаем асинхронно, выполняем код, пока ждем чтение с диска//
        if (ui.QuadPart !=
                ignoreOffset)//игнорируем первую итерацию и этерации прошедшие следующим буфером, когда нужно было вернутся в предыдущий буфер
        {   bufWork[dwBytesReadWork] = '\0';//добавим нуль-терминатор
            find = bufWork; //новый буфер
        go_1:
            char* strStart = bufWork;
            char* strEnd = NULL;
 
            if (findStatus == 0)//goFind
            {   find = strstr(find, findStr);
                if (find != NULL) //если нужная подстрока найдена
                {
 
                    for (strStart = find; strStart >= bufWork; strStart--)
                    {   if (*strStart == '\n')
                        {   break;    //если нашли начало строки
                        }
                    }
                    strStart++;
                    if (ui.QuadPart == nNumberOfBytesToRead
                            || strStart != bufWork)//если первый буфер или найдено начало строки
                    {   strEnd = strchr(find, '\n');
                        if (strEnd != NULL) //если нашли конец строки
                        {   strOut = strOut + std::string(strStart, strEnd - strStart + 1);
                            if (!multiLine)
                            {   goto return0;
                            }
                            else//поиск в следующей строке начинаем с конца предыдущей
                            {   find = strEnd++;
                                findStatus = 0;
                                goto go_1;
                            }
                        }
                        else//если конец строки в следующем буфере или конец файла
                        {   strOut = strOut + std::string(strStart);
                            findStatus = 1;
                        }
                    }
                    else //если начало строки не найдено и это не первый буфер смотрим предыдущий буфер
                    {   findStatus = 2;
                        ui.QuadPart -= nNumberOfBytesToRead * 3;
                        ignoreOffset = ui.QuadPart + nNumberOfBytesToRead;
                    }
                } //если нужная подстрока найдена
            }
            else if (findStatus == 1)//goBuf
            {   strEnd = strchr(find, '\n');
                if (strEnd != NULL) //если нашли конец строки
                {   strOut = strOut + std::string(find, strEnd - find+1);
                    findStatus = 0;
                    if (!multiLine)
                    {   goto return0;
                    }
                    else//поиск в следующей строке начинаем с конца предыдущей
                    {   find = strEnd++;
                        findStatus = 0;
                        goto go_1;
                    }
                }
                else//если конец строки в следующем буфере или конец файла
                {   strOut = strOut + std::string(find);
                }
            }
            else if (findStatus == 2)//goBackBuf
            {
 
                for (strStart = bufWork + dwBytesReadWork; strStart >= bufWork; strStart--)
                {   if (*strStart == '\n')
                    {   break;    //если нашли начало строки
                    }
                }
                strStart++;
                if (ui.QuadPart == nNumberOfBytesToRead
                        || strStart != bufWork)//если первый буфер или найдено начало строки
                {   find = strStart++;
                    findStatus = 1;
                    goto go_1;
                }
                else
                {   ui.QuadPart -= nNumberOfBytesToRead *
                                   3;//если начало строки не найдлено смотрим предыдущий буфер
                    ignoreOffset = ui.QuadPart + nNumberOfBytesToRead;
                }
 
            }
        }
        if (ERR_HANDLE_EOF)
        {   if (findStatus != 2) goto return0;
        }
        //работаем асинхронно, выполняем код, пока ждем чтение с диска//
 
        // ждем, пока завершится асинхронная операция чтения
        WaitForSingleObject(hEndRead, INFINITE);
 
        // проверим результат работы асинхронного чтения // если возникла проблема ...
        if (!GetOverlappedResult(hFile, &ovl, &dwBytesRead, FALSE))
        {   switch (dwError = GetLastError())// решаем что делать с кодом ошибки
            {   case ERROR_HANDLE_EOF:
                    {   if (findStatus != 2) goto return0;
                        break;//если конец файла. но мы должны вернутся найти начало строки.
                    }// мы достигли конца файла в ходе асинхронной операции
                default:
                    {   goto return1;    // другие ошибки
                    }
            }// конец процедуры switch (dwError = GetLastError())
        }
 
        //синхронно копируем данные из буфера в рабочий буфер, далее с ним работаем асинхронно
        memcpy(bufWork, buf, nNumberOfBytesToRead);
 
        // увеличиваем смещение в файле
        dwBytesReadWork = dwBytesRead;//кол-во считанных байт
        ui.QuadPart += nNumberOfBytesToRead; //добавляем смещение к указателю на файл
        ovl.Offset = ui.LowPart;// вносим смещение в младшее слово
        ovl.OffsetHigh = ui.HighPart;// вносим смещение в старшеее слово
    }
 
return0:
// закрываем дескрипторы, освобождаем память
    //std::cout << "String Find " << strOut;
    CloseHandle(hFile);
    CloseHandle(hEndRead);
    delete[] notAlignBuf;
    delete[] notAlignBufBufWork;
    return 0;
return1:
    CloseHandle(hFile);
    CloseHandle(hEndRead);
    delete[] notAlignBuf;
    delete[] notAlignBufBufWork;
    return -1;
}
 
const char* const NAMEFILE = "N1GB.txt";
 
///--------------------------------------|
/// Лимит на максимальный размер строки. |
///--------------------------------------:
size_t MAXSTR = 1024;
 
///----------------------------------------------------------------------------|
/// Генератор файла большого размера.
///----------------------------------------------------------------------------:
void generator_testfile()
{   std::ifstream inf(NAMEFILE);
    if(inf.is_open())
    {   inf.close();
        std::cout << "file exist...\n\n";
        return;
    }
    inf.close();
    
    std::cout << "generator_testfile() work now...\n\n";
    std::ofstream f(NAMEFILE);
 
    const int N1GB = 1024*1024*4;
    std::string s =
        "qwerty1234567890qwerty1234567890qwerty1234567890qwerty1234567";
    MAXSTR = 4 * s.size() + 1;
 
    for    (int i = 0; i < N1GB; i++)
    {   f << s << s << s << s << "\n";
    }
    f << "1.......................ASD123FGH456........................2\n";
    f.close();
}
 
int main()
{   setlocale(0, "");
    generator_testfile();
 
    clock_t t1;
 
    {   ///-------------------------------------|
        /// bedvit                              |
        ///-------------------------------------:
        std::cout << "1: ";/////////////////////////////////////////////////---1
        t1 = clock();
        int        x;
        if(x = FindInCSVansi("N1GB.txt", "ASD123FGH456", 0, 0))
        {
        }
        printf("bedvit                  : Time = %f\n\n",
               (clock() - t1 + .0) / CLOCKS_PER_SEC); // время отработки
    }
 
    {   ///-------------------------------------|
        /// bedvit                              |
        ///-------------------------------------:
        std::cout << "2: ...\n\n";//////////////////////////////////////////---2
    }
 
    {   std::cout << "3: ";////////////////////////////////////////////////---3!
        t1 = clock();
        std::ifstream is(NAMEFILE, std::ios::in | std::ios::binary);
        
        is.seekg (0, std::ios::end);
        size_t size = is.tellg()+1;
        is.seekg (0, std::ios::beg);
        
        char* p = new char[size];
        std::string s("ASD123FGH456");
        while (is)
        {   is.read(p, size);
 
            std::string str(std::move(p));
            size_t found = str.find(s);
            if (found != std::string::npos)
            {   std::cout << "Find OK: " << std::endl;
            };
        }
        printf("   read + Find             : Time = %f(школа)\n\n",
               (clock() - t1 + .0) / CLOCKS_PER_SEC); // время отработки
        is.close();
        delete[] p;
    }
 
    {   std::cout << "4: ";/////////////////////////////////////////////////---4
        t1 = clock();
        std::ifstream is(NAMEFILE, std::ios::in | std::ios::binary);
 
        is.seekg (0, std::ios::end);
        size_t size = is.tellg();
        is.seekg (0, std::ios::beg);
 
        char* p = new char[size];
        while (is)
        {   is.read(p, size);
        }
        printf("read(без поиска)        : Time = %f(школа)\n\n",
               (clock() - t1 + .0) / CLOCKS_PER_SEC); // время отработки
        is.close();
        delete[] p;
    }
 
    {   ///-------------------------------------|
        /// Небольшая школьная оптимизация!     |
        ///-------------------------------------:
        std::cout << "5: ";/////////////////////////////////////////////////---5
        t1 = clock();
        std::ifstream is(NAMEFILE);
        std::string str;
        str.reserve(1024);
        std::string s("ASD123FGH456");
        while(is)
        {   std::getline(is, str);
            size_t found = str.find(s);
            if (found != std::string::npos)
            {   std::cout << "Find OK: " << std::endl;
            };
        }
        printf("   getline + reserve(1024) : Time = %f(школа)\n\n",
               (clock() - t1 + .0) / CLOCKS_PER_SEC); // время отработки
        is.close();
    }
    
    {   std::cout << "6: ";/////////////////////////////////////////////////---6
        t1 = clock();
        std::ifstream is(NAMEFILE, std::ios::in | std::ios::binary);
        
        size_t size = 64000000;
        std::vector<char> v(size);
        
        std::string s("ASD123FGH456");
        std::streamoff offset = -s.size();
        
        while (is)
        {   is.read(&v[0], size);
            is.seekg (offset, std::ios::cur);
            
            std::string str(std::move(&v[0]));
            size_t found = str.find(s);
            
            if (found != std::string::npos)
            {   std::cout << "Find OK: ";
            
                if     (size - found < MAXSTR) // +
                {   is.seekg (MAXSTR-size, std::ios::cur);
                    is.read(&v[0], size);
                }
                else if(size - found < size - MAXSTR) // -
                {   is.seekg (-MAXSTR-size, std::ios::cur);
                    is.read(&v[0], size);
                }
                str = std::string(std::move(&v[0]));
            
                size_t s1 = str.rfind('\n', found);
                size_t s2 = str.find ('\n', found);
                std::cout << str.substr(s1, s2-s1) << std::endl;
            };
        }
        printf("   read + Find + seekg     : Time = %f(школа)\n\n",
               (clock() - t1 + .0) / CLOCKS_PER_SEC); // время отработки
        is.close();
    }
    
    {   std::cout << "7: ";/////////////////////////////////////////////////---7
        t1 = clock();
        std::ifstream is(NAMEFILE, std::ios::in | std::ios::binary);
        
        size_t size = 100000;
        std::string str; str.assign(size, ' ');
        
        std::string s("ASD123FGH456");
        std::streamoff offset = -s.size();
        
        while (is)
        {   is.read((char*)str.data(), size);
            is.seekg (offset, std::ios::cur);
            
            size_t found = str.find(s);
            if (found != std::string::npos)
            {   std::cout << "Find OK: ";
            
                if     (size - found < MAXSTR) // +
                {   is.seekg (MAXSTR-size, std::ios::cur);
                    is.read((char*)str.data(), size);
                }
                else if(size - found < size - MAXSTR) // -
                {   is.seekg (-MAXSTR-size, std::ios::cur);
                    is.read((char*)str.data(), size);
                }
            
                size_t s1 = str.rfind('\n', found);
                size_t s2 = str.find ('\n', found);
                std::cout << str.substr(s1, s2-s1) << std::endl;
            };
        }
        printf("   read + Find + seekg     : Time = %f(школа)\n\n",
               (clock() - t1 + .0) / CLOCKS_PER_SEC); // время отработки
        is.close();
    }
 
    std::cout << "\n\n";
    system("pause");
    return 0;
}


код без вылизования под требования, которых как бы нет,
но нужно обратить внимание на два момента:
1.
C++
239
240
241
242
///--------------------------------------|
/// Лимит на максимальный размер строки. |
///--------------------------------------:
size_t MAXSTR = 1024;
2. Все строки должны заканчиваться спецсимволом '\n' - завершения строки.
Это критично если подстрока находится в последней строке файла.

или просто использовать мой генератор большого файла.

один прогон без заморочек:


там добавил код, который проверяет попала ли строка в буфер целиком или нет,
если нет, то буфер перегружается уже с поправкой.
1
Just Do It!
 Аватар для XLAT
4219 / 2680 / 656
Регистрация: 23.09.2014
Сообщений: 9,235
Записей в блоге: 3
08.06.2020, 22:46
Цитата Сообщение от XLAT Посмотреть сообщение
заняло 10 минут,
в 6,7 лажа,
правки:
C++
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
    {   std::cout << "6: ";/////////////////////////////////////////////////---6
        t1 = clock();
        std::ifstream is(NAMEFILE, std::ios::in | std::ios::binary);
        
        size_t size = 64000000;
        std::vector<char> v(size);
        
        std::string s("ASD123FGH456");
        std::streamoff offset = -s.size();
        
        while (is)
        {   is.read(&v[0], size);
            is.seekg (offset, std::ios::cur);
            
            std::string str(std::move(&v[0]));
            size_t found = str.find(s);
            
            if (found != std::string::npos)
            {   std::cout << "Find OK: ";
            
                if     (size - found < MAXSTR) // +
                {   is.seekg (MAXSTR-size, std::ios::cur);
                    is.read(&v[0], size);
                    str = std::string(std::move(&v[0]));
                    found -= MAXSTR;
                }
                else if(found < MAXSTR) // -
                {   is.seekg (-MAXSTR-size, std::ios::cur);
                    is.read(&v[0], size);
                    str = std::string(std::move(&v[0]));
                    found += MAXSTR;
                }
            
                size_t s1 = str.rfind('\n', found);
                size_t s2 = str.find ('\n', found);
                std::cout << str.substr(s1, s2-s1) << std::endl;
            };
        }
        printf("   read + Find + seekg     : Time = %f(школа)\n\n",
               (clock() - t1 + .0) / CLOCKS_PER_SEC); // время отработки
        is.close();
    }
    
    {   std::cout << "7: ";/////////////////////////////////////////////////---7
        t1 = clock();
        std::ifstream is(NAMEFILE, std::ios::in | std::ios::binary);
        
        size_t size = 100000;
        std::string str; str.assign(size, ' ');
        
        std::string s("ASD123FGH456");
        std::streamoff offset = -s.size();
        
        while (is)
        {   is.read((char*)str.data(), size);
            is.seekg (offset, std::ios::cur);
            
            size_t found = str.find(s);
            if (found != std::string::npos)
            {   std::cout << "Find OK: ";
            
                if     (size - found < MAXSTR) // +
                {   is.seekg (MAXSTR-size, std::ios::cur);
                    is.read((char*)str.data(), size);
                    found -= MAXSTR;
                }
                else if(size - found > size - MAXSTR) // -
                {   is.seekg (-MAXSTR-size, std::ios::cur);
                    is.read((char*)str.data(), size);
                    found += MAXSTR;
                }
            
                size_t s1 = str.rfind('\n', found);
                size_t s2 = str.find ('\n', found);
                std::cout << str.substr(s1, s2-s1) << std::endl;
            };
        }
        printf("   read + Find + seekg     : Time = %f(школа)\n\n",
               (clock() - t1 + .0) / CLOCKS_PER_SEC); // время отработки
        is.close();
    }
первичный тест то прошёл, но ...
как бы доказательство на необходимость специального тестирования.


Добавлено через 5 минут
ваще можно ещё пошоркать напильником, будет на 0.0001% ещё быстрее.
1
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
08.06.2020, 23:15  [ТС]
XLAT, неплохо.
Теперь ищем в файле 10 ГБ 40 млн. строку.
Видим паритет.
Потом я отключаю системный буфер в функции, и мой код на 20% быстрее.
Каков вывод: ваш алгоритм хорошо читает закешированные файлы, т.е. хорошо работает с памятью, а не с диском.
Это тоже необходимо, но недостаточно для победы
Миниатюры
Скорость чтения csv с разных носителей   Скорость чтения csv с разных носителей  
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
08.06.2020, 23:18  [ТС]
Тест проводился на SSD.
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
08.06.2020, 23:29  [ТС]
Вот на медленном HDD.
Видим, что паритет, потому как здесь просто время чтения с диска 99% общего времени.
Миниатюры
Скорость чтения csv с разных носителей  
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
08.06.2020, 23:34  [ТС]
Вот результат, когда файл не кеширован (1 ГБ - SSD)
Опять я выигрываю (за счет отключения системного буфера)
Миниатюры
Скорость чтения csv с разных носителей  
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
08.06.2020, 23:36  [ТС]
Вот результат, когда файл не кеширован (1 ГБ - HDD)
Паритет.
Миниатюры
Скорость чтения csv с разных носителей  
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
09.06.2020, 00:21  [ТС]
Тесты на HDD в основном это тест на скорость чтения с диска, у меня самый первый алгоритм (см. начало темы) считает столько же, как самый последний, просто потому, что расчет 1% времени, остальное 99% времени - это чтение с диска.
SSD уже показывает разницу в алгоритмах.

Добавлено через 40 минут
Avazart,
Есть смысл дочитывать данные при обнаружении частичного совпадения
вопрос в том, что такое частичное совпадение, в теории от 1 символа до всех кроме последнего. Представляется довольно сложная реализация. На первый взгляд сдвиг на количество символов подстроки поиска проще. Но и здесь возникает ситуация когда строка может быть на несколько буферов вперёд и назад от найденной подстроки. Нужно это смещение учитывать.
0
Just Do It!
 Аватар для XLAT
4219 / 2680 / 656
Регистрация: 23.09.2014
Сообщений: 9,235
Записей в блоге: 3
09.06.2020, 00:30
Цитата Сообщение от bedvit Посмотреть сообщение
и мой код на 20% быстрее.
молодцы.

bedvit, у мя к вам два вопроса:

1. можно код теста целиком?(там где у вас всё включено, т.е. ваще всё включено)
2. версия вашего компилятора?

зы:
компильнул щас в VS2019 там у мя 7 подтест 0 секунд
а 6 по скорости обгоняет ваш в 3 раза.
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
09.06.2020, 11:39  [ТС]
XLAT,
код
Кликните здесь для просмотра всего текста
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
#include "stdafx.h"
#include <fstream>
#include <string>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <Windows.h>
#include <vector>
#include <exception>
#include <stdio.h>
 
int FindRowsInCSVansi(PCTSTR path, const char* findStr, bool multiLine, bool noBuffering)
{
    const DWORD  nNumberOfBytesToRead = 16777216;//67108864;//33554432; //16777216;//8388608;//читаем в буфер байты
char* notAlignBuf = new char[nNumberOfBytesToRead + 4096]; //буфер
char* buf = notAlignBuf; //буфер
if (size_t(buf) % 4096) { buf += 4096 - (size_t(buf) % 4096); }//адрес принимающего буфера тоже должен быть выровнен по размеру сектора/страницы 
 
char* notAlignBufBufWork = new char[nNumberOfBytesToRead + 4096 + 1]; //буфер Рабочий
char* bufWork = notAlignBufBufWork; //буфер
if (size_t(bufWork) % 4096) { bufWork += 4096 - (size_t(bufWork) % 4096); }//адрес рабочего буфера тоже выровнял по размеру сектора/страницы  
 
bufWork[0] = '\0';//добавим нуль-терминатор
bufWork[nNumberOfBytesToRead] = '\0';//добавим нуль-терминатор
char* find;// указатель для поиска
size_t strCount = 1; //счетчик строк
size_t findStrLen = strlen(findStr); //счетчик строк
std::string strOut; //итоговая строка
DWORD dwBytesReadWork;
DWORD findStatus = 0; //статус поиска
ULONGLONG ignoreOffset=0; //для расчета холостых циклов
bool errHandleEOF = false; //метка конца файла
 
// создаем события с автоматическим сбросом
HANDLE hEndRead = CreateEvent(NULL, FALSE, FALSE, NULL);// дескриптор события
if (hEndRead == NULL) { return GetLastError(); }
 
_ULARGE_INTEGER ui; //Представляет 64-разрядное целое число без знака обединяя два 32-х разрядных
ui.QuadPart = 0;
 
OVERLAPPED  ovl;   // структура управления асинхронным доступом к файлу// инициализируем структуру OVERLAPPED
ovl.Offset = 0;         // младшая часть смещения равна 0
ovl.OffsetHigh = 0;      // старшая часть смещения равна 0
ovl.hEvent = hEndRead;   // событие для оповещения завершения чтения
 
// открываем файл для чтения
HANDLE hFile = CreateFile(  // дескриптор файла
    path,   // имя файла
    GENERIC_READ,          // чтение из файла
    FILE_SHARE_READ,       // совместный доступ к файлу
    NULL,                  // защиты нет
    OPEN_EXISTING,         // открываем существующий файл
    FILE_FLAG_OVERLAPPED | (noBuffering ? FILE_FLAG_NO_BUFFERING : FILE_FLAG_RANDOM_ACCESS),// асинхронный ввод//отключаем системный буфер
    NULL                   // шаблона нет
);
// проверяем на успешное открытие
if (hFile == INVALID_HANDLE_VALUE)
{
    CloseHandle(hEndRead);
    delete[] notAlignBuf;
    delete[] notAlignBufBufWork;
    return -1;
}
// читаем данные из файла
for (;;)
{
    DWORD  dwBytesRead;
    DWORD  dwError;
    find = buf; //буфер
    // читаем одну запись
    if (!ReadFile(
        hFile,           // дескриптор файла
        buf,             // адрес буфера, куда читаем данные
        nNumberOfBytesToRead,// количество читаемых байтов
        &dwBytesRead,    // количество прочитанных байтов
        &ovl             // чтение асинхронное
    ))
    {
        switch (dwError = GetLastError())// решаем что делать с кодом ошибки
        {
            //эти ошибки смотрм после завершения асинхронной операции чтения, для возможности обработать рабочий буфер
        case ERROR_IO_PENDING: { break; }        // асинхронный ввод-вывод все еще происходит // сделаем кое-что пока он идет 
        case ERROR_HANDLE_EOF: { errHandleEOF = true;   break; } // мы достигли конца файла читалкой ReadFile
        default: {goto return1; }// другие ошибки
        }
    }
    //работаем асинхронно, выполняем код, пока ждем чтение с диска//
    if (ui.QuadPart != ignoreOffset)//игнорируем первую итерацию и этерации прошедшие следующим буфером, когда нужно было вернутся в предыдущий буфер
    {
        bufWork[dwBytesReadWork] = '\0';//добавим нуль-терминатор
        find = bufWork; //новый буфер
    go_1:
        char* strStart = bufWork;
        char* strEnd = NULL;
 
        if (findStatus == 0)//goFind
        {
            find = strstr(find, findStr);
            if (find != NULL) //если нужная подстрока найдена
            {
 
                for (strStart = find; strStart >= bufWork; strStart--)
                {
                    if (*strStart == '\n') { break; } //если нашли начало строки
                }
                strStart++;
                if (ui.QuadPart == nNumberOfBytesToRead || strStart != bufWork)//если первый буфер или найдено начало строки
                {
                    strEnd = strchr(find, '\n');
                    if (strEnd != NULL) //если нашли конец строки
                    {
                        strOut = strOut + std::string(strStart, strEnd - strStart + 1);
                        if (!multiLine)
                        {
                            goto return0;
                        }
                        else//поиск в следующей строке начинаем с конца предыдущей
                        {
                            find = strEnd++;
                            findStatus = 0;
                            goto go_1;
                        }
                    }
                    else//если конец строки в следующем буфере или конец файла
                    {
                        strOut = strOut + std::string(strStart);
                        findStatus = 1;
                    }
                }
                else //если начало строки не найдено и это не первый буфер смотрим предыдущий буфер
                {
                    findStatus = 2;
                    ui.QuadPart -= (nNumberOfBytesToRead) * 3;
                    ignoreOffset = ui.QuadPart + nNumberOfBytesToRead;
                }
            } //если нужная подстрока найдена
        }
        else if (findStatus == 1)//goBuf
        {
            strEnd = strchr(find, '\n');
            if (strEnd != NULL) //если нашли конец строки
            {
                strOut = strOut + std::string(find, strEnd - find+1);
                findStatus = 0;
                if (!multiLine)
                {
                    goto return0;
                }
                else//поиск в следующей строке начинаем с конца предыдущей
                {
                    find = strEnd++;
                    findStatus = 0;
                    goto go_1;
                }
            }
            else//если конец строки в следующем буфере или конец файла
            {
                strOut = strOut + std::string(find);
            }
        }
        else if (findStatus == 2)//goBackBuf
        {
 
            for (strStart = bufWork + dwBytesReadWork; strStart >= bufWork; strStart--)
            {
                if (*strStart == '\n') { break; }//если нашли начало строки
            }
            strStart++;
            if (ui.QuadPart == nNumberOfBytesToRead || strStart != bufWork)//если первый буфер или найдено начало строки
            {
                find = strStart++;
                findStatus = 1;
                goto go_1;
            }
            else
            {
                ui.QuadPart -= nNumberOfBytesToRead * 3;//если начало строки не найдлено смотрим предыдущий буфер
                ignoreOffset = ui.QuadPart + nNumberOfBytesToRead;
            }
 
        }
    }
    if (errHandleEOF) { if (findStatus != 2) goto return0; }
    //работаем асинхронно, выполняем код, пока ждем чтение с диска//
 
    // ждем, пока завершится асинхронная операция чтения
    WaitForSingleObject(hEndRead, INFINITE);
 
    // проверим результат работы асинхронного чтения // если возникла проблема ... 
    if (!GetOverlappedResult(hFile, &ovl, &dwBytesRead, FALSE))
    {
        switch (dwError = GetLastError())// решаем что делать с кодом ошибки
        {
        case ERROR_HANDLE_EOF: 
        {
            if (findStatus != 2) goto return0; break;//если конец файла. но мы должны вернутся найти начало строки.
        }// мы достигли конца файла в ходе асинхронной операции
        default: {goto return1; }// другие ошибки
        }// конец процедуры switch (dwError = GetLastError())
    }
 
    //синхронно копируем данные из буфера в рабочий буфер, далее с ним работаем асинхронно
    memcpy(bufWork, buf, nNumberOfBytesToRead);
 
    // увеличиваем смещение в файле
    dwBytesReadWork = dwBytesRead;//кол-во считанных байт
    ui.QuadPart += nNumberOfBytesToRead; //добавляем смещение к указателю на файл
    ovl.Offset = ui.LowPart;// вносим смещение в младшее слово
    ovl.OffsetHigh = ui.HighPart;// вносим смещение в старшеее слово
}
 
return0:
// закрываем дескрипторы, освобождаем память
std::cout << "String Find\n" << strOut << std::endl;
CloseHandle(hFile);
CloseHandle(hEndRead);
delete[] notAlignBuf;
delete[] notAlignBufBufWork;
return 0;
return1:
CloseHandle(hFile);
CloseHandle(hEndRead);
delete[] notAlignBuf;
delete[] notAlignBufBufWork;
return -1;
}
 
int createfile() //создание файла для теста
{
    const int N = 4000000; // количество строк в файле
    std::ofstream fout("C:\\CSV_1_GB.csv");
    std::string str = "Пятый; Тридацть четвертый; 44221100; BBB; CIFRAPOLE; POLEPVTRETYE; ODIN ODIN - TRI; CC; 01.01.2013; 01.01.2013; 8963; 2UTY39ADVGKR; СU707039; 40200М У0026034; -; 11; 2; 150; 1998; 1; -; 21; 1980; 1490; НОМЕР ПЯТЬ; -; ПОЛЕ ОДИН; ПОЛЕ ОДИН ПЯТЬ; -; -";
    if (!fout){ return 1; }
 
    for (int i = 0; i < N; ++i)
    {
        fout << i + 1;
        fout << str << std::endl;
    }
    fout.close();
    return 0;
}
 
#pragma warning(disable : 4146)
int XLAT()
{
    clock_t t1;
    clock_t t2;
 
    size_t MAXSTR = 1024;
    const char* const NAMEFILE = "C:\\CSV_1_GB.csv";
    t1 = clock();
    std::ifstream is(NAMEFILE, std::ios::in | std::ios::binary);
 
    size_t size = 100000;
    std::string str; str.assign(size, ' ');
 
    std::string s("4000000");
    std::streamoff offset = -s.size();
 
    while (is)
    {
        is.read((char*)str.data(), size);
        is.seekg(offset, std::ios::cur);
 
        size_t found = str.find(s);
        if (found != std::string::npos)
        {
            std::cout << "Find OK: ";
 
            if (size - found < MAXSTR) // +
            {
                is.seekg(MAXSTR - size, std::ios::cur);
                is.read((char*)str.data(), size);
                found -= MAXSTR;
            }
            else if (size - found > size - MAXSTR) // -
            {
                is.seekg(-MAXSTR - size, std::ios::cur);
                is.read((char*)str.data(), size);
                found += MAXSTR;
            }
 
            size_t s1 = str.rfind('\n', found);
            size_t s2 = str.find('\n', found);
            std::cout << str.substr(s1, s2 - s1) << std::endl;
        };
    }
    is.close();
    printf("   read + Find + seekg     : Time = %f(школа)\n\n",
        (clock() - t1 + .0) / CLOCKS_PER_SEC); // время отработки
 
 
 
}
int main() 
{
    if (createfile() != 0) { return 1; }; //генератор данных в файле
    clock_t t1;
    clock_t t2;
    int x;
 
    t1 = clock();
    if ((x = FindRowsInCSVansi(L"C:\\CSV_1_GB.csv","4000000",0,1)) > -1)
    {
        t2 = clock();
        printf("bedvit1: Time - %f\n", (t2 - t1 + .0) / CLOCKS_PER_SEC); // время отработки
    }
 
    XLAT();
 
    t1 = clock();
    if ((x = FindRowsInCSVansi(L"C:\\CSV_1_GB.csv", "4000000", 0, 1)) > -1)
    {
        t2 = clock();
        printf("bedvit2: Time - %f\n", (t2 - t1 + .0) / CLOCKS_PER_SEC); // время отработки
    }
 
    XLAT();
 
    system("pause");
    return 0;
}


Тестовый стенд:
Кликните здесь для просмотра всего текста
Операционная система Microsoft Windows 10 Professional
Тип ЦП QuadCore AMD Phenom II X4 Black Edition 955, 3200 MHz (16 x 200)
Системная плата Asus M4A89GTD Pro (2 PCI, 1 PCI-E x1, 1 PCI-E x4, 2 PCI-E x16, 4 DDR3 DIMM, Audio, Video, Gigabit LAN, IEEE-1394)
Чипсет системной платы AMD 890GX, AMD K10
Системная память 8192 МБ (DDR3-1333 DDR3 SDRAM)
DIMM1: Kingston 99U5474-028.A00LF 4 ГБ DDR3-1333 DDR3 SDRAM (9-9-9-24 @ 666 МГц) (8-8-8-22 @ 609 МГц) (7-7-7-20 @ 533 МГц) (6-6-6-17 @ 457 МГц)
DIMM2: Kingston 99P5458-005.A00LF 4 ГБ DDR3-1333 DDR3 SDRAM (9-9-9-24 @ 666 МГц) (8-8-8-22 @ 609 МГц) (7-7-7-20 @ 533 МГц) (6-6-6-17 @ 457 МГц)
Хранение данных
Дисковый накопитель SSD KINGSTON SV300S37A120G (120 ГБ, SATA-III)
Дисковый накопитель HDD WDC WD10EACS-00ZJB0 (1000 ГБ, SATA-II)
Миниатюры
Скорость чтения csv с разных носителей   Скорость чтения csv с разных носителей   Скорость чтения csv с разных носителей  

1
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
09.06.2020, 11:43  [ТС]
тест на SSD
0
Эксперт С++
 Аватар для Avazart
8489 / 6156 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
09.06.2020, 11:47
Цитата Сообщение от bedvit Посмотреть сообщение
вопрос в том, что такое частичное совпадение, в теории от 1 символа до всех кроме последнего. Представляется довольно сложная реализация. На первый взгляд сдвиг на количество символов подстроки поиска проще. Но и здесь возникает ситуация когда строка может быть на несколько буферов вперёд и назад от найденной подстроки. Нужно это смещение учитывать.
Я же привел ссылку - ничего сложного. Другое дело как это адаптировать под асинхронное чтение.
Без этого же Ваш код - не рабочий.
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
09.06.2020, 13:09  [ТС]
Первый раз, после создания файла FindRowsInCSVansi отрабатывает дольше, во всех остальных случая (и когда уже есть файл работает как во втором прогоне, т.е. быстрее). Поэтому сделал два запуска для примера, т.к. по факту файл будет, и тайминг будет из второго запуска.

Добавлено через 33 секунды
Цитата Сообщение от Avazart Посмотреть сообщение
Без этого же Ваш код - не рабочий.
Идея со смещением вам не нравится, чем?

Добавлено через 1 час 18 минут
Или поясните идею с частичным поиском в конце буфера. На пальцах.
0
Эксперт С++
 Аватар для Avazart
8489 / 6156 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
09.06.2020, 13:19
На пальца-яйцах не объясняю. Я дал ссылку на код.
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
20.06.2020, 00:45  [ТС]
Упростил код, в отличии от первого - искомая строка не может быть больше буфера.
В тестовом режиме сравнил с кодом от XLAT.
Кликните здесь для просмотра всего текста
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#pragma warning(disable : 4146)
std::string XLAT(std::string s)
{
    clock_t t1;
    clock_t t2;
 
    size_t MAXSTR = 1024;
    const char* const NAMEFILE = "C:\\CSV_1_GB.csv";
    t1 = clock();
    std::ifstream is(NAMEFILE, std::ios::in | std::ios::binary);
 
    size_t size = 100000;
    std::string str; str.assign(size, ' ');
 
    //std::string s(findStr);
    std::streamoff offset = -s.size();
 
    std::string sOut;
 
    while (is)
    {
        is.read((char*)str.data(), size);
        is.seekg(offset, std::ios::cur);
 
        size_t found = str.find(s);
        if (found != std::string::npos)
        {
            //std::cout << "Find OK: ";
 
            if (size - found < MAXSTR) // +
            {
                is.seekg(MAXSTR - size, std::ios::cur);
                is.read((char*)str.data(), size);
                found -= MAXSTR;
            }
            else if (size - found > size - MAXSTR) // -
            {
                is.seekg(-MAXSTR - size, std::ios::cur);
                is.read((char*)str.data(), size);
                found += MAXSTR;
            }
 
            size_t s1 = str.rfind('\n', found);
            size_t s2 = str.find('\n', found);
            //std::cout << str.substr(s1, s2 - s1) << std::endl;
            sOut = sOut + str.substr(s1+1, s2 - s1);
            return sOut;
        };
    }
    is.close();
    //std::cout << sOut << std::endl;
    //printf("   read + Find + seekg     : Time = %f(школа)\n\n",
    //  (clock() - t1 + .0) / CLOCKS_PER_SEC); // время отработки
    return sOut;
}
 
std::string FindRowsInCSVansiNew(PCTSTR path, const char* findStr, bool multiLine, bool noBuffering)
{
    const DWORD  nNumberOfBytesToRead = 16777216;//67108864;//33554432; //16777216;//8388608;//читаем в буфер байты
    if (strlen(findStr) >= nNumberOfBytesToRead) { return ""; }; 
    char* notAlignBuf = new char[nNumberOfBytesToRead + 4096]; //буфер
    char* buf = notAlignBuf; //буфер
    if (size_t(buf) % 4096) { buf += 4096 - (size_t(buf) % 4096); }//адрес принимающего буфера тоже должен быть выровнен по размеру сектора/страницы 
 
    char* notAlignBufWork = new char[nNumberOfBytesToRead*2 + 4096 +  1]; //буфер Рабочий
    char* bufWork = notAlignBufWork + nNumberOfBytesToRead; //буфер
    if (size_t(bufWork) % 4096) { bufWork += 4096 - (size_t(bufWork) % 4096); }//адрес рабочего буфера тоже выровнял по размеру сектора/страницы  
 
    bufWork[0] = '\0';//добавим нуль-терминатор
    bufWork[nNumberOfBytesToRead] = '\0';//добавим нуль-терминатор
    char* find;// указатель для поиска
    size_t strCount = 1; //счетчик строк
    size_t findStrLen = strlen(findStr);
    std::string strOut; //итоговая строка
    DWORD dwBytesReadWork=0;
    DWORD findStatus = 0; //статус поиска
    //ULONGLONG ignoreOffset = 0; //для расчета холостых циклов
    bool errHandleEOF = false; //метка конца файла
 
    char* strStart;
    char* strEnd;
    char* bufWorkNew = bufWork;//буфер с учетом полной строки
    size_t strStartLen=0;
 
    // создаем события с автоматическим сбросом
    HANDLE hEndRead = CreateEvent(NULL, FALSE, FALSE, NULL);// дескриптор события
    //if (hEndRead == NULL) { return GetLastError(); }
    if (hEndRead == NULL) { return ""; }
 
    _ULARGE_INTEGER ui; //Представляет 64-разрядное целое число без знака обединяя два 32-х разрядных
    ui.QuadPart = 0;
 
    OVERLAPPED  ovl;   // структура управления асинхронным доступом к файлу// инициализируем структуру OVERLAPPED
    ovl.Offset = 0;         // младшая часть смещения равна 0
    ovl.OffsetHigh = 0;      // старшая часть смещения равна 0
    ovl.hEvent = hEndRead;   // событие для оповещения завершения чтения
 
    // открываем файл для чтения
    HANDLE hFile = CreateFile(  // дескриптор файла
        path,   // имя файла
        GENERIC_READ,          // чтение из файла
        FILE_SHARE_READ,       // совместный доступ к файлу
        NULL,                  // защиты нет
        OPEN_EXISTING,         // открываем существующий файл
        FILE_FLAG_OVERLAPPED | (noBuffering ? FILE_FLAG_NO_BUFFERING : FILE_FLAG_RANDOM_ACCESS),// асинхронный ввод//отключаем системный буфер
        NULL                   // шаблона нет
    );
    // проверяем на успешное открытие
    if (hFile == INVALID_HANDLE_VALUE)
    {
        CloseHandle(hEndRead);
        delete[] notAlignBuf;
        delete[] notAlignBufWork;
        return "";
    }
    // читаем данные из файла
    for (;;)
    {
        DWORD  dwBytesRead;
        DWORD  dwError;
        find = buf; //буфер
        // читаем одну запись
        if (!ReadFile(
            hFile,           // дескриптор файла
            buf,             // адрес буфера, куда читаем данные
            nNumberOfBytesToRead,// количество читаемых байтов
            &dwBytesRead,    // количество прочитанных байтов
            &ovl             // чтение асинхронное
        ))
        {
            switch (dwError = GetLastError())// решаем что делать с кодом ошибки
            {
            //эти ошибки смотрм после завершения асинхронной операции чтения, для возможности обработать рабочий буфер
            case ERROR_IO_PENDING: { break; }        // асинхронный ввод-вывод все еще происходит // сделаем кое-что пока он идет 
            case ERROR_HANDLE_EOF: { errHandleEOF = true;   break; } // мы достигли конца файла читалкой ReadFile
            default: {goto return1; }// другие ошибки
            }
        }
        //работаем асинхронно, выполняем код, пока ждем чтение с диска//
        bufWork[dwBytesReadWork] = '\0';//добавим нуль-терминатор
                //strStart = bufWork;
                //char* strEnd = NULL;
    go_1:
        if (findStatus == 0)//goFind
        {
            find = strstr(bufWorkNew, findStr);
            if (find != NULL) //если нужная подстрока найдена
            {
                for (strStart = find; strStart >= bufWorkNew; strStart--)
                {
                    if (*strStart == '\n') { break; } //если нашли начало строки
                }
                strStart++; //не учитываем '\n'
 
                strEnd = strchr(find, '\n'); //ищем конец строки
                if (strEnd != NULL) //если нашли конец строки
                {
                    strOut = strOut + std::string(strStart, strEnd - strStart + 1);
                    if (!multiLine)
                    {
                        goto return0;
                    }
                    else//поиск в следующей строке начинаем с конца предыдущей
                    {
                        bufWorkNew = strEnd++;
                        findStatus = 0;
                        goto go_1;
                    }
                }
                else//если конец строки в следующем буфере или конец файла
                {
                    strOut = strOut + std::string(strStart);
                    findStatus = 1;
                }
                
            } //если нужная подстрока найдена
        }
        else if (findStatus == 1)//goBuf
        {
            strEnd = strchr(bufWork, '\n');
            if (strEnd != NULL) //если нашли конец строки
            {
                strOut = strOut + std::string(bufWork, strEnd - bufWork + 1);
                findStatus = 0;
                if (!multiLine)
                {
                    goto return0;
                }
                else//поиск в следующей строке начинаем с конца предыдущей
                {
                    bufWorkNew = strEnd++;
                    findStatus = 0;
                    goto go_1;
                }
            }
            else//если конец строки в следующем буфере или конец файла
            {
                strOut = strOut + std::string(bufWork);
            }
        }
 
        //блок дозагрузки основного буфера межбуферной строкой
        char* bufWorkEnd = bufWork + dwBytesReadWork; //конец буфера
        for (strStart = bufWorkEnd; strStart >= bufWork; strStart--) { if (*strStart == '\n') { break; } } //если нашли начало строки
        if (strStart < bufWork && ui.QuadPart>=nNumberOfBytesToRead) { goto return1; }; //если строка больше буфера (не найден разделитель), кроме первого буфера
        strStartLen = (bufWorkEnd - ++strStart); //размер буфера, который добавляем к рабочему
        bufWorkNew = bufWork - strStartLen;
        memcpy(bufWorkNew, strStart, strStartLen);
        //////////////////////
        if (errHandleEOF) { goto return0; }
        //работаем асинхронно, выполняем код, пока ждем чтение с диска//
 
        // ждем, пока завершится асинхронная операция чтения
        WaitForSingleObject(hEndRead, INFINITE);
 
        // проверим результат работы асинхронного чтения // если возникла проблема ... 
        if (!GetOverlappedResult(hFile, &ovl, &dwBytesRead, FALSE))
        {
            switch (dwError = GetLastError())// решаем что делать с кодом ошибки
            {
            case ERROR_HANDLE_EOF:{ goto return0; break; }//если конец файла. но мы должны вернутся найти начало строки.
            // мы достигли конца файла в ходе асинхронной операции
            default: {goto return1; }// другие ошибки
            }// конец процедуры switch (dwError = GetLastError())
        }
 
        //синхронно копируем данные из буфера в рабочий буфер, далее с ним работаем асинхронно
        memcpy(bufWork, buf, nNumberOfBytesToRead);
 
        // увеличиваем смещение в файле
        dwBytesReadWork = dwBytesRead;//кол-во считанных байт
        ui.QuadPart += nNumberOfBytesToRead; //добавляем смещение к указателю на файл
        ovl.Offset = ui.LowPart;// вносим смещение в младшее слово
        ovl.OffsetHigh = ui.HighPart;// вносим смещение в старшеее слово
        //ovl.Offset += nNumberOfBytesToRead;
    }
 
return0:
    // закрываем дескрипторы, освобождаем память
    //std::cout << "String Find\n" << strOut << std::endl;
    CloseHandle(hFile);
    CloseHandle(hEndRead);
    delete[] notAlignBuf;
    delete[] notAlignBufWork;
    return strOut;
return1:
    CloseHandle(hFile);
    CloseHandle(hEndRead);
    delete[] notAlignBuf;
    delete[] notAlignBufWork;
    return "";
}
 
 
int main() 
{
    std::string sOut;
    std::string sOut2;
    clock_t t1;
    clock_t t2;
    int x;
 
    for (int i = 1; i <= 4000000; i++)
    {
        sOut = FindRowsInCSVansiNew(L"C:\\CSV_1_GB.csv", std::to_string(i).c_str(), 0, 0);
        sOut2 = XLAT(std::to_string(i));
        if (sOut != sOut2)
        {
            std::cout <<"find: "<<i<<"\nbedvit\n"<< sOut << std::endl;
            std::cout <<"XLAT\n"<<sOut2 << std::endl;
        }
    }
 
    system("pause");
    return 0;
}

Времени было мало, красивости не наводил.
XLAT, у вас обнаружились некоторые неточности, посмотрите сами. Но зато ваш код работает быстрее при кешировании, но нужно привести его в порядок, возможно время изменится.
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
20.06.2020, 11:52  [ТС]
Тест на скорость чтения с буфером и без (когда файл читается первый раз) - 5 итераций:
FILE_FLAG_NO_BUFFERING

bedvit1: Time - 2.683000
XLAT: Time - 3.277000
bedvit1: Time - 2.669000
XLAT: Time - 3.234000
bedvit1: Time - 2.712000
XLAT: Time - 3.244000
bedvit1: Time - 2.668000
XLAT: Time - 3.230000
bedvit1: Time - 2.662000
XLAT: Time - 3.229000

FILE_FLAG_BUFFERING

bedvit1: Time - 1.284000
XLAT: Time - 1.008000
bedvit1: Time - 1.384000
XLAT: Time - 1.016000
bedvit1: Time - 1.288000
XLAT: Time - 1.026000
bedvit1: Time - 1.315000
XLAT: Time - 1.019000
bedvit1: Time - 1.287000
XLAT: Time - 1.012000

Кликните здесь для просмотра всего текста
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
int main() 
{
 
    std::string sOut;
    std::string sOut2;
 
    //if (createfile() != 0) { return 1; }; //генератор данных в файле
    clock_t t1;
    clock_t t2;
 
    std::cout << "\n\FILE_FLAG_NO_BUFFERING\n" << std::endl;
    for (int i = 1; i <= 5; i++)
    {
        t1 = clock();
        sOut = FindRowsInCSVansiNew(L"C:\\CSV_1_GB.csv", "4000000", 0, 1);
        t2 = clock();
        printf("bedvit1: Time - %f\n", (t2 - t1 + .0) / CLOCKS_PER_SEC); // время отработки
 
        t1 = clock();
        sOut2 = XLAT("4000000");
        t2 = clock();
        printf("XLAT: Time - %f\n", (t2 - t1 + .0) / CLOCKS_PER_SEC); // время отработки
    }
 
    //кешировано
    std::cout << "\n\FILE_FLAG_BUFFERING\n" << std::endl;
    for (int i = 1; i <= 5; i++)
    {
        t1 = clock();
        sOut = FindRowsInCSVansiNew(L"C:\\CSV_1_GB.csv", "4000000", 0, 0);
        t2 = clock();
        printf("bedvit1: Time - %f\n", (t2 - t1 + .0) / CLOCKS_PER_SEC); // время отработки
 
        t1 = clock();
        sOut2 = XLAT("4000000");
        t2 = clock();
        printf("XLAT: Time - %f\n", (t2 - t1 + .0) / CLOCKS_PER_SEC); // время отработки
    }
 
    system("pause");
    return 0;
}

Генератор CSV_1_GB.csv здесь (сообщение 50) выкладывал.

Добавлено через 2 минуты
Думаю, когда читается из кеша, здесь ассинхронность только помеха, со всеми накладными расходами и независимой работой с копией буфера.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
20.06.2020, 11:52

Программа для чтения csv
Нужно прочитать csv-файл, записать в массив и потом делать с ним всякие манипуляции и сортировки (ну это как раз самое простое). У меня...

Скорость импорта CSV
Здравствуйте. Прислали мне CSV-шник размером 10 гигов, чтобы сделать пару запросов. Поставил я себе MySQL Workbench, подготовил...

Bat - файл для чтения только одной строки из файла CSV
Добрый день! Подскажите пожалуйста как сделать батник чтобы он выводил только одну (2, 3, 4,...) строку из файла CSV. На текущий...

Как правильно написать скрипт для чтения файла с расширением .csv(Excel) ?
как правильно написать скрипт для чтения файла с расширением .csv(Excel) пишу вот такой програмный код: &lt;? $count = 1; $file =...

Скорость чтения/записи
Всем привет! Есть ли какие-нибудь библиотеки в Java, чтобы узнать скорость чтения/записи на диск? Интересует именно Java, потому что...


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

Или воспользуйтесь поиском по форуму:
100
Ответ Создать тему
Новые блоги и статьи
сукцессия 29. Переход от одних деревьев на другие делать более или менее вероятностным?
anaschu 12.07.2026
Насколько смена типов микоризы — исключительное событие в двухвековой сукцессии? Оценка вероятности в пространстве параметров В текущей версии модели успешно реализован ключевой механизм. . .
сукцессия 27. Думаю, как переделывать уже написанную статью с планами на сукцессию.
anaschu 12.07.2026
Анализ соответствия модели требованиям Реализованные компоненты: Механизм закисления почвы через протонную помпу Конкуренция между типами микориз pH как триггер сукцессии C/ P соотношение. . .
Сукцессия 26. Мат модель создана.
anaschu 12.07.2026
Модель смены растительных сукцессий посредством управления грибами работает внутри небольшой ячейки почвы, восстанавливающейся после пожара, где ненадолго бывшее царство хвойных снова захватили. . .
Решил проблему с ошибкой пагинации сообщений с сервера на алгоритме обхода дерева "Эстафета хвоста".
Hrethgir 12.07.2026
Проблема была в том, что удалялась именно новая кнопка, а не старая. Ни один ИИ не обнаружил это, а сам я смог только когда с работой стало попроще и когда заставил работать будущее автономное. . .
сукцессия 25. Хронология ошибок
anaschu 12.07.2026
# От 50-тонного гриба до устойчивого леса: хроника ошибок при построении модели вековой сукцессии микоризы ## О чём эта статья В процессе построения ОДУ-модели (система дифференциальных. . .
сукцессия 24. Промежуточное общее описание модели
anaschu 12.07.2026
Хендофф: модель АМ→ЭКМ сукцессии микоризы (ризосфера, 50 лет) Содержание проекта Симуляция вековой (50 лет) экологической сукцессии в почве леса Основные участники: АМ-гриб, ЭКМ-гриб,. . .
сукцессия 23. Более физиологичная физиология, более экологичная экология, более диффурные диффуры.
anaschu 12.07.2026
Что реально нашли и починили за эти 5 часов Правило Линдемана (КПД конверсии сахара в тело, kEff) — раньше 100% полученного углерода шло прямо в биомассу гриба; теперь только kEff=0. 5 (после. . .
сукцессия 22. От артефактов к физиологии: калибровка агентной модели грибной сукцессии для воспроизведения сезонной динамики и pH-плато
anaschu 11.07.2026
Аннотация В данной работе представлена калибровка агентной модели динамики грибных сообществ (fungal-succession), направленная на устранение нефизичных артефактов (коллапс биомассы, мгновенное. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru