@@ -30,7 +30,7 @@ pub async fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Resu
30
30
}
31
31
32
32
cfg_not_docs ! {
33
- pub use std:: os:: unix:: fs:: { DirBuilderExt , DirEntryExt , OpenOptionsExt } ;
33
+ pub use std:: os:: unix:: fs:: { DirBuilderExt , DirEntryExt , OpenOptionsExt , FileExt } ;
34
34
}
35
35
36
36
cfg_docs ! {
@@ -68,4 +68,195 @@ cfg_docs! {
68
68
/// This options overwrites any previously set custom flags.
69
69
fn custom_flags( & mut self , flags: i32 ) -> & mut Self ;
70
70
}
71
+
72
+ /// Unix-specific extensions to [`fs::File`].
73
+ pub trait FileExt {
74
+ /// Reads a number of bytes starting from a given offset.
75
+ ///
76
+ /// Returns the number of bytes read.
77
+ ///
78
+ /// The offset is relative to the start of the file and thus independent
79
+ /// from the current cursor.
80
+ ///
81
+ /// The current file cursor is not affected by this function.
82
+ ///
83
+ /// Note that similar to [`File::read`], it is not an error to return with a
84
+ /// short read.
85
+ ///
86
+ /// [`File::read`]: fs::File::read
87
+ ///
88
+ /// # Examples
89
+ ///
90
+ /// ```no_run
91
+ /// use async_std::io;
92
+ /// use async_std::fs::File;
93
+ /// use async_std::os::unix::prelude::FileExt;
94
+ ///
95
+ /// async fn main() -> io::Result<()> {
96
+ /// let mut buf = [0u8; 8];
97
+ /// let file = File::open("foo.txt").await?;
98
+ ///
99
+ /// // We now read 8 bytes from the offset 10.
100
+ /// let num_bytes_read = file.read_at(&mut buf, 10).await?;
101
+ /// println!("read {} bytes: {:?}", num_bytes_read, buf);
102
+ /// Ok(())
103
+ /// }
104
+ /// ```
105
+ async fn read_at( & self , buf: & mut [ u8 ] , offset: u64 ) -> io:: Result <usize >;
106
+
107
+ /// Reads the exact number of byte required to fill `buf` from the given offset.
108
+ ///
109
+ /// The offset is relative to the start of the file and thus independent
110
+ /// from the current cursor.
111
+ ///
112
+ /// The current file cursor is not affected by this function.
113
+ ///
114
+ /// Similar to [`io::Read::read_exact`] but uses [`read_at`] instead of `read`.
115
+ ///
116
+ /// [`read_at`]: FileExt::read_at
117
+ ///
118
+ /// # Errors
119
+ ///
120
+ /// If this function encounters an error of the kind
121
+ /// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation
122
+ /// will continue.
123
+ ///
124
+ /// If this function encounters an "end of file" before completely filling
125
+ /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`].
126
+ /// The contents of `buf` are unspecified in this case.
127
+ ///
128
+ /// If any other read error is encountered then this function immediately
129
+ /// returns. The contents of `buf` are unspecified in this case.
130
+ ///
131
+ /// If this function returns an error, it is unspecified how many bytes it
132
+ /// has read, but it will never read more than would be necessary to
133
+ /// completely fill the buffer.
134
+ ///
135
+ /// # Examples
136
+ ///
137
+ /// ```no_run
138
+ /// use async_std::io;
139
+ /// use async_std::fs::File;
140
+ /// use async_std::os::unix::prelude::FileExt;
141
+ ///
142
+ /// async fn main() -> io::Result<()> {
143
+ /// let mut buf = [0u8; 8];
144
+ /// let file = File::open("foo.txt").await?;
145
+ ///
146
+ /// // We now read exactly 8 bytes from the offset 10.
147
+ /// file.read_exact_at(&mut buf, 10).await?;
148
+ /// println!("read {} bytes: {:?}", buf.len(), buf);
149
+ /// Ok(())
150
+ /// }
151
+ /// ```
152
+ async fn read_exact_at( & self , mut buf: & mut [ u8 ] , mut offset: u64 ) -> io:: Result <( ) > {
153
+ while !buf. is_empty( ) {
154
+ match self . read_at( buf, offset) . await {
155
+ Ok ( 0 ) => break ,
156
+ Ok ( n) => {
157
+ let tmp = buf;
158
+ buf = & mut tmp[ n..] ;
159
+ offset += n as u64 ;
160
+ }
161
+ Err ( ref e) if e. kind( ) == io:: ErrorKind :: Interrupted => { }
162
+ Err ( e) => return Err ( e) ,
163
+ }
164
+ }
165
+ if !buf. is_empty( ) {
166
+ Err ( io:: Error :: new( io:: ErrorKind :: UnexpectedEof , "failed to fill whole buffer" ) )
167
+ } else {
168
+ Ok ( ( ) )
169
+ }
170
+ }
171
+
172
+ /// Writes a number of bytes starting from a given offset.
173
+ ///
174
+ /// Returns the number of bytes written.
175
+ ///
176
+ /// The offset is relative to the start of the file and thus independent
177
+ /// from the current cursor.
178
+ ///
179
+ /// The current file cursor is not affected by this function.
180
+ ///
181
+ /// When writing beyond the end of the file, the file is appropriately
182
+ /// extended and the intermediate bytes are initialized with the value 0.
183
+ ///
184
+ /// Note that similar to [`File::write`], it is not an error to return a
185
+ /// short write.
186
+ ///
187
+ /// [`File::write`]: fs::File::write
188
+ ///
189
+ /// # Examples
190
+ ///
191
+ /// ```no_run
192
+ /// use async_std::fs::File;
193
+ /// use async_std::io;
194
+ /// use async_std::os::unix::prelude::FileExt;
195
+ ///
196
+ /// async fn main() -> io::Result<()> {
197
+ /// let file = File::open("foo.txt").await?;
198
+ ///
199
+ /// // We now write at the offset 10.
200
+ /// file.write_at(b"sushi", 10).await?;
201
+ /// Ok(())
202
+ /// }
203
+ /// ```
204
+ async fn write_at( & self , buf: & [ u8 ] , offset: u64 ) -> io:: Result <usize >;
205
+
206
+ /// Attempts to write an entire buffer starting from a given offset.
207
+ ///
208
+ /// The offset is relative to the start of the file and thus independent
209
+ /// from the current cursor.
210
+ ///
211
+ /// The current file cursor is not affected by this function.
212
+ ///
213
+ /// This method will continuously call [`write_at`] until there is no more data
214
+ /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
215
+ /// returned. This method will not return until the entire buffer has been
216
+ /// successfully written or such an error occurs. The first error that is
217
+ /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
218
+ /// returned.
219
+ ///
220
+ /// # Errors
221
+ ///
222
+ /// This function will return the first error of
223
+ /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns.
224
+ ///
225
+ /// [`write_at`]: FileExt::write_at
226
+ ///
227
+ /// # Examples
228
+ ///
229
+ /// ```no_run
230
+ /// use async_std::fs::File;
231
+ /// use async_std::io;
232
+ /// use async_std::os::unix::prelude::FileExt;
233
+ ///
234
+ /// async fn main() -> io::Result<()> {
235
+ /// let file = File::open("foo.txt").await?;
236
+ ///
237
+ /// // We now write at the offset 10.
238
+ /// file.write_all_at(b"sushi", 10).await?;
239
+ /// Ok(())
240
+ /// }
241
+ /// ```
242
+ async fn write_all_at( & self , mut buf: & [ u8 ] , mut offset: u64 ) -> io:: Result <( ) > {
243
+ while !buf. is_empty( ) {
244
+ match self . write_at( buf, offset) . await {
245
+ Ok ( 0 ) => {
246
+ return Err ( io:: Error :: new(
247
+ io:: ErrorKind :: WriteZero ,
248
+ "failed to write whole buffer" ,
249
+ ) ) ;
250
+ }
251
+ Ok ( n) => {
252
+ buf = & buf[ n..] ;
253
+ offset += n as u64
254
+ }
255
+ Err ( ref e) if e. kind( ) == io:: ErrorKind :: Interrupted => { }
256
+ Err ( e) => return Err ( e) ,
257
+ }
258
+ }
259
+ Ok ( ( ) )
260
+ }
261
+ }
71
262
}
0 commit comments