+7(960) 250-82-68 spam@mirossa.ru


 mirossa        1С           C         PHP       JAVA       MCU  


Статьи
 
 

Поиск подстрок в файлах

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

Пример. Шаблон "123". Текст в файле: "123_45634gain51235" . Смещения: 0, 14

Шаблон задается в отдельном файле pattern.txt в каталоге с приложением. Это для того, чтобы можно было задать любую кодировку.
То есть ищется последовательность байтов, из которых состоит шаблон/фраза.

Память выделяется под целый файл (любого размера).

Недостатки:

  • При обработке файлов память 'выделяется и освобождается' для каждого файла вместо того, чтобы выделить один раз под самый большой файл и освободить после обработки всех файлов.

  • Не работает с длинными путями. Максимальный путь файла - 260 символов.

  • Небольшие утечки памяти(?). Примеры:
    А. после запуска приложения оно занимает 0.7 Мб после завершения процесса поиска в каталоге с 91355(штук) файлами общим размером 74 Гб приложение занимает 10 Мб. То есть утечка 9 Мб.
    Б. Обработка двух файлов по 4.94 Гб. размер занятой памяти 1 Мб. утечка 0.3 Мб
    Незначительно.

  • Нет шкалы хода процесса.

win.exe  скачать 26_findSubStr_gui 64 bit
win.exe  скачать 26_findSubStr_gui_32bit

32-битная версия работает с файлами до 4 Гб, но ещё нужно вычесть память, занимаемую операционной системой.
При попытке прочитать большой файл в поле на форме будет выведено сообщение и приложение продолжит обрабатывать следующие файлы.

! Если 32-битная версия в 64-битной ОС будет завершаться с ошибкой (Имя сбойного модуля: ntdll.dll), то установите какой-нибудь режим совместимости.
compatibility image



Выбор кодировки (текстовый редактор)

main window

main window
/* 26_findSubStr_gui.c */

//cd "C:\Program Files\mingw-w64\x86_64-8.1.0-win32-seh-rt_v6-rev0\mingw64\bin"
//x86_64-w64-mingw32-gcc.exe 26_findSubStr_gui.c 26_list_intr.c 26_findSubStr_impl.c -lole32 -luuid -o 26_findSubStr_gui.exe -mwindows
// 26_findSubStr_gui.exe

//cd "C:\Program Files (x86)\mingw-w64\i686-8.1.0-win32-dwarf-rt_v6-rev0\mingw32\bin"
//i686-w64-mingw32-gcc.exe 26_findSubStr_gui.c 26_list_intr.c 26_findSubStr_impl.c -lole32 -luuid -o 26_findSubStr_gui_32bit.exe -mwindows
// 26_findSubStr_gui_32bit.exe

//где-то устанавливается значение NTDDI_VERSION, равное NTDDI_WS03. Из-за этого в shobjidl.h не выполняется
//секция ( условие #if NTDDI_VERSION >= NTDDI_VISTA) ), где "определяется" IID_IFileOpenDialog.
#define NTDDI_VERSION 0x06000000  //NTDDI_VISTA or NTDDI_WIN6

#include <shobjidl.h>
#include <windows.h>
#include <shlwapi.h>
#include <stdio.h>
#include "26_list_intr.h"
#include <string.h>
#include <stdlib.h>
#include <stdint.h> // для int64_t
#include <inttypes.h> // для правильного вывода int64_t в printf
#include "26_findSubStr_impl.h"


#define message01 L"Список файлов в каталоге: \xD\xA"
#define message02 L"Каталог не выбран."
#define message03 L"В каталоге нет файлов."
#define message04 L"ошибка при открытии файла "
#define message05 L"ошибка при получении данных из файла "
#define message06 L"ошибка при создании таблицы состояний конечного автомата"
#define message07 L"ошибка при поиске шаблона в файле "

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void startFind(void);
void OutPathToEditW(Paths * ps, wchar_t * cstr);
void OutPathToFileW(Paths * ps, wchar_t * cstr, FILE * ff);
void ShowDialogDirSelect(PWSTR selectedFilePath);
void AddTextToEditW(wchar_t * str);

HWND hWnd_button1, editctl;
WCHAR selectedFilePath[MAX_PATH+1];

HWND hMainWnd; // дескриптор будущего окна

Paths exPath;
WORD sx, sy;	

/* 64-bit */ 
long long id_button1 = 10001;
long long IDC_EDIT   = 10002;

/* // 32-bit
int id_button1 = 10001;
int IDC_EDIT   = 10002;
*/

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
	
	wchar_t szClassName[] = L"26_findSubStr_gui"; // строка с именем класса  
    MSG msg; // создаём экземпляр структуры MSG для обработки сообщений
    WNDCLASSEXW wc; // создааём экземпляр, для обращения к членам класса WNDCLASSEX
	
// TCHAR type depends from the UNICODE preprocessor constant
	/////////////////
	
    wc.cbSize        = sizeof(wc); // размер структуры (в байтах)
    wc.style         = CS_HREDRAW | CS_VREDRAW; // стиль класса окна
    wc.lpfnWndProc   = WndProc; // указатель на пользовательскую функцию
    wc.lpszMenuName  = NULL; // указатель на имя меню (у нас его нет)
    wc.lpszClassName = szClassName; // указатель на имя класса
    wc.cbWndExtra    = 0; // число освобождаемых байтов в конце структуры
    wc.cbClsExtra    = 0; // число освобождаемых байтов при создании экземпляра приложения
    wc.hIcon         = LoadIcon(NULL, IDI_WINLOGO); // декриптор пиктограммы
    wc.hIconSm       = LoadIcon(NULL, IDI_WINLOGO); // дескриптор маленькой пиктограммы (в трэе)
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW); // дескриптор курсора
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // дескриптор кисти для закраски фона окна
    wc.hInstance     = hInst; // указатель на строку, содержащую имя меню, применяемого для класса
    if(!RegisterClassExW(&wc)){
        // в случае отсутствия регистрации класса:
        MessageBoxW(NULL, L"Класс окна не зарегистрирован!", L"Err_Err", MB_OK);
        return 1;
    }
 
	// Функция, создающая окно:
    hMainWnd = CreateWindowW(
        szClassName, // имя класса
        L"Поиск строки в файлах", // заголовок окна // L"\x41F\x43E\x438\x441\x43A \x441\x442\x440\x43E\x43A\x438 \x432 \x444\x430\x439\x43B\x430\x445"
        WS_OVERLAPPEDWINDOW,              // | WS_VSCROLL, // режимы отображения окна
        CW_USEDEFAULT, // позиция окна по оси х
        CW_USEDEFAULT, // позиция окна по оси у (раз дефолт в х, то писать не нужно)
        500, // ширина окна
        400, // высота окна (раз дефолт в ширине, то писать не нужно)
        NULL, // дескриптор родительского окна
        NULL, // дескриптор меню
        hInst, // дескриптор экземпляра приложения
        NULL); // ничего не передааём из WndProc
    if(!hMainWnd){
        // в случае некорректного создания окна (неверные параметры и тп):
        MessageBoxW(NULL, L"Главное окно не создано!", L"Err_Err2", MB_OK);
        return 0;
    }
	
	//////////////button1 - to start coping. //////////////////////////////////
	
	//Создаем кнопку
						//macro TEXT(L"Выбрать каталог...")
	hWnd_button1 = CreateWindowW(L"button", L"Выбрать каталог и начать поиск...", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	10, 30, 250, 30, hMainWnd, (HMENU)id_button1, hInst, NULL);	
	
	////////////// EDIT 1/////////////////////////////////////////

editctl = CreateWindowW(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_HSCROLL |
		ES_LEFT | ES_AUTOHSCROLL | ES_WANTRETURN | ES_MULTILINE | ES_AUTOVSCROLL | ES_NOHIDESEL,
	10, 70, 100, 100, hMainWnd, (HMENU)IDC_EDIT, hInst, 0);
	
	
	ShowWindow(hMainWnd, nCmdShow); // отображаем окно
    UpdateWindow(hMainWnd); // обновляем окно
    while(GetMessageW(&msg, NULL, 0, 0)){ // извлекаем сообщения из очереди, посылаемые фу-циями, ОС
        TranslateMessage(&msg); // интерпретируем сообщения
        DispatchMessageW(&msg); // передааём сообщения обратно ОС
    }
    return msg.wParam; // возвращаем код выхода из приложения
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
	
	
	switch(uMsg){
		
	case WM_COMMAND:
	
		if (LOWORD(wParam) == id_button1){   //  start coping
		
		
			startFind();
			
		}
	
	break;
	case WM_SIZE:     // Sent to a window after its size has changed
          
        sx = LOWORD(lParam); //ширина клиентской области
        sy = HIWORD(lParam); //высота
				
		SetWindowPos(editctl, (HWND)NULL, 10, 70, sx- 20, sy - 80, 0);
		
		
    break;
	case WM_DESTROY:
				
        PostQuitMessage(0); // отправляем WinMain() сообщение WM_QUIT
        break;
		
	default:
        return DefWindowProcW(hWnd, uMsg, wParam, lParam); 
    }
	
}

void startFind(void){
		
	int readRes;
	
	Node * nextEx;
	
	int64_t * nextState = NULL;
	int64_t  m;
	int64_t * arr_out;
	int64_t n_out, i;
	uint8_t rez;
	
	int64_t _file_size = 0;
	
	char * pattern = NULL;
	char * textF = NULL;
	
	wchar_t * offsetsText = NULL;
	wchar_t itemOffsetsText[25];
	int64_t SizeOfoffsetsText = 0, SizeOfoffsetsTextNew;
	unsigned int s;
	int64_t currPos = (int64_t)0; 
	
	SetWindowTextW(editctl, L"### Начало\xD\xA");
	
	if ( ! ( rez = getTextW(L"pattern.txt", &pattern, &m) ) ){ // ok
	
		rez = createNextState(pattern, &nextState, m);
		
		free(pattern);
		if (rez == 1){
			AddTextToEditW(message06);
			AddTextToEditW(L"\xD\xA");
			return;
		}
	} else {
		if ( rez == 2 ){
			AddTextToEditW(message04);
			AddTextToEditW(L"pattern.txt");
			AddTextToEditW(L"\xD\xA");
		}else if( rez == 1) {
			AddTextToEditW(message05);
			AddTextToEditW(L"pattern.txt");
			AddTextToEditW(L"\xD\xA");
		} else {
			AddTextToEditW(L"Файл pattern.txt пустой.");
			AddTextToEditW(L"\xD\xA");	
		}
		return;
	}
	
			
	selectedFilePath[0] = L'\0';
	ShowDialogDirSelect(selectedFilePath);
	
	if( selectedFilePath[0] == L'\0' ){
		AddTextToEditW(message02);
		AddTextToEditW(L"\xD\xA");
		if ( nextState != NULL )
			free(nextState);
		return;
	}
	
	initList(&exPath);
	
	readRes = ReadPaths(&exPath, selectedFilePath);

	if ( exPath.nump > 0 ){
		//OutPathToEditW(&exPath, message01);	//shows all paths
	
		nextEx = exPath.begin;
		while ( nextEx != NULL ){
		
			if ( ! ( rez = getTextW( nextEx->item.path1 , &textF, &_file_size) ) ){  // "D:\\\\text.txt" 
				
				//printf(" _file_size == %"  PRId64  "\n", _file_size);
				
				rez = findSubStr(textF, _file_size, nextState, m, &n_out, &arr_out);
			
				free(textF);
				if (rez == 1){
					AddTextToEditW(message07); 
					AddTextToEditW(nextEx->item.path1);
					AddTextToEditW(L"\xD\xA");
					nextEx = nextEx->next;
					continue;
				}
				
				//обработка полученного массива смещений
				if ( n_out != 0 ){
					AddTextToEditW(nextEx->item.path1);
					AddTextToEditW(L"\xD\xA");
					
					// Int64.MaxValue = 9223372036854775807, учитывая это
					// выделяю память для всех элементов массива в текстовом представлении.
					// Если памяти, выделенной для предыдущей обработки, хватит для текущей, то
					// использую её.
					
					SizeOfoffsetsTextNew = (22 + 2) * sizeof(wchar_t) * n_out;
					if ( offsetsText != NULL ){
						
						if ( SizeOfoffsetsTextNew > SizeOfoffsetsText ){
							free(offsetsText);
							offsetsText = (wchar_t*) malloc( SizeOfoffsetsTextNew );
						}
					} else {
						offsetsText = (wchar_t*) malloc( SizeOfoffsetsTextNew );
					}
					SizeOfoffsetsText = SizeOfoffsetsTextNew;
					
					s = 0;
					AddTextToEditW(L"Количество найденных вхождений: ");
					swprintf(itemOffsetsText, 25, L"%I64d", n_out); //check return value
					AddTextToEditW(itemOffsetsText);
					AddTextToEditW(L"\xD\xA");
					
					for( i = 0; i < n_out; i++ ){
						
						swprintf(itemOffsetsText, 25, L"%I64d", arr_out[i]); //check return value
						
						swprintf(offsetsText + s, SizeOfoffsetsText / sizeof(wchar_t) - s, L", %s", itemOffsetsText);
						s += wcslen(itemOffsetsText) + 2; // + ", "
						
					}
					AddTextToEditW(offsetsText + 2); // skip ", "
					AddTextToEditW(L"\xD\xA\xD\xA");
					
				} 
				
				
			}else {
				if ( rez == 2 ){
					AddTextToEditW(message04);
					AddTextToEditW(nextEx->item.path1);
					AddTextToEditW(L"\xD\xA");
				}else if ( rez == 1 ){ 
					AddTextToEditW(message05);
					AddTextToEditW(nextEx->item.path1);
					AddTextToEditW(L"\xD\xA");
				}
				  // rez == 3 - file is empty.
			}
		
			
		
			nextEx = nextEx->next;
		}
		
		
		if ( offsetsText != NULL)
			free(offsetsText);
	}	
	else{ 
		AddTextToEditW(message03);
		AddTextToEditW(L"\xD\xA");
	}
	
	//очистка памяти
	freeList(&exPath);
	if ( nextState != NULL )
		free(nextState);
	
	AddTextToEditW(L"### Конец.");
}


void OutPathToEditW(Paths * ps, wchar_t * cstr){
	unsigned int slen, clen, i = 0, num;
	Node * nextEx;
	wchar_t * str;
	
//MessageBoxW(NULL, L"Отладка", L"Отладка", MB_OK); 
		
	slen = ( ps->lengthAllPaths1 + ps->nump * 2 ) * sizeof(wchar_t); // + \xD\xA
	clen = wcslen(cstr) * sizeof(wchar_t);
	num = clen + slen + 3*sizeof(wchar_t);
	str = (wchar_t *) malloc( num ); // + \xD\xA + \0
	if (str == NULL){
		SetWindowTextW(editctl, L"Нет свободной памяти.");
		return;
	}
		
	num = num / sizeof(wchar_t);
	
	swprintf(str, num, L"%s\xD\xA", cstr); //check return value
	i = wcslen(cstr) + 2;
	
	nextEx = ps->begin;
	while ( nextEx != NULL ){
		
		swprintf(str + i, num - i, L"%s\xD\xA", nextEx->item.path1); //check return value     
		
		i += nextEx->item.num1 + 2; // + \xD\xA
		nextEx = nextEx->next;
	}
	
	SetWindowTextW(editctl, str);
	free(str);
}

void AddTextToEditW(wchar_t * str){

	int nLen = GetWindowTextLengthW(editctl);
	SendMessageW (editctl, EM_SETSEL, nLen, nLen);
	SendMessageW (editctl, EM_REPLACESEL, 0, (LPARAM)str);


}

void OutPathToFileW(Paths * ps, wchar_t * cstr, FILE * ff){

	Node * nextEx;
	
	fputws(cstr, ff);
	fputws(L"\n", ff);
		
	nextEx = ps->begin;
	while ( nextEx != NULL ){
		fputws(nextEx->item.path1, ff);
		fputws(L"\n", ff);
		nextEx = nextEx->next;
	}
	

}

void ShowDialogDirSelect(PWSTR selectedFilePath){
	
	HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
	
    if (SUCCEEDED(hr))
    {
        IFileOpenDialog *pFileOpen;

        // Create the FileOpenDialog object.
        hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, CLSCTX_ALL, &IID_IFileOpenDialog, (void**)(&pFileOpen)  );

        if (SUCCEEDED(hr))
        {
			// options
			hr = pFileOpen->lpVtbl->SetOptions(pFileOpen, FOS_PICKFOLDERS);
			
            // Show the Open dialog box.
            hr = pFileOpen->lpVtbl->Show(pFileOpen, NULL);

            // Get the file name from the dialog box.
            if (SUCCEEDED(hr))
            {
                IShellItem *pItem;
                hr = pFileOpen->lpVtbl->GetResult(pFileOpen, &pItem);
                if (SUCCEEDED(hr))
                {
                    PWSTR pszFilePath;
                    hr = pItem->lpVtbl->GetDisplayName(pItem, SIGDN_FILESYSPATH, &pszFilePath);

                    // Display the file name to the user.
                    if (SUCCEEDED(hr))
                    {
						wcscpy (selectedFilePath, pszFilePath);					
                        
						 //MessageBoxW(NULL, pszFilePath, L"File Path", MB_OK);
						 // winnt.h
						 //typedef wchar_t WCHAR;
						 //typedef WCHAR *NWPSTR,*LPWSTR,*PWSTR;
						 
							/* The size modifier of the string literal (L, u, U) determines the type of the literal.
							char   a[] = "Hello";
							wchar_t  b[] = L"Hello";
							char16_t c[] = u"Hello";
							char32_t d[] = U"Hello"; */
						 
							// null termination: L'\0'
							
							// https://docs.microsoft.com/ru-ru/cpp/cpp/string-and-character-literals-cpp?view=vs-2019
							// https://en.wikipedia.org/wiki/C_string_handling
							
                        CoTaskMemFree(pszFilePath);
                    }
                    pItem->lpVtbl->Release(pItem);
                }
            }
            pFileOpen->lpVtbl->Release(pFileOpen);
        }
        CoUninitialize();
    }
	
	// https://docs.microsoft.com/en-us/windows/win32/learnwin32/example--the-open-dialog-box
}


 /* 26_findSubStr_impl.h -- интерфейс  */
 
#include <stdint.h> // для int64_t

#ifndef _FIND_SUB_STR_IMPL_
#define _FIND_SUB_STR_IMPL_

// создается таблица состояний автомата для Шаблона, которую можно использовать
// для поиска Шаблона в разных файлах.	
//вход 
// pattern - шаблон/фраза, который нужно искать
//
// выход
// nextState - указатель на двухмерный массив размером m * colNum
//       colNum всегда равно 256
// m - максимальный номер состояния автомата, или длина шаблона
//
// возврат. 0 - хорошо. 1 - нет памяти
uint8_t createNextState(const char * pattern, int64_t ** nextState, int64_t m);

// Поиск подстроки в строке
// вход
// text - указатель на файл с данными(текстом), где нужно искать шаблон
// _file_size - длина файла
// nextState - указатель на уже созданную таблицу состояний
// m - максимальный номер состояния автомата( длина шаблона)
// выход
// n_out - количество найденных совпадений
// arr_out - указатель на массив смещений ( от 0 ) от начала text. Или null
//
// возврат 1, если возникли разные ошибки при работе функции (не связано с выделением памяти).
//
// переданные указатель на файл с текстом (массив данных). Кодировка не важна.
// передается готовая таблица состояний.
// формируется связный список, который заполняется смещениями.
// после окончания поиска создаётся массив и туда копируются все элементы связного списка.
//
uint8_t findSubStr(const char * text, int64_t _file_size, int64_t * nextState, int64_t m, int64_t * n_out, int64_t ** arr_out);

//открывает файл на чтение. Выделяет память под него. 
//вход 
// fname - имя файла
//выход
// str - данные файла
// _file_size - размер файла
// возврат. 0 - хорошо. 1 - нет памяти, другое ; 2 - ошибка при открытии файла; 3 - пустой файл
uint8_t getTextW(const wchar_t * fname, char ** str, int64_t * _file_size);

#endif


 /* 26_findSubStr_impl.c -- реализация  */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h> // для int64_t
#include <windows.h>
#include <inttypes.h> // для правильного вывода int64_t в printf
#include "26_findSubStr_impl.h"

#define colNum 256

	typedef struct node {
		int64_t value;
		struct node * next;
	} Node;
	
	typedef struct list {
		Node * head;
		Node * current;
		int64_t length;
	} List;


static void initList(List * lst);
static void freeList(List * lst);
static uint8_t addToList(List * lst, int64_t value);
static uint8_t ListToArray(List * lst, int64_t ** arr_out);	
	

uint8_t createNextState(const char * pattern, int64_t ** nextState, int64_t m){
		
	char * Pk; //суффикс подстроки
	int j;
	
	int64_t PkLen, i,  PKi, Pkinc, PKi2;
    
	short int equal;
	
	*nextState = malloc( sizeof(int64_t) * ( m +1) * colNum ); // 256 столбцов для всех значений из байта
	if ( *nextState == NULL )
		return 1;
	
	Pk = malloc( m + 2 ); // 
	if ( Pk == NULL ){
		free(*nextState);
		*nextState = NULL;
		return 1;
	}
	
	*Pk = '\0'; // ?
	
	// I I I I I I I I I I формирование таблицы состояний I I I I I I I I I I 
	for ( i = 0; i <= m ; i++ ){
		for ( j = 0; j <= colNum ; j++ ){  // for ( j = 0; j <= 127 ; j++ ){  // 
			
			//берем очередной возможный символ и присоединяем его справа к префиксу подстроки
			if ( i > 0 ){
				strncpy(Pk, pattern, i);
				*(Pk+i) = (char)j;
				*(Pk+i+1) = '\0';
				PkLen = i + 1;
			}else {
				*(Pk) = (char)j;
				*(Pk+1) = '\0';
				PkLen = 1;
			}
			
			PKi = PkLen;
			if ( PkLen > m ){
				PKi = m;
			}
			
again:		PKi2 = PKi;
			Pkinc = 1;
			// проверяю, является Pi суффиксом Pk ?
			
			while ( PKi2 > 0 ){   // сравнение последнего символа префикса подстроки и последнего символа суффикса прочитанного текста
				if ( *(pattern + PKi2 - 1 )  != *( Pk + PkLen - Pkinc ) ){
					break;
				}
				++Pkinc;
				--PKi2;
			}
			if ( PKi2 > 0 ){ // String's parts are not equal.
				--PKi;
				if (PKi > 0)
					goto again;
				else
					*( (*nextState) + i*colNum + j) = 0;
			}else{
				*( (*nextState) + i*colNum + j) = PKi;
			}
			
						
		}
		
	}
	
free(Pk);
return 0;
}

uint8_t findSubStr(const char * text, int64_t _file_size, int64_t * nextState, int64_t m, int64_t * n_out, int64_t ** arr_out){	
	
	int64_t state = (int64_t)0;
	int64_t i;
	uint8_t rez;
	
	List offsets;
		
	initList(&offsets);

	 for ( i = (int64_t)0; i < _file_size; i++ ){
		 
		 state = *( nextState + state*colNum + (unsigned char)*(text + i) );
		 
		 if( state == m ){
			 
			 if ( addToList(&offsets, i - m + 1) ){
				 freeList(&offsets);

				 return 1;
			 }
			 
		 }
		 
	 }
	 
	 *n_out = offsets.length;
	 
	 if ( *n_out > 0 ){
		 //создать массив и заполнить его смещениями из списка
		 
		 rez = ListToArray(&offsets, arr_out);
		 freeList(&offsets);		 
		 
		 if ( rez )
			 return rez;
	 }
	
	return 0;
}

 
 uint8_t getTextW(const wchar_t * fname, char ** str, int64_t * _file_size) {
	
	LARGE_INTEGER u_winFsz;
	DWORD  nNumberOfBytesToRead;		// typedef unsigned long DWORD;
	DWORD  NumberOfBytesRead;
	
	int64_t currPos = (int64_t)0; 
	int64_t size;
	
	HANDLE hFile;
	
	hFile = CreateFileW(fname, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL , NULL); // | FILE_FLAG_OVERLAPPED 
	if(hFile == INVALID_HANDLE_VALUE){
		*_file_size = -1;
		return 2;
	}
	else{
		GetFileSizeEx(hFile, &u_winFsz);
		*_file_size = u_winFsz.QuadPart;
		size = u_winFsz.QuadPart;
	}
	
	if ( *_file_size > (int64_t)0 ){
		*(str) = malloc(*_file_size);
		if ( *(str) == NULL ){
			CloseHandle(hFile);
			return 1;
		}

		do {
			nNumberOfBytesToRead = (size > (unsigned __int64) ULONG_MAX) ? ULONG_MAX : (unsigned long)size;  // 4294967295
		
			if ( ReadFile(hFile, *(str) + currPos, nNumberOfBytesToRead, &NumberOfBytesRead, NULL) == 0 )
				break;
				
			size -= NumberOfBytesRead;
			
			currPos += NumberOfBytesRead;
			
			
			
		} while ( size > 0 && NumberOfBytesRead == nNumberOfBytesToRead);
		
		CloseHandle(hFile);
		hFile = NULL;
			
		if ( size == 0 )
			return 0;
		else {
			free(*(str));
			return 1;
		}
	} else {
	
		if ( hFile != NULL )
			CloseHandle(hFile);
		return 3;
	}
 }
 
static void initList(List * lst){
	lst->head = NULL;
	lst->current = NULL;
	lst->length = (int64_t)0;
}

static void freeList(List * lst){
	Node * c, * n;
	
	c = lst->head;
	while ( c != NULL ){
		n = c->next;
		free(c);
		c = n;
	}
}

static uint8_t addToList(List * lst, int64_t value){
	
	Node * newNode;
	
	newNode = malloc(sizeof(Node));
	if ( newNode == NULL )
		return 1;
	
	newNode->next = NULL;
	newNode->value = value;
	
	if ( lst->head == NULL ){
		lst->head = newNode;
		lst->current = newNode;
		(lst->length)++;
	} else {
		lst->current->next = newNode;
		lst->current = newNode;
		(lst->length)++;
	}
	
	return 0;
}

static uint8_t ListToArray(List * lst, int64_t ** arr_out){
	
	int64_t il;
	
	il = lst->length;
	if ( il == 0 )
		return 0;
	
	Node * cn;
		
	*arr_out = malloc( il * sizeof(int64_t) );
	if ( *arr_out == NULL )
		return 1;
	
	cn = lst->head;
	il = 0;
	while ( cn != NULL ){
		*( *arr_out + il) = cn->value;
		il++;
		cn = cn->next;
	}
	
	return 0;
}


/* list_intr.h -- интерфейс списка */

#ifndef _LIST_INTR_
#define _LIST_INTR_
////////////////////////////////////////
typedef struct item {
		wchar_t * path1;
		unsigned int num1;
	} Item;
////////////////////////////////////////

typedef struct node {
	Item item;
	struct node * next;
} Node;

typedef struct paths{
	Node * begin;
	unsigned int nump;
	unsigned int lengthAllPaths1;    // длина путей всех файлов
} Paths;	

//инициализирует переменные
void initList(Paths * exPath);

//чтение данных из настроечного файла
//вход: exPath - указатель на список, куда будут добавлены пути файлов

//выход: заполнен список exPath; возвращает 0 в случае успешного выполнения
int ReadPaths(Paths * exPath, wchar_t * path);

//очищает занятую память
int freeList(Paths * exPath);

#endif


/* файл list_intr.c - реализация интерфейса*/

#include <windows.h>
#include <shlwapi.h>
#include <stdio.h>
#include "26_list_intr.h"

#define f1 L"\\*.*"

static void findFAdd(wchar_t * path, HANDLE handleNext, WIN32_FIND_DATAW * dataF, Paths * exPath, Node ** nextExInFind);

void initList(Paths * exPath){
	
	exPath->begin = NULL;
	exPath->nump = 0;
	exPath->lengthAllPaths1 = 0;
}

int ReadPaths(Paths * exPath, wchar_t * path){
	
	int  num, nb;
	
	wchar_t * pathN;
	
	
	WIN32_FIND_DATAW dataF;
	HANDLE handleNext;
	
	Node * nextEx = NULL;
	
			nb = sizeof(wchar_t);
					// sizeof(f1) = 10 ( not 8 )
			num = sizeof(f1) + wcslen(path) * sizeof(wchar_t) + nb;
			pathN = (wchar_t*) malloc( num );  
			if ( pathN == NULL )
				return 3;
			
			swprintf(pathN, num / nb, L"%s%s", path, f1); //check return value
			
			handleNext = FindFirstFileW( pathN, &dataF); 	// =>   dataF.cFileName = "."
		
			if ( handleNext != INVALID_HANDLE_VALUE ){

				findFAdd( path, handleNext, &dataF, exPath, &nextEx);
				FindClose(handleNext);	
			} 
			//else 	//можно обработать ошибку
			
			
			free(pathN);    // можно заменить выделение памяти под pathN на pathN[MAX_PATH]
	
	return 0;
}   // end ReadPaths()

// поиск вложенных файлов и добавление к основному списку существующих путей
static void findFAdd(wchar_t * path, HANDLE handleNext, WIN32_FIND_DATAW * dataF, Paths * exPath,
			Node ** nextExInFind){
	
	Node * tempNode;
	int len, mem = 0;
	wchar_t CurPath[MAX_PATH+1];
	
	while ( FindNextFileW(handleNext, dataF) != 0 ){
		
		if ( (dataF -> dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){
			
				swprintf(CurPath, MAX_PATH+1, L"%s\\%s", path, dataF -> cFileName); //check return value
					
				tempNode = malloc(sizeof(Node));
				if ( tempNode == NULL ){
					return; // ВОЗВРАТ БЕЗ ОПОВЕЩЕНИЯ
				}
			
				tempNode->next = NULL;
								
				len = wcslen(CurPath);
				
				mem = (len + 1)* sizeof(wchar_t);
				tempNode -> item.path1 = (wchar_t*) malloc ( mem ); // выделение памяти под путь
				if ( tempNode -> item.path1 == NULL ){
					return; // ВОЗВРАТ БЕЗ ОПОВЕЩЕНИЯ
				}
				
				wcscpy (tempNode -> item.path1, CurPath);		// копирование можно заменить выделением памяти
				tempNode -> item.num1 = len;      // без /0
				
				exPath->lengthAllPaths1 += len;
				
				if ( exPath->begin == NULL ){ // добавляем первый элемент
				
					exPath->begin = tempNode;
					*nextExInFind = tempNode;						
					exPath->nump++;
					
				} else {  // добавляем последующие элементы
				
					(*nextExInFind)->next = tempNode;
					*nextExInFind = tempNode;	
					exPath->nump++;	
				}
											
		} else {
						
			if ( (dataF -> cFileName)[0] == L'.' && (dataF -> cFileName)[1] == L'.' ) 	// ".."
				continue;
							
			wchar_t newDirF[MAX_PATH+1];
			_snwprintf(newDirF, MAX_PATH+1, L"%s\\%s", path, dataF -> cFileName);
			
			wchar_t pathN[MAX_PATH+1];
			_snwprintf(pathN, MAX_PATH+1, L"%s\\%s%s", path, dataF -> cFileName, f1);
			
			HANDLE handleNext2 = FindFirstFileW( pathN, dataF);	// =>   dataF.cFileName = "."
			
			findFAdd(newDirF, handleNext2, dataF, exPath, nextExInFind);
			
			FindClose(handleNext2);	
		}
	}	 
 }
			
int freeList(Paths * exPath){ 
	
	Node * currN = NULL;
	Node * nextN;
	
	currN = exPath->begin;

	while (currN != NULL){
		
		nextN = currN-> next;
		
		if (currN->item.path1 != NULL){
			free(currN->item.path1);
			
		}
		free(currN);
		currN = nextN;
	}
	exPath->nump = 0;
	exPath->lengthAllPaths1 = 0;
}

51 + 23

Комментарии




information