You may have heard the phrase "Everything is a file" in relation to how
things work in Linux or Unix.

Normal files

What's meant by this, is that most things in Linux share something in
common with files.

For example, regular files are opened with the open(2) system call,
but so are directories with the O_DIRECTORY flag, which is how the
standard library's opendir(3) works.

Symbolic links aren't generally openable, but every file path is openable
with the O_PATH option, which along with directory file descriptors,
can be passed to system calls like fchdir(2) or the *at(2)
family of system calls.

Devices

Along with all the normal files, there's also special device files in
/dev.

There's block devices, like /dev/sda, which represent your physical
devices. These let you store persistent data, usually by mounting them as a file system with the mount(2) system call.

Because block devices are files, they can be copied like any normal file
to make backups.

There's also a variety of character devices, you are unlikely to need to
know all of them, but there's a hand-full of useful ones that everyone
should be aware of, like /dev/null, which allows you to discard all
writes to a file, everywhere a file is needed, but you don't need the
output that would be written there.

There's also /dev/full, which can be used to test how a program handles
low space conditions, by always saying that there's no space to write
to the file.

/dev/zero produces an inexhaustible supply of zero-bytes, which can be convenient for obliterating the contents of another file.

/dev/random and /dev/urandom are the traditional interfaces to the
random number generator, though getrandom(2) is a recent addition,
which doesn't require a file to be opened, so it's available when /dev
is not reachable, and when you are at your file descriptor limit.

There's also many files in /dev that only work with open(2),
close(2) and the device-specific ioctl(2) system call, which is
not massively like regular files, but there is still value in sharing
the same ownership semantics.

Sockets

There is also the mkfifo(3) system call, which creates a "named
pipe", which is an alternative way of creating pipes to the pipe(2)
system call, which is often easier to use to have two processes have
either end of a pipe.

Speaking of which, the read end of a pipe can be read like any regular
file, and the write end can be written like any regular file. This is
how pipelines work.

unix(7) sockets also appear on the file system, and unlike pipes,
the resultant file descriptor can be both read from and written to.

There's also a variety of other types of sockets that can't be opened
from the file system, typically created with the socket(2) or
socketpair(2) system calls.

Other files

There's plenty of other file-like objects that are made availably by
more esoteric system calls.

There's the memfd_create(2) system call for creating anonymous
memory maps, which can later be sealed and passed to another process,
as a way of sharing data structures between processes.

Sealing the file descriptor is required so that the data can safely
be passed around, since if the receiver can't trust that it won't be
modified by the sender, then it can't safely use it, since you could
change it while it is being used.

Most system calls that handle resources will reference them with a file
descriptor, so an exhaustive list would be both boring and very
long, but if you're interested in learning about others, just browse
man7.org.