Skip to content

Commit c7b6d82

Browse files
committed
Auto merge of #45837 - SimonSapin:file_read_write, r=dtolnay
Add read, read_string, and write functions to std::fs New APIs in `std::fs`: ```rust pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> { … } pub fn read_string<P: AsRef<Path>>(path: P) -> io::Result<String> { … } pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> { ... } ``` (`read_string` is based on `read_to_string` and so returns an error on non-UTF-8 content.) Before: ```rust use std::fs::File; use std::io::Read; let mut bytes = Vec::new(); File::open(filename)?.read_to_end(&mut bytes)?; do_something_with(bytes) ``` After: ```rust use std::fs; do_something_with(fs::read(filename)?) ```
2 parents ad3543d + c5eff54 commit c7b6d82

File tree

2 files changed

+134
-1
lines changed

2 files changed

+134
-1
lines changed

src/libstd/fs.rs

+133-1
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,115 @@ pub struct DirBuilder {
211211
recursive: bool,
212212
}
213213

214+
/// Read the entire contents of a file into a bytes vector.
215+
///
216+
/// This is a convenience function for using [`File::open`] and [`read_to_end`]
217+
/// with fewer imports and without an intermediate variable.
218+
///
219+
/// [`File::open`]: struct.File.html#method.open
220+
/// [`read_to_end`]: ../io/trait.Read.html#method.read_to_end
221+
///
222+
/// # Errors
223+
///
224+
/// This function will return an error if `path` does not already exist.
225+
/// Other errors may also be returned according to [`OpenOptions::open`].
226+
///
227+
/// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
228+
///
229+
/// It will also return an error if it encounters while reading an error
230+
/// of a kind other than [`ErrorKind::Interrupted`].
231+
///
232+
/// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
233+
///
234+
/// # Examples
235+
///
236+
/// ```no_run
237+
/// #![feature(fs_read_write)]
238+
///
239+
/// use std::fs;
240+
/// use std::net::SocketAddr;
241+
///
242+
/// # fn foo() -> Result<(), Box<std::error::Error + 'static>> {
243+
/// let foo: SocketAddr = String::from_utf8_lossy(&fs::read("address.txt")?).parse()?;
244+
/// # Ok(())
245+
/// # }
246+
/// ```
247+
#[unstable(feature = "fs_read_write", issue = "46588")]
248+
pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
249+
let mut bytes = Vec::new();
250+
File::open(path)?.read_to_end(&mut bytes)?;
251+
Ok(bytes)
252+
}
253+
254+
/// Read the entire contents of a file into a string.
255+
///
256+
/// This is a convenience function for using [`File::open`] and [`read_to_string`]
257+
/// with fewer imports and without an intermediate variable.
258+
///
259+
/// [`File::open`]: struct.File.html#method.open
260+
/// [`read_to_string`]: ../io/trait.Read.html#method.read_to_string
261+
///
262+
/// # Errors
263+
///
264+
/// This function will return an error if `path` does not already exist.
265+
/// Other errors may also be returned according to [`OpenOptions::open`].
266+
///
267+
/// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
268+
///
269+
/// It will also return an error if it encounters while reading an error
270+
/// of a kind other than [`ErrorKind::Interrupted`],
271+
/// or if the contents of the file are not valid UTF-8.
272+
///
273+
/// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
274+
///
275+
/// # Examples
276+
///
277+
/// ```no_run
278+
/// #![feature(fs_read_write)]
279+
///
280+
/// use std::fs;
281+
/// use std::net::SocketAddr;
282+
///
283+
/// # fn foo() -> Result<(), Box<std::error::Error + 'static>> {
284+
/// let foo: SocketAddr = fs::read_string("address.txt")?.parse()?;
285+
/// # Ok(())
286+
/// # }
287+
/// ```
288+
#[unstable(feature = "fs_read_write", issue = "46588")]
289+
pub fn read_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
290+
let mut string = String::new();
291+
File::open(path)?.read_to_string(&mut string)?;
292+
Ok(string)
293+
}
294+
295+
/// Write a slice as the entire contents of a file.
296+
///
297+
/// This function will create a file if it does not exist,
298+
/// and will entirely replace its contents if it does.
299+
///
300+
/// This is a convenience function for using [`File::create`] and [`write_all`]
301+
/// with fewer imports.
302+
///
303+
/// [`File::create`]: struct.File.html#method.create
304+
/// [`write_all`]: ../io/trait.Write.html#method.write_all
305+
///
306+
/// # Examples
307+
///
308+
/// ```no_run
309+
/// #![feature(fs_read_write)]
310+
///
311+
/// use std::fs;
312+
///
313+
/// # fn foo() -> std::io::Result<()> {
314+
/// fs::write("foo.txt", b"Lorem ipsum")?;
315+
/// # Ok(())
316+
/// # }
317+
/// ```
318+
#[unstable(feature = "fs_read_write", issue = "46588")]
319+
pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
320+
File::create(path)?.write_all(contents.as_ref())
321+
}
322+
214323
impl File {
215324
/// Attempts to open a file in read-only mode.
216325
///
@@ -1912,7 +2021,9 @@ mod tests {
19122021
) }
19132022

19142023
#[cfg(unix)]
1915-
macro_rules! error { ($e:expr, $s:expr) => (
2024+
macro_rules! error { ($e:expr, $s:expr) => ( error_contains!($e, $s) ) }
2025+
2026+
macro_rules! error_contains { ($e:expr, $s:expr) => (
19162027
match $e {
19172028
Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
19182029
Err(ref err) => assert!(err.to_string().contains($s),
@@ -2921,6 +3032,27 @@ mod tests {
29213032
assert!(v == &bytes[..]);
29223033
}
29233034

3035+
#[test]
3036+
fn write_then_read() {
3037+
let mut bytes = [0; 1024];
3038+
StdRng::new().unwrap().fill_bytes(&mut bytes);
3039+
3040+
let tmpdir = tmpdir();
3041+
3042+
check!(fs::write(&tmpdir.join("test"), &bytes[..]));
3043+
let v = check!(fs::read(&tmpdir.join("test")));
3044+
assert!(v == &bytes[..]);
3045+
3046+
check!(fs::write(&tmpdir.join("not-utf8"), &[0xFF]));
3047+
error_contains!(fs::read_string(&tmpdir.join("not-utf8")),
3048+
"stream did not contain valid UTF-8");
3049+
3050+
let s = "𐁁𐀓𐀠𐀴𐀍";
3051+
check!(fs::write(&tmpdir.join("utf8"), s.as_bytes()));
3052+
let string = check!(fs::read_string(&tmpdir.join("utf8")));
3053+
assert_eq!(string, s);
3054+
}
3055+
29243056
#[test]
29253057
fn file_try_clone() {
29263058
let tmpdir = tmpdir();

src/libstd/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@
260260
#![feature(core_intrinsics)]
261261
#![feature(dropck_eyepatch)]
262262
#![feature(exact_size_is_empty)]
263+
#![feature(fs_read_write)]
263264
#![feature(fixed_size_array)]
264265
#![feature(float_from_str_radix)]
265266
#![feature(fn_traits)]

0 commit comments

Comments
 (0)