# FileSystem

The `effect/FileSystem` module provides a set of operations for reading and writing from/to the file system.

## Basic Usage

The module provides a single `FileSystem` [service key](/docs/v4/requirements-management/services/), which acts as the gateway for interacting with the filesystem.

**Example** (Accessing File System Operations)

```ts
import { Effect, FileSystem } from "effect"

const program = Effect.gen(function* () {
  const fs = yield* FileSystem.FileSystem

  // Use `fs` to perform file system operations
})

Effect.isEffect(program) // => true
```

The `FileSystem` interface includes the following operations:

| Operation                   | Description                                                                                                                                                            |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **access**                  | Check if a file can be accessed. You can optionally specify the level of access to check for.                                                                          |
| **copy**                    | Copy a file or directory from `fromPath` to `toPath`. Equivalent to `cp -r`.                                                                                           |
| **copyFile**                | Copy a file from `fromPath` to `toPath`.                                                                                                                               |
| **chmod**                   | Change the permissions of a file.                                                                                                                                      |
| **chown**                   | Change the owner and group of a file.                                                                                                                                  |
| **exists**                  | Check if a path exists.                                                                                                                                                |
| **link**                    | Create a hard link from `fromPath` to `toPath`.                                                                                                                        |
| **makeDirectory**           | Create a directory at `path`. You can optionally specify the mode and whether to recursively create nested directories.                                                |
| **makeTempDirectory**       | Create a temporary directory. By default, the directory will be created inside the system's default temporary directory.                                               |
| **makeTempDirectoryScoped** | Create a temporary directory inside a scope. Functionally equivalent to `makeTempDirectory`, but the directory will be automatically deleted when the scope is closed. |
| **makeTempFile**            | Create a temporary file. The directory creation is functionally equivalent to `makeTempDirectory`. The file name will be a randomly generated string.                  |
| **makeTempFileScoped**      | Create a temporary file inside a scope. Functionally equivalent to `makeTempFile`, but the file will be automatically deleted when the scope is closed.                |
| **open**                    | Open a file at `path` with the specified `options`. The file handle will be automatically closed when the scope is closed.                                             |
| **readDirectory**           | List the contents of a directory. You can recursively list the contents of nested directories by setting the `recursive` option.                                       |
| **readFile**                | Read the contents of a file.                                                                                                                                           |
| **readFileString**          | Read the contents of a file as a string.                                                                                                                               |
| **readLink**                | Read the destination of a symbolic link.                                                                                                                               |
| **realPath**                | Resolve a path to its canonicalized absolute pathname.                                                                                                                 |
| **remove**                  | Remove a file or directory. By setting the `recursive` option to `true`, you can recursively remove nested directories.                                                |
| **rename**                  | Rename a file or directory.                                                                                                                                            |
| **sink**                    | Create a writable `Sink` for the specified `path`.                                                                                                                     |
| **stat**                    | Get information about a file at `path`.                                                                                                                                |
| **stream**                  | Create a readable `Stream` for the specified `path`.                                                                                                                   |
| **symlink**                 | Create a symbolic link from `fromPath` to `toPath`.                                                                                                                    |
| **truncate**                | Truncate a file to a specified length. If the `length` is not specified, the file will be truncated to length `0`.                                                     |
| **utimes**                  | Change the file system timestamps of the file at `path`.                                                                                                               |
| **watch**                   | Watch a directory or file for changes.                                                                                                                                 |
| **writeFile**               | Write data to a file at `path`.                                                                                                                                        |
| **writeFileString**         | Write a string to a file at `path`.                                                                                                                                    |

**Example** (Reading a File as a String)

```ts
import { Effect, FileSystem } from "effect"
import { NodeServices, NodeRuntime } from "@effect/platform-node"

//      ┌─── Effect<void, PlatformError, FileSystem>
//      ▼
const program = Effect.gen(function* () {
  const fs = yield* FileSystem.FileSystem

  // Reading the content of the same file where this code is written
  const content = yield* fs.readFileString("./index.ts", "utf8")
  console.log(content)
})

// Provide the necessary context and run the program
NodeRuntime.runMain(program.pipe(Effect.provide(NodeServices.layer)))
```

## Mocking the File System

In testing environments, you may want to mock the file system to avoid performing actual disk operations. The `FileSystem.layerNoop` provides a no-operation implementation of the `FileSystem` service.

Most operations in `FileSystem.layerNoop` return a **failure** (e.g., `Effect.fail` for missing files) or a **defect** (e.g., `Effect.die` for unimplemented features).
However, you can override specific behaviors by passing an object to `FileSystem.layerNoop` to define custom return values for selected methods.

**Example** (Mocking File System with Custom Behavior)

```ts
import { Effect, FileSystem } from "effect"

const program = Effect.gen(function* () {
  const fs = yield* FileSystem.FileSystem

  const exists = yield* fs.exists("/some/path")
  console.log(exists)
  exists // => true

  const content = yield* fs.readFileString("/some/path")
  console.log(content)
  content // => "mocked content"
})

//      ┌─── Layer<FileSystem.FileSystem, never, never>
//      ▼
const customMock = FileSystem.layerNoop({
  readFileString: () => Effect.succeed("mocked content"),
  exists: (path) => Effect.succeed(path === "/some/path"),
})

// Provide the customized FileSystem mock implementation
Effect.runPromise(program.pipe(Effect.provide(customMock)))
```
