---
title: Save report
summary: Renders a report if the destination file is missing or a refresh is requested, then writes the rendered bytes to disk.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-07-30
library: SAIF.Services.Printing
reference_type: package
operation_id: OP-PRT-07
trigger: Caller invokes ReportBase.Save(overwrite)
---

# Save report

`ReportBase.Save` persists a rendered report to a file path the caller has configured through `DestinationFileName`. It checks whether the file already exists before deciding whether to render and write, so repeat calls without `overwrite` do not regenerate an existing file.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-PRT-07 |
| **Trigger** | Caller invokes `ReportBase.Save(overwrite)` after setting `DestinationFileName` |
| **Inputs** | `DestinationFileName`; optional `overwrite` flag |
| **Outputs** | A file written to `DestinationFileName`; boolean result reflecting whether the file exists after the call |
| **Primary components** | `Reporting.ReportBase.Save`, `Reporting.ReportBase.Render` |
| **Entry point** | `Services\SAIF.Services.Printing\Reporting\ReportBase.vb` |

## Steps

1. `Save` checks whether a file already exists at `DestinationFileName` using `IO.File.Exists`.
2. If the file does not exist, or `overwrite` is `True`:
   - `Save` checks that `DestinationFileName` has a non-zero length.
     - If a destination is configured: `Save` calls `Render(overwrite)` — see [Render report](render-report.md) — to ensure rendered bytes are available ([BR-004](../business-rules.md#br-004-rendered-bytes-are-reused-until-overwrite-is-requested)).
     - `Save` opens `DestinationFileName` with `IO.FileStream` in `Create` mode and writes the full `m_reportFile` byte array to it.
   - If `DestinationFileName` is empty: no render or write is attempted.
3. `Save` returns `IO.File.Exists(DestinationFileName)` as the final result, re-checking the file system rather than returning a cached success flag.

## Process flow

The following diagram visualizes the exists-check, render, and write sequence.

```mermaid
flowchart TD
	Start([Save called with overwrite]) --> Exists{File already<br>exists at destination?}
	Exists -->|Yes, overwrite = False| Skip[Skip render and write]
	Exists -->|No, or overwrite = True| HasDest{DestinationFileName<br>non-empty?}
	HasDest -->|No| Skip
	HasDest -->|Yes| Render[Call Render overwrite]
	Render --> Write[Write ReportFile bytes<br>to DestinationFileName]
	Write --> Recheck
	Skip --> Recheck[Re-check IO.File.Exists]
	Recheck --> End([Return existence result])
```

## Failure and edge-case behavior

- If `Render(overwrite)` fails and leaves `m_reportFile` as `Nothing`, the subsequent `fs.Write(m_reportFile, 0, m_reportFile.Length)` call would raise a `NullReferenceException`; `Save` does not check for a `Nothing` `ReportFile` before writing, and no `Try`/`Catch` wraps this step.**
- `Save` returns the file system's current existence state rather than a flag captured at write time, so a file removed by another process between the write and the return would still be reflected accurately, but a `Save` call that skipped rendering entirely (because the file already existed) returns `True` even though no new content was written.*
- A destination path with an existing file and `overwrite = False` results in `Save` treating the call as a no-op success without attempting to render or verify the existing file's content matches the current report state.*

> **Note:** Statements marked with * were inferred from code structure, naming conventions, or
> contextual evidence where direct confirmation was not available in source artifacts. Statements
> marked with ** could not be confirmed; treat as unknown until verified.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

## Sources
- `Services\SAIF.Services.Printing\Reporting\ReportBase.vb`
