@@ -59,6 +59,78 @@ pub trait FileExt {
59
59
#[ stable( feature = "file_offset" , since = "1.15.0" ) ]
60
60
fn read_at ( & self , buf : & mut [ u8 ] , offset : u64 ) -> io:: Result < usize > ;
61
61
62
+ /// Reads the exact number of byte required to fill `buf` from the given offset.
63
+ ///
64
+ /// The offset is relative to the start of the file and thus independent
65
+ /// from the current cursor.
66
+ ///
67
+ /// The current file cursor is not affected by this function.
68
+ ///
69
+ /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`.
70
+ ///
71
+ /// [`Read::read_exact`]: ../../../../std/io/trait.Read.html#method.read_exact
72
+ /// [`read_at`]: #tymethod.read_at
73
+ ///
74
+ /// # Errors
75
+ ///
76
+ /// If this function encounters an error of the kind
77
+ /// [`ErrorKind::Interrupted`] then the error is ignored and the operation
78
+ /// will continue.
79
+ ///
80
+ /// If this function encounters an "end of file" before completely filling
81
+ /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`].
82
+ /// The contents of `buf` are unspecified in this case.
83
+ ///
84
+ /// If any other read error is encountered then this function immediately
85
+ /// returns. The contents of `buf` are unspecified in this case.
86
+ ///
87
+ /// If this function returns an error, it is unspecified how many bytes it
88
+ /// has read, but it will never read more than would be necessary to
89
+ /// completely fill the buffer.
90
+ ///
91
+ /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
92
+ /// [`ErrorKind::UnexpectedEof`]: ../../../../std/io/enum.ErrorKind.html#variant.UnexpectedEof
93
+ ///
94
+ /// # Examples
95
+ ///
96
+ /// ```no_run
97
+ /// #![feature(rw_exact_all_at)]
98
+ /// use std::io;
99
+ /// use std::fs::File;
100
+ /// use std::os::unix::prelude::FileExt;
101
+ ///
102
+ /// fn main() -> io::Result<()> {
103
+ /// let mut buf = [0u8; 8];
104
+ /// let file = File::open("foo.txt")?;
105
+ ///
106
+ /// // We now read exactly 8 bytes from the offset 10.
107
+ /// file.read_exact_at(&mut buf, 10)?;
108
+ /// println!("read {} bytes: {:?}", buf.len(), buf);
109
+ /// Ok(())
110
+ /// }
111
+ /// ```
112
+ #[ unstable( feature = "rw_exact_all_at" , issue = "51984" ) ]
113
+ fn read_exact_at ( & self , mut buf : & mut [ u8 ] , mut offset : u64 ) -> io:: Result < ( ) > {
114
+ while !buf. is_empty ( ) {
115
+ match self . read_at ( buf, offset) {
116
+ Ok ( 0 ) => break ,
117
+ Ok ( n) => {
118
+ let tmp = buf;
119
+ buf = & mut tmp[ n..] ;
120
+ offset += n as u64 ;
121
+ }
122
+ Err ( ref e) if e. kind ( ) == io:: ErrorKind :: Interrupted => { }
123
+ Err ( e) => return Err ( e) ,
124
+ }
125
+ }
126
+ if !buf. is_empty ( ) {
127
+ Err ( io:: Error :: new ( io:: ErrorKind :: UnexpectedEof ,
128
+ "failed to fill whole buffer" ) )
129
+ } else {
130
+ Ok ( ( ) )
131
+ }
132
+ }
133
+
62
134
/// Writes a number of bytes starting from a given offset.
63
135
///
64
136
/// Returns the number of bytes written.
@@ -93,6 +165,61 @@ pub trait FileExt {
93
165
/// ```
94
166
#[ stable( feature = "file_offset" , since = "1.15.0" ) ]
95
167
fn write_at ( & self , buf : & [ u8 ] , offset : u64 ) -> io:: Result < usize > ;
168
+
169
+ /// Attempts to write an entire buffer starting from a given offset.
170
+ ///
171
+ /// The offset is relative to the start of the file and thus independent
172
+ /// from the current cursor.
173
+ ///
174
+ /// The current file cursor is not affected by this function.
175
+ ///
176
+ /// This method will continuously call [`write_at`] until there is no more data
177
+ /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is
178
+ /// returned. This method will not return until the entire buffer has been
179
+ /// successfully written or such an error occurs. The first error that is
180
+ /// not of [`ErrorKind::Interrupted`] kind generated from this method will be
181
+ /// returned.
182
+ ///
183
+ /// # Errors
184
+ ///
185
+ /// This function will return the first error of
186
+ /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns.
187
+ ///
188
+ /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
189
+ /// [`write_at`]: #tymethod.write_at
190
+ ///
191
+ /// # Examples
192
+ ///
193
+ /// ```no_run
194
+ /// #![feature(rw_exact_all_at)]
195
+ /// use std::fs::File;
196
+ /// use std::io;
197
+ /// use std::os::unix::prelude::FileExt;
198
+ ///
199
+ /// fn main() -> io::Result<()> {
200
+ /// let file = File::open("foo.txt")?;
201
+ ///
202
+ /// // We now write at the offset 10.
203
+ /// file.write_all_at(b"sushi", 10)?;
204
+ /// Ok(())
205
+ /// }
206
+ /// ```
207
+ #[ unstable( feature = "rw_exact_all_at" , issue = "51984" ) ]
208
+ fn write_all_at ( & self , mut buf : & [ u8 ] , mut offset : u64 ) -> io:: Result < ( ) > {
209
+ while !buf. is_empty ( ) {
210
+ match self . write_at ( buf, offset) {
211
+ Ok ( 0 ) => return Err ( io:: Error :: new ( io:: ErrorKind :: WriteZero ,
212
+ "failed to write whole buffer" ) ) ,
213
+ Ok ( n) => {
214
+ buf = & buf[ n..] ;
215
+ offset += n as u64
216
+ }
217
+ Err ( ref e) if e. kind ( ) == io:: ErrorKind :: Interrupted => { }
218
+ Err ( e) => return Err ( e) ,
219
+ }
220
+ }
221
+ Ok ( ( ) )
222
+ }
96
223
}
97
224
98
225
#[ stable( feature = "file_offset" , since = "1.15.0" ) ]
0 commit comments