Current section
Files
Jump to
Current section
Files
src/simplifile.gleam
import gleam/bit_string
/// This type represents all of the reasons for why a file system operation could fail.
///
/// Most of these reasons are POSIX errors, which come from the operating system
/// and start with E. Others have been added to represent other issues that may
/// arise specific to this library.
///
pub type FileError {
/// Permission denied.
Eacces
/// Resource temporarily unavailable.
Eagain
/// Bad file number
Ebadf
/// Bad message.
Ebadmsg
/// File busy.
Ebusy
/// Resource deadlock avoided.
Edeadlk
/// On most architectures, same as `Edeadlk`. On some architectures, it
/// means "File locking deadlock error."
Edeadlock
/// Disk quota exceeded.
Edquot
/// File already exists.
Eexist
/// Bad address in system call argument.
Efault
/// File too large.
Efbig
/// Inappropriate file type or format. Usually caused by trying to set the
/// "sticky bit" on a regular file (not a directory).
Eftype
/// Interrupted system call.
Eintr
/// Invalid argument.
Einval
/// I/O error.
Eio
/// Illegal operation on a directory.
Eisdir
/// Too many levels of symbolic links.
Eloop
/// Too many open files.
Emfile
/// Too many links.
Emlink
/// Multihop attempted.
Emultihop
/// Filename too long
Enametoolong
/// File table overflow
Enfile
/// No buffer space available.
Enobufs
/// No such device.
Enodev
/// No locks available.
Enolck
/// Link has been severed.
Enolink
/// No such file or directory.
Enoent
/// Not enough memory.
Enomem
/// No space left on device.
Enospc
/// No STREAM resources.
Enosr
/// Not a STREAM.
Enostr
/// Function not implemented.
Enosys
/// Block device required.
Enotblk
/// Not a directory.
Enotdir
/// Operation not supported.
Enotsup
/// No such device or address.
Enxio
/// Operation not supported on socket.
Eopnotsupp
/// Value too large to be stored in data type.
Eoverflow
/// Not owner.
Eperm
/// Broken pipe.
Epipe
/// Result too large.
Erange
/// Read-only file system.
Erofs
/// Invalid seek.
Espipe
/// No such process.
Esrch
/// Stale remote file handle.
Estale
/// Text file busy.
Etxtbsy
/// Cross-domain link.
Exdev
/// File was requested to be read as UTF-8, but is not UTF-8 encoded.
NotUtf8
/// Any error not accounted for by this type
Unknown
}
/// Read a files contents as a string
/// ## Example
/// ```gleam
/// let assert Ok(records) = read(from: "./users.csv")
/// ```
///
pub fn read(from filepath: String) -> Result(String, FileError) {
do_read(filepath)
|> cast_error
}
/// Write a string to a file at the given path
/// ## Example
/// ```gleam
/// let assert Ok(Nil) = write("Hello, World!", to: "./hello_world.txt")
/// ```
///
pub fn write(contents: String, to filepath: String) -> Result(Nil, FileError) {
do_write(contents, to: filepath)
|> cast_error
}
/// Delete a file at a given filepath
/// ## Example
/// ```gleam
/// let assert Ok(Nil) = delete(file_at: "./delete_me.txt")
/// ```
///
pub fn delete(file_at filepath: String) -> Result(Nil, FileError) {
do_delete(filepath)
|> cast_error
}
/// Append a string to the contents of a file at the given path
/// ## Example
/// ```gleam
/// let assert Ok(Nil) = append("more text", to: "./needs_more_text.txt")
/// ```
///
pub fn append(contents: String, to filepath: String) -> Result(Nil, FileError) {
do_append(contents, to: filepath)
|> cast_error
}
/// Read a files contents as a bitstring
/// ## Example
/// ```gleam
/// let assert Ok(records) = read_bits(from: "./users.csv")
/// ```
///
pub fn read_bits(from filepath: String) -> Result(BitString, FileError) {
do_read_bits(filepath)
|> cast_error
}
/// Write a bitstring to a file at the given path
/// ## Example
/// ```gleam
/// let assert Ok(Nil) = write_bits(<<"Hello, World!":utf8>>, to: "./hello_world.txt")
/// ```
///
pub fn write_bits(
bits: BitString,
to filepath: String,
) -> Result(Nil, FileError) {
do_write_bits(bits, filepath)
|> cast_error
}
/// Append a bitstring to the contents of a file at the given path
/// ## Example
/// ```gleam
/// let assert Ok(Nil) = append_bits(<<"more text":utf8>>, to: "./needs_more_text.txt")
/// ```
///
pub fn append_bits(
bits: BitString,
to filepath: String,
) -> Result(Nil, FileError) {
do_append_bits(bits, filepath)
|> cast_error
}
/// Checks if the provided filepath is a directory
/// ## Example
/// ```gleam
/// let assert True = is_directory("./test")
/// ```
pub fn is_directory(filepath: String) -> Bool {
do_is_directory(filepath)
}
/// Make a directory at the provided filepath
///
/// ## Example
/// ```gleam
/// make_directory("./test")
/// ```
pub fn make_directory(filepath: String) -> Result(Nil, FileError) {
do_make_directory(filepath)
}
/// Delete a directory at the provided filepath
///
/// ## Example
/// ```gleam
/// delete_directory("./test")
/// ```
pub fn delete_directory(filepath: String) -> Result(Nil, FileError) {
do_delete_directory(filepath)
}
/// Lists the contents of a directory.
/// The list contains directory and file names, and is not recursive.
///
/// ## Example
/// ```gleam
/// let assert Ok(files_and_folders) = list_contents(of: "./Folder1")
/// ```
///
pub fn list_contents(of directory: String) -> Result(List(String), FileError) {
do_list_contents(directory)
}
@target(javascript)
import gleam/result
@target(javascript)
fn do_read(from filepath: String) -> Result(String, String) {
case do_read_bits(filepath) {
Ok(bit_str) -> {
case bit_string.to_string(bit_str) {
Ok(str) -> Ok(str)
_ -> Error("NOTUTF8")
}
}
Error(e) -> Error(e)
}
}
@target(javascript)
external fn do_write(String, to: String) -> Result(Nil, String) =
"./file.mjs" "writeFile"
@target(javascript)
external fn do_delete(file_at: String) -> Result(Nil, String) =
"./file.mjs" "deleteFile"
@target(javascript)
external fn do_append(String, to: String) -> Result(Nil, String) =
"./file.mjs" "appendFile"
@target(javascript)
external fn do_read_bits(from: String) -> Result(BitString, String) =
"./file.mjs" "readBits"
@target(javascript)
external fn do_write_bits(BitString, to: String) -> Result(Nil, String) =
"./file.mjs" "writeBits"
@target(javascript)
external fn do_append_bits(BitString, to: String) -> Result(Nil, String) =
"./file.mjs" "appendBits"
@target(javascript)
external fn do_is_directory(String) -> Bool =
"./file.mjs" "isDirectory"
@target(javascript)
external fn do_make_directory(String) -> Result(Nil, FileError) =
"./file.mjs" "makeDirectory"
@target(javascript)
external fn do_delete_directory(String) -> Result(Nil, FileError) =
"./file.mjs" "deleteDirectory"
@target(javascript)
external fn do_list_contents(String) -> Result(List(String), FileError) =
"./file.mjs" "listContents"
@target(javascript)
fn cast_error(input: Result(a, String)) -> Result(a, FileError) {
result.map_error(
input,
fn(e) {
case e {
"EACCES" -> Eacces
"EAGAIN" -> Eagain
"EBADF" -> Ebadf
"EBADMSG" -> Ebadmsg
"EBUSY" -> Ebusy
"EDEADLK" -> Edeadlk
"EDEADLOCK" -> Edeadlock
"EDQUOT" -> Edquot
"EEXIST" -> Eexist
"EFAULT" -> Efault
"EFBIG" -> Efbig
"EFTYPE" -> Eftype
"EINTR" -> Eintr
"EINVAL" -> Einval
"EIO" -> Eio
"EISDIR" -> Eisdir
"ELOOP" -> Eloop
"EMFILE" -> Emfile
"EMLINK" -> Emlink
"EMULTIHOP" -> Emultihop
"ENAMETOOLONG" -> Enametoolong
"ENFILE" -> Enfile
"ENOBUFS" -> Enobufs
"ENODEV" -> Enodev
"ENOLCK" -> Enolck
"ENOLINK" -> Enolink
"ENOENT" -> Enoent
"ENOMEM" -> Enomem
"ENOSPC" -> Enospc
"ENOSR" -> Enosr
"ENOSTR" -> Enostr
"ENOSYS" -> Enosys
"ENOBLK" -> Enotblk
"ENODIR" -> Enotdir
"ENOTSUP" -> Enotsup
"ENXIO" -> Enxio
"EOPNOTSUPP" -> Eopnotsupp
"EOVERFLOW" -> Eoverflow
"EPERM" -> Eperm
"EPIPE" -> Epipe
"ERANGE" -> Erange
"EROFS" -> Erofs
"ESPIPE" -> Espipe
"ESRCH" -> Esrch
"ESTALE" -> Estale
"ETXTBSY" -> Etxtbsy
"EXDEV" -> Exdev
"NOTUTF8" -> NotUtf8
_ -> Unknown
}
},
)
}
@target(erlang)
external fn do_append_bits(BitString, to: String) -> Result(Nil, FileError) =
"gleam_erlang_ffi" "append_file"
@target(erlang)
external fn do_write_bits(BitString, to: String) -> Result(Nil, FileError) =
"gleam_erlang_ffi" "write_file"
@target(erlang)
external fn do_read_bits(from: String) -> Result(BitString, FileError) =
"gleam_erlang_ffi" "read_file"
@target(erlang)
external fn do_delete(String) -> Result(Nil, FileError) =
"gleam_erlang_ffi" "delete_file"
@target(erlang)
fn do_append(content: String, to filepath: String) -> Result(Nil, FileError) {
content
|> bit_string.from_string
|> do_append_bits(filepath)
}
@target(erlang)
fn do_write(content: String, to filepath: String) -> Result(Nil, FileError) {
content
|> bit_string.from_string
|> do_write_bits(filepath)
}
@target(erlang)
fn do_read(from filepath: String) -> Result(String, FileError) {
case do_read_bits(filepath) {
Ok(bit_str) -> {
case bit_string.to_string(bit_str) {
Ok(str) -> Ok(str)
_ -> Error(NotUtf8)
}
}
Error(e) -> Error(e)
}
}
@target(erlang)
fn cast_error(input: Result(a, FileError)) -> Result(a, FileError) {
input
}
@target(erlang)
external fn do_is_directory(String) -> Bool =
"filelib" "is_dir"
@target(erlang)
external fn do_make_directory(directory: String) -> Result(Nil, FileError) =
"gleam_erlang_ffi" "make_directory"
@target(erlang)
external fn do_delete_directory(directory: String) -> Result(Nil, FileError) =
"gleam_erlang_ffi" "delete_directory"
@target(erlang)
external fn do_list_contents(
directory: String,
) -> Result(List(String), FileError) =
"gleam_erlang_ffi" "list_directory"