tokio/fs/mod.rs
1#![cfg(not(loom))]
2
3//! Asynchronous file utilities.
4//!
5//! This module contains utility methods for working with the file system
6//! asynchronously. This includes reading/writing to files, and working with
7//! directories.
8//!
9//! Be aware that most operating systems do not provide asynchronous file system
10//! APIs. Because of that, Tokio will use ordinary blocking file operations
11//! behind the scenes. This is done using the [`spawn_blocking`] threadpool to
12//! run them in the background.
13//!
14//! The `tokio::fs` module should only be used for ordinary files. Trying to use
15//! it with e.g., a named pipe on Linux can result in surprising behavior,
16//! such as hangs during runtime shutdown. For special files, you should use a
17//! dedicated type such as [`tokio::net::unix::pipe`] or [`AsyncFd`] instead.
18//!
19//! Tokio currently uses [`spawn_blocking`] on all platforms, but also uses
20//! io_uring for file operations on Linux when compiled with `tokio_unstable`.
21//! Operations that cannot be cancelled with [`spawn_blocking`] may possibly
22//! be cancelled with io_uring.
23//!
24//! # Cancellation
25//!
26//! Cancelling a future from this module will stop waiting for the result, but
27//! the underlying blocking operation will continue to run on the thread pool.
28//! For example, cancelling a [`write()`] future after it has been
29//! polled will still result in the data being written to disk.
30//!
31//! # Usage
32//!
33//! The easiest way to use this module is to use the utility functions that
34//! operate on entire files:
35//!
36//! * [`tokio::fs::read`](fn@crate::fs::read)
37//! * [`tokio::fs::read_to_string`](fn@crate::fs::read_to_string)
38//! * [`tokio::fs::write`](fn@crate::fs::write)
39//!
40//! The two `read` functions reads the entire file and returns its contents.
41//! The `write` function takes the contents of the file and writes those
42//! contents to the file. It overwrites the existing file, if any.
43//!
44//! For example, to read the file:
45//!
46//! ```
47//! # async fn dox() -> std::io::Result<()> {
48//! let contents = tokio::fs::read_to_string("my_file.txt").await?;
49//!
50//! println!("File has {} lines.", contents.lines().count());
51//! # Ok(())
52//! # }
53//! ```
54//!
55//! To overwrite the file:
56//!
57//! ```
58//! # async fn dox() -> std::io::Result<()> {
59//! let contents = "First line.\nSecond line.\nThird line.\n";
60//!
61//! tokio::fs::write("my_file.txt", contents.as_bytes()).await?;
62//! # Ok(())
63//! # }
64//! ```
65//!
66//! ## Using `File`
67//!
68//! The main type for interacting with files is [`File`]. It can be used to read
69//! from and write to a given file. This is done using the [`AsyncRead`] and
70//! [`AsyncWrite`] traits. This type is generally used when you want to do
71//! something more complex than just reading or writing the entire contents in
72//! one go.
73//!
74//! **Note:** It is important to use [`flush`] when writing to a Tokio
75//! [`File`]. This is because calls to `write` will return before the write has
76//! finished, and [`flush`] will wait for the write to finish. (The write will
77//! happen even if you don't flush; it will just happen later.) This is
78//! different from [`std::fs::File`], and is due to the fact that `File` uses
79//! `spawn_blocking` behind the scenes.
80//!
81//! For example, to count the number of lines in a file without loading the
82//! entire file into memory:
83//!
84//! ```no_run
85//! use tokio::fs::File;
86//! use tokio::io::AsyncReadExt;
87//!
88//! # async fn dox() -> std::io::Result<()> {
89//! let mut file = File::open("my_file.txt").await?;
90//!
91//! let mut chunk = vec![0; 4096];
92//! let mut number_of_lines = 0;
93//! loop {
94//! let len = file.read(&mut chunk).await?;
95//! if len == 0 {
96//! // Length of zero means end of file.
97//! break;
98//! }
99//! for &b in &chunk[..len] {
100//! if b == b'\n' {
101//! number_of_lines += 1;
102//! }
103//! }
104//! }
105//!
106//! println!("File has {} lines.", number_of_lines);
107//! # Ok(())
108//! # }
109//! ```
110//!
111//! For example, to write a file line-by-line:
112//!
113//! ```no_run
114//! use tokio::fs::File;
115//! use tokio::io::AsyncWriteExt;
116//!
117//! # async fn dox() -> std::io::Result<()> {
118//! let mut file = File::create("my_file.txt").await?;
119//!
120//! file.write_all(b"First line.\n").await?;
121//! file.write_all(b"Second line.\n").await?;
122//! file.write_all(b"Third line.\n").await?;
123//!
124//! // Remember to call `flush` after writing!
125//! file.flush().await?;
126//! # Ok(())
127//! # }
128//! ```
129//!
130//! ## Tuning your file IO
131//!
132//! Tokio's file uses [`spawn_blocking`] behind the scenes, and this has serious
133//! performance consequences. To get good performance with file IO on Tokio, it
134//! is recommended to batch your operations into as few `spawn_blocking` calls
135//! as possible.
136//!
137//! One example of this difference can be seen by comparing the two reading
138//! examples above. The first example uses [`tokio::fs::read`], which reads the
139//! entire file in a single `spawn_blocking` call, and then returns it. The
140//! second example will read the file in chunks using many `spawn_blocking`
141//! calls. This means that the second example will most likely be more expensive
142//! for large files. (Of course, using chunks may be necessary for very large
143//! files that don't fit in memory.)
144//!
145//! The following examples will show some strategies for this:
146//!
147//! When creating a file, write the data to a `String` or `Vec<u8>` and then
148//! write the entire file in a single `spawn_blocking` call with
149//! `tokio::fs::write`.
150//!
151//! ```no_run
152//! # async fn dox() -> std::io::Result<()> {
153//! let mut contents = String::new();
154//!
155//! contents.push_str("First line.\n");
156//! contents.push_str("Second line.\n");
157//! contents.push_str("Third line.\n");
158//!
159//! tokio::fs::write("my_file.txt", contents.as_bytes()).await?;
160//! # Ok(())
161//! # }
162//! ```
163//!
164//! Use [`BufReader`] and [`BufWriter`] to buffer many small reads or writes
165//! into a few large ones. This example will most likely only perform one
166//! `spawn_blocking` call.
167//!
168//! ```no_run
169//! use tokio::fs::File;
170//! use tokio::io::{AsyncWriteExt, BufWriter};
171//!
172//! # async fn dox() -> std::io::Result<()> {
173//! let mut file = BufWriter::new(File::create("my_file.txt").await?);
174//!
175//! file.write_all(b"First line.\n").await?;
176//! file.write_all(b"Second line.\n").await?;
177//! file.write_all(b"Third line.\n").await?;
178//!
179//! // Due to the BufWriter, the actual write and spawn_blocking
180//! // call happens when you flush.
181//! file.flush().await?;
182//! # Ok(())
183//! # }
184//! ```
185//!
186//! Manually use [`std::fs`] inside [`spawn_blocking`].
187//!
188//! ```no_run
189//! use std::fs::File;
190//! use std::io::{self, Write};
191//! use tokio::task::spawn_blocking;
192//!
193//! # async fn dox() -> std::io::Result<()> {
194//! spawn_blocking(move || {
195//! let mut file = File::create("my_file.txt")?;
196//!
197//! file.write_all(b"First line.\n")?;
198//! file.write_all(b"Second line.\n")?;
199//! file.write_all(b"Third line.\n")?;
200//!
201//! // Unlike Tokio's file, the std::fs file does
202//! // not need flush.
203//!
204//! io::Result::Ok(())
205//! }).await.unwrap()?;
206//! # Ok(())
207//! # }
208//! ```
209//!
210//! It's also good to be aware of [`File::set_max_buf_size`], which controls the
211//! maximum amount of bytes that Tokio's [`File`] will read or write in a single
212//! [`spawn_blocking`] call. The default is two megabytes, but this is subject
213//! to change.
214//!
215//! [`spawn_blocking`]: fn@crate::task::spawn_blocking
216//! [`AsyncRead`]: trait@crate::io::AsyncRead
217//! [`AsyncWrite`]: trait@crate::io::AsyncWrite
218//! [`BufReader`]: struct@crate::io::BufReader
219//! [`BufWriter`]: struct@crate::io::BufWriter
220//! [`tokio::net::unix::pipe`]: crate::net::unix::pipe
221//! [`AsyncFd`]: crate::io::unix::AsyncFd
222//! [`flush`]: crate::io::AsyncWriteExt::flush
223//! [`tokio::fs::read`]: fn@crate::fs::read
224
225mod canonicalize;
226pub use self::canonicalize::canonicalize;
227
228mod create_dir;
229pub use self::create_dir::create_dir;
230
231mod create_dir_all;
232pub use self::create_dir_all::create_dir_all;
233
234mod dir_builder;
235pub use self::dir_builder::DirBuilder;
236
237mod file;
238pub use self::file::File;
239
240mod file_times;
241pub use self::file_times::FileTimes;
242
243mod hard_link;
244pub use self::hard_link::hard_link;
245
246mod metadata;
247pub use self::metadata::metadata;
248
249mod open_options;
250pub use self::open_options::OpenOptions;
251
252mod read;
253pub use self::read::read;
254
255mod read_dir;
256pub use self::read_dir::{read_dir, DirEntry, ReadDir};
257
258mod read_link;
259pub use self::read_link::read_link;
260
261mod read_to_string;
262pub use self::read_to_string::read_to_string;
263
264mod remove_dir;
265pub use self::remove_dir::remove_dir;
266
267mod remove_dir_all;
268pub use self::remove_dir_all::remove_dir_all;
269
270mod remove_file;
271pub use self::remove_file::remove_file;
272
273mod rename;
274pub use self::rename::rename;
275
276mod set_permissions;
277pub use self::set_permissions::set_permissions;
278
279mod symlink_metadata;
280pub use self::symlink_metadata::symlink_metadata;
281
282mod write;
283pub use self::write::write;
284
285mod copy;
286pub use self::copy::copy;
287
288mod try_exists;
289pub use self::try_exists::try_exists;
290
291#[cfg(test)]
292mod mocks;
293
294feature! {
295 #![unix]
296
297 mod symlink;
298 pub use self::symlink::symlink;
299}
300
301cfg_windows! {
302 mod symlink_dir;
303 pub use self::symlink_dir::symlink_dir;
304
305 mod symlink_file;
306 pub use self::symlink_file::symlink_file;
307}
308
309cfg_io_uring! {
310 pub(crate) mod read_uring;
311 pub(crate) use self::read_uring::read_uring;
312
313 pub(crate) use self::open_options::UringOpenOptions;
314}
315
316use std::io;
317
318#[cfg(not(test))]
319use crate::blocking::spawn_blocking;
320#[cfg(test)]
321use mocks::spawn_blocking;
322
323pub(crate) async fn asyncify<F, T>(f: F) -> io::Result<T>
324where
325 F: FnOnce() -> io::Result<T> + Send + 'static,
326 T: Send + 'static,
327{
328 match spawn_blocking(f).await {
329 Ok(res) => res,
330 Err(_) => Err(io::Error::other("background task failed")),
331 }
332}