🕵️📁 Local File Search Tool (Part 3): Search in files content


The evolution of our local search tool continues 😄 (if you missed the previous episodes you can take a look here and here).

In this episode we will see how to integrate the search functionality into the contents of files 📝 (and not just the file name).

🔗 Do you like Techelopment? Check out the site for all the details!

Objective

The goal of this evolution of the tool is to extend the search to the file content so as to identify the keyword not only in the file or folder name but also within the text of the files.

We must therefore give the user the ability to choose how to perform the search:

  1. Only in the name (file + folders) — current behavior of the tool developed in previous articles

  2. In the contents of the files — in addition to searching in the name, the program must open the files and search their contents

The extension is completely transparent to the user: just enter a name and the program searches everywhere, in folders, files and file contents.


Code

import os
import time
import subprocess
import platform


# -----------------------------
# OPEN FOLDER
# -----------------------------
def open_folder(path):
    system = platform.system()

    if system == "Windows":
        os.startfile(path)
    elif system == "Darwin":  # macOS
        subprocess.Popen(["open", path])
    else:  # Linux
        subprocess.Popen(["xdg-open", path])


# -----------------------------
# OPEN FILE
# -----------------------------
def open_file(path):
    system = platform.system()

    if system == "Windows":
        os.startfile(path)
    elif system == "Darwin":  # macOS
        subprocess.Popen(["open", path])
    else:  # Linux
        subprocess.Popen(["xdg-open", path])


# -----------------------------
# MAIN LOOP
# -----------------------------
while True:

    root = input("Search in (or type 'exit' to quit): ").strip()
    if root.lower() == "exit":
        print("Program terminated.")
        break

    if not os.path.isdir(root):
        print("Invalid path.\n")
        continue

    name = input("Search term (file/folder name or content): ").strip()
    if name.lower() == "exit":
        print("Program terminated.")
        break

    # -----------------------------
    # CHOOSE SEARCH MODE
    # -----------------------------
    print("\nChoose search mode:")
    print("1) Search only in file/folder NAMES")
    print("2) Search also inside FILE CONTENTS")

    while True:
        mode = input("> ").strip()
        if mode in ("1", "2"):
            break
        print("Invalid choice. Type 1 or 2.")

    search_in_content = (mode == "2")

    print("\nSearching...")
    start_time = time.time()

    found_paths = []  # files + folders
    found_files = []  # only files (for opening later)
    found_folders = []  # only folders (actual folders found)

    # -----------------------------
    # SEARCH EXECUTION
    # -----------------------------
    for path, dirs, files in os.walk(root):

        # ---- SEARCH IN FOLDER NAMES ----
        for dirname in dirs:
            if name.lower() in dirname.lower():
                folder_path = os.path.join(path, dirname)
                found_paths.append(folder_path)
                found_folders.append(folder_path)
                print("📁 Found folder:", folder_path)

        # ---- SEARCH IN FILE NAMES ----
        for filename in files:
            if name.lower() in filename.lower():
                file_path = os.path.join(path, filename)
                found_paths.append(file_path)
                found_files.append(file_path)
                print("📄 Found file:", file_path)

        # ---- SEARCH IN FILE CONTENTS (optional) ----
        if search_in_content:
            for filename in files:
                file_path = os.path.join(path, filename)

                try:
                    with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
                        for line in f:
                            if name.lower() in line.lower():
                                if file_path not in found_paths:
                                    found_paths.append(file_path)
                                    found_files.append(file_path)
                                    print("📝 Found in content:", file_path)
                                break
                except:
                    pass

    duration = time.time() - start_time
    print(f"\nSearch completed in {duration:.3f} seconds.")

    if not found_paths:
        print("No results found.\n")
        continue

    # -----------------------------
    # UNIQUE FOLDERS FOR THE FINAL MENU
    # -----------------------------
    unique_folders = set()

    for p in found_paths:
        if os.path.isdir(p):
            unique_folders.add(p)  # actual folder found
        else:
            unique_folders.add(os.path.dirname(p))  # parent folder of file

    unique_folders = sorted(unique_folders)
    found_files = sorted(found_files)

    # -----------------------------
    # FINAL MENU FOR OPENING ITEMS
    # -----------------------------
    while True:
        print("\nWould you like to open something?")
        print("1) Open a folder")
        print("2) Open a file")
        print("no) Continue to new search\n")

        choice = input("> ").strip().lower()

        if choice == "no":
            print("")
            break

        # ---- OPEN FOLDERS ----
        if choice == "1":
            print("\n=== FOLDERS ===")
            for i, folder in enumerate(unique_folders, 1):
                print(f"{i}) 📁 {folder}")

            sel = input("\nChoose a folder number (or 'no'): ").strip()
            if sel.lower() == "no":
                continue
            if sel.isdigit():
                index = int(sel)
                if 1 <= index <= len(unique_folders):
                    folder = unique_folders[index - 1]
                    print("Opening:", folder)
                    open_folder(folder)
                else:
                    print("Invalid number.")
            continue

        # ---- OPEN FILES ----
        if choice == "2":
            if not found_files:
                print("No files available to open.")
                continue

            print("\n=== FILES ===")
            for i, file in enumerate(found_files, 1):
                print(f"{i}) 📄 {file}")

            sel = input("\nChoose a file number (or 'no'): ").strip()
            if sel.lower() == "no":
                continue
            if sel.isdigit():
                index = int(sel)
                if 1 <= index <= len(found_files):
                    file = found_files[index - 1]
                    print("Opening:", file)
                    open_file(file)
                else:
                    print("Invalid number.")
            continue

        print("Invalid choice.")


Example Output

 
Choose search mode: 
1) Search only in file/folder NAMES 
2) Search also inside FILE CONTENTS 

> 2 

Searching... 
📄 Found file: C:\Users\Example\Desktop\project.txt 
📄 Found file: C:\Users\Example\Desktop\project.xlsx 
📝 Found in content:C:\Users\Example\Desktop\MasterPlan.pptx 
📁 Found folder: C:\Users\Example\Desktop\Project 

Search completed in 5,237 seconds. 

Would you like to open something? 
1) Open a folder 
2) Open to file 
no) Continue to new search 

> 2 

=== FILES === 
1) 📄 C:\Users\Example\Desktop\project.txt 
2) 📄 C:\Users\Example\Desktop\project.xlsx 
3) 📄 C:\Users\Example\Desktop\MasterPlan.pptx 

Choose a file number (or 'no'): 1 
Opening: C:\Users\Example\Desktop\project.txt

🎉 What does the program do now?

✔ Search in file names

✔ Search in folder names

Optional: Also search file contents

✔ Show separate lists:

        📁 folders that match directly

        🗂 folders that contain found files

        ✔ Avoid duplicates

        ✔ Maintains all folder opening functionality

        ✔ Avoid errors on binary or overly large files


Conclusion

Thanks to this new feature, the tool is now able to perform 360° searches — a bit like we would do with Windows, but much faster.

Happy searching 🔎!


 


Follow me #techelopment

Official site: www.techelopment.it
facebook: Techelopment
instagram: @techelopment
X: techelopment
Bluesky: @techelopment
telegram: @techelopment_channel
whatsapp: Techelopment
youtube: @techelopment