Read File

Opens the specified file and reads its entire contents into memory either as a text or a binary (bytes).

Read File


Processing

Reads the contents of a specified file into memory, either as text or binary (bytes) data, based on the selected mode. Returns the file content and associated metadata.

Inputs

path
The file path to read.

Inputs Types

Input Types
path Str, FilePath

You can check the list of supported types here: Available Type Hints.

Outputs

content
The file's contents, either as text or binary data.
metadata
A dictionary containing file metadata such as name, size, and modification date.

Outputs Types

Output Types
content Str, Bytes
metadata Dict

You can check the list of supported types here: Available Type Hints.

The metadata output contains the following metadata:

  • name: The name of the file.
  • size_bytes: The file size in bytes.
  • size_formatted: The file size in a human-readable format.
  • mimetype: The MIME type of the file.
  • type: The general type of the file.
  • type_detail: Detailed type information about the file.
  • date_modified: The file's last modification timestamp.
  • date_modified_str: The file's last modification date as a string.
  • full_path: The absolute path to the file.
  • relative_path: The relative path to the file.

Options

The Read File brick contains some changeable options:

Reading Mode
Selects the mode for reading the file, either 'automatic' (tries text first, falls back to binary) or 'binary' (reads as bytes).
Verbose
Enables or disables detailed logging of the file reading process.
import os
import logging
import mimetypes
from datetime import datetime
from coded_flows.types import Str, FilePath, Tuple, Bytes, Union, Dict

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


def _format_file_size(size_bytes):
    """Format file size in human-readable format."""
    if size_bytes == 0:
        return "0 B"
    size_names = ["B", "KB", "MB", "GB", "TB"]
    size = float(size_bytes)
    i = 0
    while size >= 1024.0 and i < len(size_names) - 1:
        size /= 1024.0
        i += 1
    return f"{size:.1f} {size_names[i]}"


def _get_item_metadata(path):
    """Extract metadata for a file or folder."""
    try:
        stat_info = path.stat()
        if path.is_file():
            item_type = "File"
            extension = path.suffix.lower() if path.suffix else "No extension"
            type_detail = (
                f"File ({extension})" if extension != "No extension" else "File"
            )
        elif path.is_dir():
            item_type = "Folder"
            type_detail = "Folder"
        else:
            item_type = "Other"
            type_detail = "Other"
        size_bytes = stat_info.st_size if path.is_file() else 0
        size_formatted = _format_file_size(size_bytes)
        modified_timestamp = stat_info.st_mtime
        modified_date = datetime.fromtimestamp(modified_timestamp)
        mime_type = mimetypes.guess_type(path)[0]
        return {
            "name": path.name,
            "size_bytes": size_bytes,
            "size_formatted": size_formatted,
            "mimetype": mime_type,
            "type": item_type,
            "type_detail": type_detail,
            "date_modified": modified_date,
            "date_modified_str": modified_date.strftime("%Y-%m-%d %H:%M:%S"),
            "full_path": str(path) + os.sep if path.is_dir() else str(path),
            "relative_path": (
                str(path.relative_to(path.parent)) if path.parent != path else str(path)
            ),
        }
    except (OSError, PermissionError):
        return {
            "name": None,
            "size_bytes": None,
            "size_formatted": None,
            "mimetype": None,
            "type": None,
            "type_detail": None,
            "date_modified": None,
            "date_modified_str": None,
            "full_path": None,
            "relative_path": None,
        }


def read_file(
    path: Union[Str, FilePath], options=None
) -> Tuple[Union[Str, Bytes], Dict]:
    brick_display_name = "Read File"
    if options is None:
        options = {}
    mode = options.get("mode", "automatic")
    verbose = options.get("verbose", True)
    p = FilePath(path)
    try:
        file_path = p.resolve(strict=True)
    except FileNotFoundError:
        verbose and logging.error(f"[{brick_display_name}] Path not found: '{path}'.")
        raise FileNotFoundError(f"Path not found: '{path}'")
    content = None
    metadata = {
        "name": None,
        "size_bytes": None,
        "size_formatted": None,
        "mimetype": None,
        "type": None,
        "type_detail": None,
        "date_modified": None,
        "date_modified_str": None,
        "full_path": None,
        "relative_path": None,
    }
    if file_path.is_file():
        verbose and logger.info(
            f"[{brick_display_name}] Using the '{mode}' mode for reading the file at '{path}'."
        )
        metadata = _get_item_metadata(file_path)
        if mode == "automatic":
            try:
                content = file_path.read_text(encoding="utf-8")
            except UnicodeDecodeError:
                content = file_path.read_bytes()
            except Exception as e:
                verbose and logger.error(
                    f"[{brick_display_name}] An unexpected error occurred in automatic mode!"
                )
                raise
        elif mode == "binary":
            try:
                content = file_path.read_bytes()
            except Exception as e:
                verbose and logger.error(
                    f"[{brick_display_name}] Error reading file as binary!"
                )
                raise
    else:
        verbose and logger.error(
            f"[{brick_display_name}] '{file_path}' is not a file path!"
        )
        raise ValueError(f"'{file_path}' is not a file path!")
    return (content, metadata)

Brick Info

version v0.1.4
python 3.10, 3.11, 3.12, 3.13
requirements
    -