Created
January 4, 2016 11:47
-
-
Save naezith/c082373252c54ed29c44 to your computer and use it in GitHub Desktop.
Threaded File Walker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This code walks through text files which including "marks", calculates average of them in threads | |
#include <pthread.h> | |
#include <dirent.h> | |
#include <regex.h> | |
#include <stdio.h> | |
// Walks through all files, counts them and saves the directories to fileNames list | |
int getFileNames(const char* dir, const char* pattern, const char** * fileNamesOut, short* fileCountOut); | |
// Error Codes | |
enum {OK = 0, BADPATTERN, BADOPEN, BADALLOC, THREAD_BADCREATE, THREAD_BADJOIN}; | |
// Opens the file, prints the average of marks in it | |
void* printAverage(void* fileNamePtr); | |
int main(int argc, char** argv) { | |
printf("Average Calculation\r\n"); | |
do { | |
//Taking the folder name or DIR | |
printf("\r\nEnter the Folder DIR : "); | |
char* folderDir = (char*) malloc(256); // Buffer for user input, max path is 256 characters | |
if(folderDir == NULL) { | |
printf("Memory allocation failed."); | |
return BADALLOC; | |
} | |
gets(folderDir); | |
if(strcmp(folderDir, "q") == 0) return 0; // q for quit | |
//Variables | |
char** fileNames = NULL; // List of file directory strings | |
short fileCount = 0; | |
int status = -1, i; // Error code of getFileNames function | |
if((status = getFileNames(folderDir, ".txt", &fileNames, &fileCount)) != OK) { | |
free(folderDir); | |
printf("There was an error trying to read the directory given. Error Code: %d. Try again.", status); | |
continue; | |
} else if(fileCount == 0) { | |
free(folderDir); | |
printf("Couldn't find any .txt files in the given directory. Try again."); | |
continue; | |
} | |
free(folderDir); // We don't need folderDir anymore so we free the memory | |
// Allocate memory for threads | |
pthread_t* threads = malloc(fileCount * sizeof(pthread_t)); | |
if(threads == NULL) { | |
printf("\nFailed memory allocation\n"); | |
return BADALLOC; | |
} | |
// Create threads and print average of files one by one | |
for(i = 0; i < fileCount; i++) | |
if(pthread_create(&threads[i], NULL, &printAverage, (void*) fileNames[i])) { | |
printf("\nCould not create thread\n"); | |
return THREAD_BADCREATE; | |
} | |
// Join threads, wait functions to finish their work | |
for(i = 0; i < fileCount; i++) | |
if(pthread_join(threads[i], NULL)) { | |
printf("\nCould not join thread\n"); | |
return THREAD_BADJOIN; | |
} | |
free(threads); | |
free(fileNames); | |
} while(1); | |
return 0; | |
} | |
// Get all the files in the given directory. | |
int getFileNames(const char* dir, const char* pattern, const char** * fileNamesOut, short* fileCountOut) { | |
struct dirent* entry; | |
regex_t reg; | |
DIR* d; | |
short threadCount = 0, i; | |
char** fileNames = NULL; | |
unsigned short dirLen = strlen(dir) + 1; | |
char lastChar = dir[(dirLen == 1) ? 0 : (dirLen - 2)]; | |
//Fix the user input, add / to the end of DIR if there is not one | |
if(dirLen > 1 && lastChar != '\\' && lastChar != '/') {strcat(dir, "/"); dirLen++;} | |
// Initialize the walker and check for errors | |
if(regcomp(®, pattern, REG_EXTENDED | REG_NOSUB)) | |
return BADPATTERN; | |
if(!(d = opendir(dir))) | |
return BADOPEN; | |
// Walk through all files, count them and save names | |
while(entry = readdir(d)) | |
if(!regexec(®, entry->d_name, 0, NULL, 0)) { | |
threadCount++; | |
// Expand the fileNames list | |
fileNames = (char**) realloc(fileNames, threadCount * sizeof(char*)); | |
if(fileNames == NULL) { | |
printf("Memory allocation failed."); | |
return BADALLOC; | |
} | |
// Allocate memory for the full DIR and save it | |
fileNames[threadCount - 1] = (char*) malloc(dirLen + entry->d_namlen); | |
strcpy(fileNames[threadCount - 1], dir); | |
strcat(fileNames[threadCount - 1], entry->d_name); | |
} | |
closedir(d); | |
regfree(®); | |
//Return the info | |
*fileNamesOut = fileNames; | |
*fileCountOut = threadCount; | |
return OK; | |
} | |
// printAverage function - Opens the file, prints average of marks in it | |
void* printAverage(void* fileNamePtr) { | |
char* fileName = (char*) fileNamePtr; // Convert the fileName pointer back to char* | |
FILE* fr; | |
short lineCount = 0, sum = 0, mark; | |
char line[4]; // 4 Characters are enough for a mark <=100 | |
// Open the file and read it line by line, sum up marks | |
fr = fopen(fileName, "rt"); | |
while(fgets(line, 4, fr) != NULL) { | |
sscanf(line, "%d", &mark); | |
sum += mark; | |
lineCount++; | |
} | |
fclose(fr); | |
printf("\n\n%s\nAverage : %.2f", fileName, (float) sum / lineCount); | |
free(fileNamePtr); // Free the string-sized memory | |
pthread_exit(NULL); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment