6 // Miguel de Icaza (miguel@ximian.com)
7 // Jim Richardson (develop@wtfo-guru.com)
8 // Dan Lewis (dihlewis@yahoo.co.uk)
9 // Ville Palo (vi64pa@kolumbus.fi)
11 // Copyright 2002 Ximian, Inc. http://www.ximian.com
12 // Copyright (C) 2001 Moonlight Enterprises, All Rights Reserved
13 // Copyright (C) 2004, 2006, 2010 Novell, Inc (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System
.Collections
.Generic
;
37 using System
.Diagnostics
;
38 using System
.Security
;
40 using System
.Runtime
.InteropServices
;
43 using System
.Security
.AccessControl
;
49 public static class File
51 public static void AppendAllText (string path
, string contents
)
53 using (TextWriter w
= new StreamWriter (path
, true)) {
58 public static void AppendAllText (string path
, string contents
, Encoding encoding
)
60 using (TextWriter w
= new StreamWriter (path
, true, encoding
)) {
65 public static StreamWriter
AppendText (string path
)
67 return new StreamWriter (path
, true);
70 public static void Copy (string sourceFileName
, string destFileName
)
72 Copy (sourceFileName
, destFileName
, false);
75 public static void Copy (string sourceFileName
, string destFileName
, bool overwrite
)
79 if (sourceFileName
== null)
80 throw new ArgumentNullException ("sourceFileName");
81 if (destFileName
== null)
82 throw new ArgumentNullException ("destFileName");
83 if (sourceFileName
.Length
== 0)
84 throw new ArgumentException ("An empty file name is not valid.", "sourceFileName");
85 if (sourceFileName
.Trim ().Length
== 0 || sourceFileName
.IndexOfAny (Path
.InvalidPathChars
) != -1)
86 throw new ArgumentException ("The file name is not valid.");
87 if (destFileName
.Length
== 0)
88 throw new ArgumentException ("An empty file name is not valid.", "destFileName");
89 if (destFileName
.Trim ().Length
== 0 || destFileName
.IndexOfAny (Path
.InvalidPathChars
) != -1)
90 throw new ArgumentException ("The file name is not valid.");
92 SecurityManager
.EnsureElevatedPermissions (); // this is a no-op outside moonlight
94 if (!MonoIO
.Exists (sourceFileName
, out error
))
95 throw new FileNotFoundException (Locale
.GetText ("{0} does not exist", sourceFileName
), sourceFileName
);
96 if ((GetAttributes (sourceFileName
) & FileAttributes
.Directory
) == FileAttributes
.Directory
)
97 throw new ArgumentException (Locale
.GetText ("{0} is a directory", sourceFileName
));
99 if (MonoIO
.Exists (destFileName
, out error
)) {
100 if ((GetAttributes (destFileName
) & FileAttributes
.Directory
) == FileAttributes
.Directory
)
101 throw new ArgumentException (Locale
.GetText ("{0} is a directory", destFileName
));
103 throw new IOException (Locale
.GetText ("{0} already exists", destFileName
));
106 string DirName
= Path
.GetDirectoryName (destFileName
);
107 if (DirName
!= String
.Empty
&& !Directory
.Exists (DirName
))
108 throw new DirectoryNotFoundException (Locale
.GetText ("Destination directory not found: {0}",DirName
));
110 if (!MonoIO
.CopyFile (sourceFileName
, destFileName
, overwrite
, out error
)) {
111 string p
= Locale
.GetText ("{0}\" or \"{1}", sourceFileName
, destFileName
);
112 throw MonoIO
.GetException (p
, error
);
116 public static FileStream
Create (string path
)
118 return Create (path
, 8192);
121 public static FileStream
Create (string path
, int bufferSize
)
123 return new FileStream (path
, FileMode
.Create
, FileAccess
.ReadWrite
,
124 FileShare
.None
, bufferSize
);
127 [MonoLimitation ("FileOptions are ignored")]
128 public static FileStream
Create (string path
, int bufferSize
,
131 return new FileStream (path
, FileMode
.Create
, FileAccess
.ReadWrite
,
132 FileShare
.None
, bufferSize
, options
);
136 [MonoLimitation ("FileOptions and FileSecurity are ignored")]
137 public static FileStream
Create (string path
, int bufferSize
,
139 FileSecurity fileSecurity
)
141 return new FileStream (path
, FileMode
.Create
, FileAccess
.ReadWrite
,
142 FileShare
.None
, bufferSize
, options
);
146 public static StreamWriter
CreateText (string path
)
148 return new StreamWriter (path
, false);
151 public static void Delete (string path
)
153 Path
.Validate (path
);
154 if (Directory
.Exists (path
))
155 throw new UnauthorizedAccessException(Locale
.GetText ("{0} is a directory", path
));
157 string DirName
= Path
.GetDirectoryName(path
);
158 if (DirName
!= String
.Empty
&& !Directory
.Exists (DirName
))
159 throw new DirectoryNotFoundException (Locale
.GetText ("Could not find a part of the path \"{0}\".", path
));
161 SecurityManager
.EnsureElevatedPermissions (); // this is a no-op outside moonlight
165 if (!MonoIO
.DeleteFile (path
, out error
)){
166 if (error
!= MonoIOError
.ERROR_FILE_NOT_FOUND
)
167 throw MonoIO
.GetException (path
, error
);
171 public static bool Exists (string path
)
173 // For security reasons no exceptions are
174 // thrown, only false is returned if there is
175 // any problem with the path or permissions.
176 // Minimizes what information can be
177 // discovered by using this method.
178 if (String
.IsNullOrWhiteSpace (path
) || path
.IndexOfAny(Path
.InvalidPathChars
) >= 0)
181 // on Moonlight this does not throw but returns false
182 if (!SecurityManager
.CheckElevatedPermissions ())
186 return MonoIO
.ExistsFile (path
, out error
);
190 public static FileSecurity
GetAccessControl (string path
)
192 // AccessControlSections.Audit requires special permissions.
193 return GetAccessControl (path
,
194 AccessControlSections
.Owner
|
195 AccessControlSections
.Group
|
196 AccessControlSections
.Access
);
199 public static FileSecurity
GetAccessControl (string path
, AccessControlSections includeSections
)
201 return new FileSecurity (path
, includeSections
);
205 public static FileAttributes
GetAttributes (string path
)
207 Path
.Validate (path
);
208 SecurityManager
.EnsureElevatedPermissions (); // this is a no-op outside moonlight
211 FileAttributes attrs
;
213 attrs
= MonoIO
.GetFileAttributes (path
, out error
);
214 if (error
!= MonoIOError
.ERROR_SUCCESS
)
215 throw MonoIO
.GetException (path
, error
);
219 public static DateTime
GetCreationTime (string path
)
223 Path
.Validate (path
);
224 SecurityManager
.EnsureElevatedPermissions (); // this is a no-op outside moonlight
226 if (!MonoIO
.GetFileStat (path
, out stat
, out error
)) {
227 if (error
== MonoIOError
.ERROR_PATH_NOT_FOUND
|| error
== MonoIOError
.ERROR_FILE_NOT_FOUND
)
228 return DefaultLocalFileTime
;
230 throw new IOException (path
);
232 return DateTime
.FromFileTime (stat
.CreationTime
);
235 public static DateTime
GetCreationTimeUtc (string path
)
237 return GetCreationTime (path
).ToUniversalTime ();
240 public static DateTime
GetLastAccessTime (string path
)
244 Path
.Validate (path
);
245 SecurityManager
.EnsureElevatedPermissions (); // this is a no-op outside moonlight
247 if (!MonoIO
.GetFileStat (path
, out stat
, out error
)) {
248 if (error
== MonoIOError
.ERROR_PATH_NOT_FOUND
|| error
== MonoIOError
.ERROR_FILE_NOT_FOUND
)
249 return DefaultLocalFileTime
;
251 throw new IOException (path
);
253 return DateTime
.FromFileTime (stat
.LastAccessTime
);
256 public static DateTime
GetLastAccessTimeUtc (string path
)
258 return GetLastAccessTime (path
).ToUniversalTime ();
261 public static DateTime
GetLastWriteTime (string path
)
265 Path
.Validate (path
);
266 SecurityManager
.EnsureElevatedPermissions (); // this is a no-op outside moonlight
268 if (!MonoIO
.GetFileStat (path
, out stat
, out error
)) {
269 if (error
== MonoIOError
.ERROR_PATH_NOT_FOUND
|| error
== MonoIOError
.ERROR_FILE_NOT_FOUND
)
270 return DefaultLocalFileTime
;
272 throw new IOException (path
);
274 return DateTime
.FromFileTime (stat
.LastWriteTime
);
277 public static DateTime
GetLastWriteTimeUtc (string path
)
279 return GetLastWriteTime (path
).ToUniversalTime ();
282 public static void Move (string sourceFileName
, string destFileName
)
284 if (sourceFileName
== null)
285 throw new ArgumentNullException ("sourceFileName");
286 if (destFileName
== null)
287 throw new ArgumentNullException ("destFileName");
288 if (sourceFileName
.Length
== 0)
289 throw new ArgumentException ("An empty file name is not valid.", "sourceFileName");
290 if (sourceFileName
.Trim ().Length
== 0 || sourceFileName
.IndexOfAny (Path
.InvalidPathChars
) != -1)
291 throw new ArgumentException ("The file name is not valid.");
292 if (destFileName
.Length
== 0)
293 throw new ArgumentException ("An empty file name is not valid.", "destFileName");
294 if (destFileName
.Trim ().Length
== 0 || destFileName
.IndexOfAny (Path
.InvalidPathChars
) != -1)
295 throw new ArgumentException ("The file name is not valid.");
297 SecurityManager
.EnsureElevatedPermissions (); // this is a no-op outside moonlight
300 if (!MonoIO
.Exists (sourceFileName
, out error
))
301 throw new FileNotFoundException (Locale
.GetText ("{0} does not exist", sourceFileName
), sourceFileName
);
303 // Don't check for this error here to allow the runtime
304 // to check if sourceFileName and destFileName are equal.
305 // Comparing sourceFileName and destFileName is not enough.
306 //if (MonoIO.Exists (destFileName, out error))
307 // throw new IOException (Locale.GetText ("{0} already exists", destFileName));
310 DirName
= Path
.GetDirectoryName (destFileName
);
311 if (DirName
!= String
.Empty
&& !Directory
.Exists (DirName
))
312 throw new DirectoryNotFoundException (Locale
.GetText ("Could not find a part of the path."));
314 if (!MonoIO
.MoveFile (sourceFileName
, destFileName
, out error
)) {
315 if (error
== MonoIOError
.ERROR_ALREADY_EXISTS
)
316 throw MonoIO
.GetException (error
);
317 else if (error
== MonoIOError
.ERROR_SHARING_VIOLATION
)
318 throw MonoIO
.GetException (sourceFileName
, error
);
320 throw MonoIO
.GetException (error
);
324 public static FileStream
Open (string path
, FileMode mode
)
326 return new FileStream (path
, mode
, mode
== FileMode
.Append
? FileAccess
.Write
: FileAccess
.ReadWrite
, FileShare
.None
);
329 public static FileStream
Open (string path
, FileMode mode
, FileAccess access
)
331 return new FileStream (path
, mode
, access
, FileShare
.None
);
334 public static FileStream
Open (string path
, FileMode mode
, FileAccess access
,
337 return new FileStream (path
, mode
, access
, share
);
340 public static FileStream
OpenRead (string path
)
342 return new FileStream (path
, FileMode
.Open
, FileAccess
.Read
, FileShare
.Read
);
345 public static StreamReader
OpenText (string path
)
347 return new StreamReader (path
);
350 public static FileStream
OpenWrite (string path
)
352 return new FileStream(path
, FileMode
.OpenOrCreate
, FileAccess
.Write
, FileShare
.None
);
355 public static void Replace (string sourceFileName
,
356 string destinationFileName
,
357 string destinationBackupFileName
)
359 Replace (sourceFileName
, destinationFileName
, destinationBackupFileName
, false);
362 public static void Replace (string sourceFileName
,
363 string destinationFileName
,
364 string destinationBackupFileName
,
365 bool ignoreMetadataErrors
)
369 if (sourceFileName
== null)
370 throw new ArgumentNullException ("sourceFileName");
371 if (destinationFileName
== null)
372 throw new ArgumentNullException ("destinationFileName");
373 if (sourceFileName
.Trim ().Length
== 0 || sourceFileName
.IndexOfAny (Path
.InvalidPathChars
) != -1)
374 throw new ArgumentException ("sourceFileName");
375 if (destinationFileName
.Trim ().Length
== 0 || destinationFileName
.IndexOfAny (Path
.InvalidPathChars
) != -1)
376 throw new ArgumentException ("destinationFileName");
378 string fullSource
= Path
.GetFullPath (sourceFileName
);
379 string fullDest
= Path
.GetFullPath (destinationFileName
);
380 if (MonoIO
.ExistsDirectory (fullSource
, out error
))
381 throw new IOException (Locale
.GetText ("{0} is a directory", sourceFileName
));
382 if (MonoIO
.ExistsDirectory (fullDest
, out error
))
383 throw new IOException (Locale
.GetText ("{0} is a directory", destinationFileName
));
385 if (!Exists (fullSource
))
386 throw new FileNotFoundException (Locale
.GetText ("{0} does not exist", sourceFileName
),
388 if (!Exists (fullDest
))
389 throw new FileNotFoundException (Locale
.GetText ("{0} does not exist", destinationFileName
),
390 destinationFileName
);
391 if (fullSource
== fullDest
)
392 throw new IOException (Locale
.GetText ("Source and destination arguments are the same file."));
394 string fullBackup
= null;
395 if (destinationBackupFileName
!= null) {
396 if (destinationBackupFileName
.Trim ().Length
== 0 ||
397 destinationBackupFileName
.IndexOfAny (Path
.InvalidPathChars
) != -1)
398 throw new ArgumentException ("destinationBackupFileName");
400 fullBackup
= Path
.GetFullPath (destinationBackupFileName
);
401 if (MonoIO
.ExistsDirectory (fullBackup
, out error
))
402 throw new IOException (Locale
.GetText ("{0} is a directory", destinationBackupFileName
));
403 if (fullSource
== fullBackup
)
404 throw new IOException (Locale
.GetText ("Source and backup arguments are the same file."));
405 if (fullDest
== fullBackup
)
406 throw new IOException (Locale
.GetText (
407 "Destination and backup arguments are the same file."));
410 if (!MonoIO
.ReplaceFile (fullSource
, fullDest
, fullBackup
,
411 ignoreMetadataErrors
, out error
)) {
412 throw MonoIO
.GetException (error
);
417 public static void SetAccessControl (string path
,
418 FileSecurity fileSecurity
)
420 if (null == fileSecurity
)
421 throw new ArgumentNullException ("fileSecurity");
423 fileSecurity
.PersistModifications (path
);
427 public static void SetAttributes (string path
,
428 FileAttributes fileAttributes
)
431 Path
.Validate (path
);
433 if (!MonoIO
.SetFileAttributes (path
, fileAttributes
, out error
))
434 throw MonoIO
.GetException (path
, error
);
437 public static void SetCreationTime (string path
, DateTime creationTime
)
440 Path
.Validate (path
);
441 if (!MonoIO
.Exists (path
, out error
))
442 throw MonoIO
.GetException (path
, error
);
443 if (!MonoIO
.SetCreationTime (path
, creationTime
, out error
))
444 throw MonoIO
.GetException (path
, error
);
447 public static void SetCreationTimeUtc (string path
, DateTime creationTimeUtc
)
449 SetCreationTime (path
, creationTimeUtc
.ToLocalTime ());
452 public static void SetLastAccessTime (string path
, DateTime lastAccessTime
)
455 Path
.Validate (path
);
456 if (!MonoIO
.Exists (path
, out error
))
457 throw MonoIO
.GetException (path
, error
);
458 if (!MonoIO
.SetLastAccessTime (path
, lastAccessTime
, out error
))
459 throw MonoIO
.GetException (path
, error
);
462 public static void SetLastAccessTimeUtc (string path
, DateTime lastAccessTimeUtc
)
464 SetLastAccessTime (path
, lastAccessTimeUtc
.ToLocalTime ());
467 public static void SetLastWriteTime (string path
,
468 DateTime lastWriteTime
)
471 Path
.Validate (path
);
472 if (!MonoIO
.Exists (path
, out error
))
473 throw MonoIO
.GetException (path
, error
);
474 if (!MonoIO
.SetLastWriteTime (path
, lastWriteTime
, out error
))
475 throw MonoIO
.GetException (path
, error
);
478 public static void SetLastWriteTimeUtc (string path
,
479 DateTime lastWriteTimeUtc
)
481 SetLastWriteTime (path
, lastWriteTimeUtc
.ToLocalTime ());
485 // The documentation for this method is most likely wrong, it
486 // talks about doing a "binary read", but the remarks say
487 // that this "detects the encoding".
489 // This can not detect and do anything useful with the encoding
490 // since the result is a byte [] not a char [].
492 public static byte [] ReadAllBytes (string path
)
494 using (FileStream s
= OpenRead (path
)) {
495 long size
= s
.Length
;
496 // limited to 2GB according to http://msdn.microsoft.com/en-us/library/system.io.file.readallbytes.aspx
497 if (size
> Int32
.MaxValue
)
498 throw new IOException ("Reading more than 2GB with this call is not supported");
501 int count
= (int) size
;
502 byte [] result
= new byte [size
];
504 int n
= s
.Read (result
, pos
, count
);
506 throw new IOException ("Unexpected end of stream");
514 public static string [] ReadAllLines (string path
)
516 using (StreamReader reader
= File
.OpenText (path
)) {
517 return ReadAllLines (reader
);
521 public static string [] ReadAllLines (string path
, Encoding encoding
)
523 using (StreamReader reader
= new StreamReader (path
, encoding
)) {
524 return ReadAllLines (reader
);
528 static string [] ReadAllLines (StreamReader reader
)
530 List
<string> list
= new List
<string> ();
531 while (!reader
.EndOfStream
)
532 list
.Add (reader
.ReadLine ());
533 return list
.ToArray ();
536 public static string ReadAllText (string path
)
538 using (StreamReader sr
= new StreamReader (path
)) {
539 return sr
.ReadToEnd ();
543 public static string ReadAllText (string path
, Encoding encoding
)
545 using (StreamReader sr
= new StreamReader (path
, encoding
)) {
546 return sr
.ReadToEnd ();
550 public static void WriteAllBytes (string path
, byte [] bytes
)
552 using (Stream stream
= File
.Create (path
)) {
553 stream
.Write (bytes
, 0, bytes
.Length
);
557 public static void WriteAllLines (string path
, string [] contents
)
559 using (StreamWriter writer
= new StreamWriter (path
)) {
560 WriteAllLines (writer
, contents
);
564 public static void WriteAllLines (string path
, string [] contents
, Encoding encoding
)
566 using (StreamWriter writer
= new StreamWriter (path
, false, encoding
)) {
567 WriteAllLines (writer
, contents
);
571 static void WriteAllLines (StreamWriter writer
, string [] contents
)
573 foreach (string line
in contents
)
574 writer
.WriteLine (line
);
577 public static void WriteAllText (string path
, string contents
)
579 WriteAllText (path
, contents
, Encoding
.UTF8Unmarked
);
582 public static void WriteAllText (string path
, string contents
, Encoding encoding
)
584 using (StreamWriter sw
= new StreamWriter (path
, false, encoding
)) {
589 static DateTime
? defaultLocalFileTime
;
590 static DateTime DefaultLocalFileTime
{
592 if (defaultLocalFileTime
== null)
593 defaultLocalFileTime
= new DateTime (1601, 1, 1).ToLocalTime ();
595 return defaultLocalFileTime
.Value
;
600 [MonoLimitation ("File encryption isn't supported (even on NTFS).")]
601 public static void Encrypt (string path
)
603 // MS.NET support this only on NTFS file systems, i.e. it's a file-system (not a framework) feature.
604 // otherwise it throws a NotSupportedException (or a PlatformNotSupportedException on older OS).
605 // we throw the same (instead of a NotImplementedException) because most code should already be
606 // handling this exception to work properly.
607 throw new NotSupportedException (Locale
.GetText ("File encryption isn't supported on any file system."));
610 [MonoLimitation ("File encryption isn't supported (even on NTFS).")]
611 public static void Decrypt (string path
)
613 // MS.NET support this only on NTFS file systems, i.e. it's a file-system (not a framework) feature.
614 // otherwise it throws a NotSupportedException (or a PlatformNotSupportedException on older OS).
615 // we throw the same (instead of a NotImplementedException) because most code should already be
616 // handling this exception to work properly.
617 throw new NotSupportedException (Locale
.GetText ("File encryption isn't supported on any file system."));
621 public static IEnumerable
<string> ReadLines (string path
)
623 return ReadLines (File
.OpenText (path
));
626 public static IEnumerable
<string> ReadLines (string path
, Encoding encoding
)
628 return ReadLines (new StreamReader (path
, encoding
));
631 // refactored in order to avoid compiler-generated names for Moonlight tools
632 static IEnumerable
<string> ReadLines (StreamReader reader
)
636 while ((s
= reader
.ReadLine ()) != null) {
642 public static void AppendAllLines (string path
, IEnumerable
<string> contents
)
644 Path
.Validate (path
);
646 if (contents
== null)
649 using (TextWriter w
= new StreamWriter (path
, true)) {
650 foreach (var line
in contents
)
655 public static void AppendAllLines (string path
, IEnumerable
<string> contents
, Encoding encoding
)
657 Path
.Validate (path
);
659 if (contents
== null)
662 using (TextWriter w
= new StreamWriter (path
, true, encoding
)) {
663 foreach (var line
in contents
)
668 public static void WriteAllLines (string path
, IEnumerable
<string> contents
)
670 Path
.Validate (path
);
672 if (contents
== null)
675 using (TextWriter w
= new StreamWriter (path
, false)) {
676 foreach (var line
in contents
)
681 public static void WriteAllLines (string path
, IEnumerable
<string> contents
, Encoding encoding
)
683 Path
.Validate (path
);
685 if (contents
== null)
688 using (TextWriter w
= new StreamWriter (path
, false, encoding
)) {
689 foreach (var line
in contents
)