Created
May 25, 2022 12:50
-
-
Save yashtibrewal/e8a59d40617df74ae07bdfcf283dda01 to your computer and use it in GitHub Desktop.
Multithreading Alternate (ZTM)
This file contains hidden or 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
package main | |
import ( | |
"bufio" | |
"fmt" | |
"io/ioutil" | |
"os" | |
"strings" | |
"sync" | |
) | |
//--Summary: | |
// Create a grep clone that can do simple substring searching | |
// within files. It must auto-recurse into subdirectories. | |
// | |
//--Requirements: | |
//* Use goroutines to search through the files for a substring match | |
//* Display matches to the terminal as they are found | |
// * Display the line number, file path, and complete line containing the match | |
//* Recurse into any subdirectories looking for matches | |
//* Use any synchronization method to ensure that all files | |
// are searched, and all results are displayed before the program | |
// terminates. | |
// | |
//--Notes: | |
//* Program invocation should follow the pattern: | |
// mgrep search_string search_dir | |
/* | |
Solution: | |
1. A function which recieves a handler to a file and searches for the word in the file | |
2. A function which iterates through all the files a directory and recurses subdirectories | |
*/ | |
type SearchResult struct { | |
lineNumber int | |
filePath string | |
line string | |
} | |
func (r *SearchResult) String() string { | |
return fmt.Sprintf("Line Number: %d, File Path: %s, Line: %v", r.lineNumber, r.filePath, r.line) | |
} | |
type SearchResults struct { | |
mutex sync.Mutex | |
waitGroup sync.WaitGroup | |
searchResults []SearchResult | |
} | |
func searchFile(filePath string, searchString string, searchResults *SearchResults) { | |
// Read the file line by line | |
// check if the line contains the search string | |
fmt.Println(filePath, " opening") | |
fileHandle, err := os.Open(filePath) | |
if err != nil { | |
fmt.Printf("Error reading file %v %v\n", filePath, err.Error()) | |
} | |
defer fileHandle.Close() | |
fileScanner := bufio.NewScanner(fileHandle) | |
fileScanner.Split(bufio.ScanLines) | |
lineNumber := 0 | |
for fileScanner.Scan() { | |
lineNumber++ | |
line := fileScanner.Text() | |
found := strings.Contains(line, searchString) | |
if found { | |
searchResults.mutex.Lock() | |
searchResult := SearchResult{ | |
lineNumber: lineNumber, | |
filePath: filePath, | |
line: line, | |
} | |
searchResults.searchResults = append(searchResults.searchResults, searchResult) | |
searchResults.mutex.Unlock() | |
} | |
} | |
searchResults.waitGroup.Done() | |
} | |
func analyzeDirector(dir string, searchString *string, searchResults *SearchResults) { | |
files, err := ioutil.ReadDir(dir) | |
if err != nil { | |
fmt.Println(err.Error()) | |
} | |
for _, file := range files { | |
if !file.IsDir() { // call the go routune in this file | |
searchResults.waitGroup.Add(1) | |
go searchFile(file.Name(), *searchString, searchResults) | |
} else { | |
analyzeDirector(file.Name(), searchString, searchResults) | |
} | |
} | |
searchResults.waitGroup.Wait() | |
} | |
func main() { | |
args := os.Args | |
args = args[1:] // remove the program name | |
if len(args) != 2 { | |
fmt.Printf("Please enter the directory and search string") | |
return | |
} | |
searchString := args[0] | |
directory := args[1] | |
searchResults := SearchResults{} | |
fmt.Println("Starting the search on files") | |
analyzeDirector(directory, &searchString, &searchResults) | |
fmt.Println("Search Completed") | |
for i := 0; i < len(searchResults.searchResults); i++ { | |
result := searchResults.searchResults[i] | |
fmt.Println(result) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment