# `Ash.Type.File`
[🔗](https://github.com/ash-project/ash/blob/v3.23.1/lib/ash/type/file.ex#L5)

A type that represents a file on the filesystem.

> #### Persistence {: .warning}
>
> This type does not support persisting via `Ash.DataLayer`.
>
> It is mainly intended to be used in
> [arguments](dsl-ash-resource.html#actions-action-argument).

## Valid values to cast

This type can cast multiple types of values:

* itself
* `Plug.Upload`
* Any value that implements the `Ash.Type.File.Source` protocol.

# `t`

```elixir
@type t() :: %Ash.Type.File{
  implementation: Ash.Type.File.Implementation.t(),
  source: Ash.Type.File.Implementation.source()
}
```

# `content_type`

```elixir
@spec content_type(file :: t()) ::
  {:ok, String.t()}
  | {:error, :not_supported | Ash.Type.File.Implementation.error()}
```

Returns the MIME content type of the file.

Not every implementation will support this operation. If the implementation
does not support this operation, then `{:error, :not_supported}` will be
returned.

## Example

    iex> file = Ash.Type.File.from_path("photo.png")
    ...> Ash.Type.File.content_type(file)
    {:error, :not_supported}

# `filename`

```elixir
@spec filename(file :: t()) ::
  {:ok, String.t()}
  | {:error, :not_supported | Ash.Type.File.Implementation.error()}
```

Returns the filename of the file.

Not every implementation will support this operation. If the implementation
does not support this operation, then `{:error, :not_supported}` will be
returned.

## Example

    iex> path = "README.md"
    ...> file = Ash.Type.File.from_path(path)
    ...> Ash.Type.File.filename(file)
    {:ok, "README.md"}

# `from_io`

```elixir
@spec from_io(device :: IO.device()) :: t()
```

Create a file from an `IO.device()`

## Example

    iex> path = "README.md"
    ...> {:ok, device} = File.open(path)
    ...> Ash.Type.File.from_io(device)
    %Ash.Type.File{source: device, implementation: Ash.Type.File.IO}

# `from_path`

```elixir
@spec from_path(path :: Path.t()) :: t()
```

Create a file from a path.

## Example

    iex> path = "README.md"
    ...> Ash.Type.File.from_path(path)
    %Ash.Type.File{source: "README.md", implementation: Ash.Type.File.Path}

# `handle_change?`

# `open`

```elixir
@spec open(file :: t(), modes :: [File.mode()]) ::
  {:ok, IO.device()} | {:error, Ash.Type.File.Implementation.error()}
```

Open the file with the given `modes`.

This function will delegate to the `open/2` function on the `implementation`.

For details on the `modes` argument, see the `File.open/2` documentation.

## Example

    iex> path = "README.md"
    ...> file = Ash.Type.File.from_path(path)
    ...> Ash.Type.File.open(file, [:read])
    ...> # => {:ok, #PID<0.109.0>}

# `path`

```elixir
@spec path(file :: t()) ::
  {:ok, Path.t()}
  | {:error, :not_supported | Ash.Type.File.Implementation.error()}
```

Returns the path to the file.

Not every implementation will support this operation. If the implementation
does not support this operation, then `{:error, :not_supported}` will be
returned. In this case, use the `open/2` function to access the file.

## Example

    iex> path = "README.md"
    ...> file = Ash.Type.File.from_path(path)
    ...> Ash.Type.File.path(file)
    {:ok, "README.md"}

# `prepare_change?`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
