Skip to content

Instantly share code, notes, and snippets.

@naezith
Created January 4, 2016 11:47
Show Gist options
  • Save naezith/c082373252c54ed29c44 to your computer and use it in GitHub Desktop.
Save naezith/c082373252c54ed29c44 to your computer and use it in GitHub Desktop.
Threaded File Walker
// 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(&reg, 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(&reg, 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(&reg);
//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