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);
128 [MonoLimitation ("FileOptions are ignored")]
129 public static FileStream Create (string path, int bufferSize,
132 return Create (path, bufferSize, options, null);
135 [MonoLimitation ("FileOptions and FileSecurity are ignored")]
136 public static FileStream Create (string path, int bufferSize,
138 FileSecurity fileSecurity)
140 return new FileStream (path, FileMode.Create, FileAccess.ReadWrite,
141 FileShare.None, bufferSize, options);
145 public static StreamWriter CreateText (string path)
147 return new StreamWriter (path, false);
150 public static void Delete (string path)
152 Path.Validate (path);
153 if (Directory.Exists (path))
154 throw new UnauthorizedAccessException(Locale.GetText ("{0} is a directory", path));
156 string DirName = Path.GetDirectoryName(path);
157 if (DirName != String.Empty && !Directory.Exists (DirName))
158 throw new DirectoryNotFoundException (Locale.GetText ("Could not find a part of the path \"{0}\".", path));
160 SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
164 if (!MonoIO.DeleteFile (path, out error)){
165 if (error != MonoIOError.ERROR_FILE_NOT_FOUND)
166 throw MonoIO.GetException (path, error);
170 public static bool Exists (string path)
172 // For security reasons no exceptions are
173 // thrown, only false is returned if there is
174 // any problem with the path or permissions.
175 // Minimizes what information can be
176 // discovered by using this method.
177 if (String.IsNullOrWhiteSpace (path) || path.IndexOfAny(Path.InvalidPathChars) >= 0)
180 // on Moonlight this does not throw but returns false
181 if (!SecurityManager.CheckElevatedPermissions ())
185 return MonoIO.ExistsFile (path, out error);
189 public static FileSecurity GetAccessControl (string path)
191 // AccessControlSections.Audit requires special permissions.
192 return GetAccessControl (path,
193 AccessControlSections.Owner |
194 AccessControlSections.Group |
195 AccessControlSections.Access);
198 public static FileSecurity GetAccessControl (string path, AccessControlSections includeSections)
200 return new FileSecurity (path, includeSections);
204 public static FileAttributes GetAttributes (string path)
206 Path.Validate (path);
207 SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
210 FileAttributes attrs;
212 attrs = MonoIO.GetFileAttributes (path, out error);
213 if (error != MonoIOError.ERROR_SUCCESS)
214 throw MonoIO.GetException (path, error);
218 public static DateTime GetCreationTime (string path)
222 Path.Validate (path);
223 SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
225 if (!MonoIO.GetFileStat (path, out stat, out error)) {
226 if (error == MonoIOError.ERROR_PATH_NOT_FOUND || error == MonoIOError.ERROR_FILE_NOT_FOUND)
227 return DefaultLocalFileTime;
229 throw new IOException (path);
231 return DateTime.FromFileTime (stat.CreationTime);
234 public static DateTime GetCreationTimeUtc (string path)
236 return GetCreationTime (path).ToUniversalTime ();
239 public static DateTime GetLastAccessTime (string path)
243 Path.Validate (path);
244 SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
246 if (!MonoIO.GetFileStat (path, out stat, out error)) {
247 if (error == MonoIOError.ERROR_PATH_NOT_FOUND || error == MonoIOError.ERROR_FILE_NOT_FOUND)
248 return DefaultLocalFileTime;
250 throw new IOException (path);
252 return DateTime.FromFileTime (stat.LastAccessTime);
255 public static DateTime GetLastAccessTimeUtc (string path)
257 return GetLastAccessTime (path).ToUniversalTime ();
260 public static DateTime GetLastWriteTime (string path)
264 Path.Validate (path);
265 SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
267 if (!MonoIO.GetFileStat (path, out stat, out error)) {
268 if (error == MonoIOError.ERROR_PATH_NOT_FOUND || error == MonoIOError.ERROR_FILE_NOT_FOUND)
269 return DefaultLocalFileTime;
271 throw new IOException (path);
273 return DateTime.FromFileTime (stat.LastWriteTime);
276 public static DateTime GetLastWriteTimeUtc (string path)
278 return GetLastWriteTime (path).ToUniversalTime ();
281 public static void Move (string sourceFileName, string destFileName)
283 if (sourceFileName == null)
284 throw new ArgumentNullException ("sourceFileName");
285 if (destFileName == null)
286 throw new ArgumentNullException ("destFileName");
287 if (sourceFileName.Length == 0)
288 throw new ArgumentException ("An empty file name is not valid.", "sourceFileName");
289 if (sourceFileName.Trim ().Length == 0 || sourceFileName.IndexOfAny (Path.InvalidPathChars) != -1)
290 throw new ArgumentException ("The file name is not valid.");
291 if (destFileName.Length == 0)
292 throw new ArgumentException ("An empty file name is not valid.", "destFileName");
293 if (destFileName.Trim ().Length == 0 || destFileName.IndexOfAny (Path.InvalidPathChars) != -1)
294 throw new ArgumentException ("The file name is not valid.");
296 SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
299 if (!MonoIO.Exists (sourceFileName, out error))
300 throw new FileNotFoundException (Locale.GetText ("{0} does not exist", sourceFileName), sourceFileName);
302 // Don't check for this error here to allow the runtime
303 // to check if sourceFileName and destFileName are equal.
304 // Comparing sourceFileName and destFileName is not enough.
305 //if (MonoIO.Exists (destFileName, out error))
306 // throw new IOException (Locale.GetText ("{0} already exists", destFileName));
309 DirName = Path.GetDirectoryName (destFileName);
310 if (DirName != String.Empty && !Directory.Exists (DirName))
311 throw new DirectoryNotFoundException (Locale.GetText ("Could not find a part of the path."));
313 if (!MonoIO.MoveFile (sourceFileName, destFileName, out error)) {
314 if (error == MonoIOError.ERROR_ALREADY_EXISTS)
315 throw MonoIO.GetException (error);
316 else if (error == MonoIOError.ERROR_SHARING_VIOLATION)
317 throw MonoIO.GetException (sourceFileName, error);
319 throw MonoIO.GetException (error);
323 public static FileStream Open (string path, FileMode mode)
325 return new FileStream (path, mode, mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite, FileShare.None);
328 public static FileStream Open (string path, FileMode mode, FileAccess access)
330 return new FileStream (path, mode, access, FileShare.None);
333 public static FileStream Open (string path, FileMode mode, FileAccess access,
336 return new FileStream (path, mode, access, share);
339 public static FileStream OpenRead (string path)
341 return new FileStream (path, FileMode.Open, FileAccess.Read, FileShare.Read);
344 public static StreamReader OpenText (string path)
346 return new StreamReader (path);
349 public static FileStream OpenWrite (string path)
351 return new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
354 public static void Replace (string sourceFileName,
355 string destinationFileName,
356 string destinationBackupFileName)
358 Replace (sourceFileName, destinationFileName, destinationBackupFileName, false);
361 public static void Replace (string sourceFileName,
362 string destinationFileName,
363 string destinationBackupFileName,
364 bool ignoreMetadataErrors)
368 if (sourceFileName == null)
369 throw new ArgumentNullException ("sourceFileName");
370 if (destinationFileName == null)
371 throw new ArgumentNullException ("destinationFileName");
372 if (sourceFileName.Trim ().Length == 0 || sourceFileName.IndexOfAny (Path.InvalidPathChars) != -1)
373 throw new ArgumentException ("sourceFileName");
374 if (destinationFileName.Trim ().Length == 0 || destinationFileName.IndexOfAny (Path.InvalidPathChars) != -1)
375 throw new ArgumentException ("destinationFileName");
377 string fullSource = Path.GetFullPath (sourceFileName);
378 string fullDest = Path.GetFullPath (destinationFileName);
379 if (MonoIO.ExistsDirectory (fullSource, out error))
380 throw new IOException (Locale.GetText ("{0} is a directory", sourceFileName));
381 if (MonoIO.ExistsDirectory (fullDest, out error))
382 throw new IOException (Locale.GetText ("{0} is a directory", destinationFileName));
384 if (!Exists (fullSource))
385 throw new FileNotFoundException (Locale.GetText ("{0} does not exist", sourceFileName),
387 if (!Exists (fullDest))
388 throw new FileNotFoundException (Locale.GetText ("{0} does not exist", destinationFileName),
389 destinationFileName);
390 if (fullSource == fullDest)
391 throw new IOException (Locale.GetText ("Source and destination arguments are the same file."));
393 string fullBackup = null;
394 if (destinationBackupFileName != null) {
395 if (destinationBackupFileName.Trim ().Length == 0 ||
396 destinationBackupFileName.IndexOfAny (Path.InvalidPathChars) != -1)
397 throw new ArgumentException ("destinationBackupFileName");
399 fullBackup = Path.GetFullPath (destinationBackupFileName);
400 if (MonoIO.ExistsDirectory (fullBackup, out error))
401 throw new IOException (Locale.GetText ("{0} is a directory", destinationBackupFileName));
402 if (fullSource == fullBackup)
403 throw new IOException (Locale.GetText ("Source and backup arguments are the same file."));
404 if (fullDest == fullBackup)
405 throw new IOException (Locale.GetText (
406 "Destination and backup arguments are the same file."));
409 if (!MonoIO.ReplaceFile (fullSource, fullDest, fullBackup,
410 ignoreMetadataErrors, out error)) {
411 throw MonoIO.GetException (error);
416 public static void SetAccessControl (string path,
417 FileSecurity fileSecurity)
419 if (null == fileSecurity)
420 throw new ArgumentNullException ("fileSecurity");
422 fileSecurity.PersistModifications (path);
426 public static void SetAttributes (string path,
427 FileAttributes fileAttributes)
430 Path.Validate (path);
432 if (!MonoIO.SetFileAttributes (path, fileAttributes, out error))
433 throw MonoIO.GetException (path, error);
436 public static void SetCreationTime (string path, DateTime creationTime)
439 Path.Validate (path);
440 if (!MonoIO.Exists (path, out error))
441 throw MonoIO.GetException (path, error);
442 if (!MonoIO.SetCreationTime (path, creationTime, out error))
443 throw MonoIO.GetException (path, error);
446 public static void SetCreationTimeUtc (string path, DateTime creationTimeUtc)
448 SetCreationTime (path, creationTimeUtc.ToLocalTime ());
451 public static void SetLastAccessTime (string path, DateTime lastAccessTime)
454 Path.Validate (path);
455 if (!MonoIO.Exists (path, out error))
456 throw MonoIO.GetException (path, error);
457 if (!MonoIO.SetLastAccessTime (path, lastAccessTime, out error))
458 throw MonoIO.GetException (path, error);
461 public static void SetLastAccessTimeUtc (string path, DateTime lastAccessTimeUtc)
463 SetLastAccessTime (path, lastAccessTimeUtc.ToLocalTime ());
466 public static void SetLastWriteTime (string path,
467 DateTime lastWriteTime)
470 Path.Validate (path);
471 if (!MonoIO.Exists (path, out error))
472 throw MonoIO.GetException (path, error);
473 if (!MonoIO.SetLastWriteTime (path, lastWriteTime, out error))
474 throw MonoIO.GetException (path, error);
477 public static void SetLastWriteTimeUtc (string path,
478 DateTime lastWriteTimeUtc)
480 SetLastWriteTime (path, lastWriteTimeUtc.ToLocalTime ());
484 // The documentation for this method is most likely wrong, it
485 // talks about doing a "binary read", but the remarks say
486 // that this "detects the encoding".
488 // This can not detect and do anything useful with the encoding
489 // since the result is a byte [] not a char [].
491 public static byte [] ReadAllBytes (string path)
493 using (FileStream s = OpenRead (path)) {
494 long size = s.Length;
495 // limited to 2GB according to http://msdn.microsoft.com/en-us/library/system.io.file.readallbytes.aspx
496 if (size > Int32.MaxValue)
497 throw new IOException ("Reading more than 2GB with this call is not supported");
500 int count = (int) size;
501 byte [] result = new byte [size];
503 int n = s.Read (result, pos, count);
505 throw new IOException ("Unexpected end of stream");
513 public static string [] ReadAllLines (string path)
515 using (StreamReader reader = File.OpenText (path)) {
516 return ReadAllLines (reader);
520 public static string [] ReadAllLines (string path, Encoding encoding)
522 using (StreamReader reader = new StreamReader (path, encoding)) {
523 return ReadAllLines (reader);
527 static string [] ReadAllLines (StreamReader reader)
529 List<string> list = new List<string> ();
530 while (!reader.EndOfStream)
531 list.Add (reader.ReadLine ());
532 return list.ToArray ();
535 public static string ReadAllText (string path)
537 using (StreamReader sr = new StreamReader (path)) {
538 return sr.ReadToEnd ();
542 public static string ReadAllText (string path, Encoding encoding)
544 using (StreamReader sr = new StreamReader (path, encoding)) {
545 return sr.ReadToEnd ();
549 public static void WriteAllBytes (string path, byte [] bytes)
551 using (Stream stream = File.Create (path)) {
552 stream.Write (bytes, 0, bytes.Length);
556 public static void WriteAllLines (string path, string [] contents)
558 using (StreamWriter writer = new StreamWriter (path)) {
559 WriteAllLines (writer, contents);
563 public static void WriteAllLines (string path, string [] contents, Encoding encoding)
565 using (StreamWriter writer = new StreamWriter (path, false, encoding)) {
566 WriteAllLines (writer, contents);
570 static void WriteAllLines (StreamWriter writer, string [] contents)
572 foreach (string line in contents)
573 writer.WriteLine (line);
576 public static void WriteAllText (string path, string contents)
578 WriteAllText (path, contents, EncodingHelper.UTF8Unmarked);
581 public static void WriteAllText (string path, string contents, Encoding encoding)
583 using (StreamWriter sw = new StreamWriter (path, false, encoding)) {
588 static DateTime? defaultLocalFileTime;
589 static DateTime DefaultLocalFileTime {
591 if (defaultLocalFileTime == null)
592 defaultLocalFileTime = new DateTime (1601, 1, 1).ToLocalTime ();
594 return defaultLocalFileTime.Value;
599 [MonoLimitation ("File encryption isn't supported (even on NTFS).")]
600 public static void Encrypt (string path)
602 // MS.NET support this only on NTFS file systems, i.e. it's a file-system (not a framework) feature.
603 // otherwise it throws a NotSupportedException (or a PlatformNotSupportedException on older OS).
604 // we throw the same (instead of a NotImplementedException) because most code should already be
605 // handling this exception to work properly.
606 throw new NotSupportedException (Locale.GetText ("File encryption isn't supported on any file system."));
609 [MonoLimitation ("File encryption isn't supported (even on NTFS).")]
610 public static void Decrypt (string path)
612 // MS.NET support this only on NTFS file systems, i.e. it's a file-system (not a framework) feature.
613 // otherwise it throws a NotSupportedException (or a PlatformNotSupportedException on older OS).
614 // we throw the same (instead of a NotImplementedException) because most code should already be
615 // handling this exception to work properly.
616 throw new NotSupportedException (Locale.GetText ("File encryption isn't supported on any file system."));
619 public static IEnumerable<string> ReadLines (string path)
621 return ReadLines (File.OpenText (path));
624 public static IEnumerable<string> ReadLines (string path, Encoding encoding)
626 return ReadLines (new StreamReader (path, encoding));
629 // refactored in order to avoid compiler-generated names for Moonlight tools
630 static IEnumerable<string> ReadLines (StreamReader reader)
634 while ((s = reader.ReadLine ()) != null) {
640 public static void AppendAllLines (string path, IEnumerable<string> contents)
642 Path.Validate (path);
644 if (contents == null)
647 using (TextWriter w = new StreamWriter (path, true)) {
648 foreach (var line in contents)
653 public static void AppendAllLines (string path, IEnumerable<string> contents, Encoding encoding)
655 Path.Validate (path);
657 if (contents == null)
660 using (TextWriter w = new StreamWriter (path, true, encoding)) {
661 foreach (var line in contents)
666 public static void WriteAllLines (string path, IEnumerable<string> contents)
668 Path.Validate (path);
670 if (contents == null)
673 using (TextWriter w = new StreamWriter (path, false)) {
674 foreach (var line in contents)
679 public static void WriteAllLines (string path, IEnumerable<string> contents, Encoding encoding)
681 Path.Validate (path);
683 if (contents == null)
686 using (TextWriter w = new StreamWriter (path, false, encoding)) {
687 foreach (var line in contents)