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 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.
38 using System.Collections.Generic;
39 using System.Runtime.InteropServices;
41 #if NET_2_0 && !NET_2_1
42 using System.Security.AccessControl;
64 public static void AppendAllText (string path, string contents)
66 using (TextWriter w = new StreamWriter (path, true)) {
71 public static void AppendAllText (string path, string contents, Encoding encoding)
73 using (TextWriter w = new StreamWriter (path, true, encoding)) {
79 public static StreamWriter AppendText (string path)
81 return new StreamWriter (path, true);
84 public static void Copy (string sourceFileName, string destFileName)
86 Copy (sourceFileName, destFileName, false);
89 public static void Copy (string sourceFileName, string destFileName, bool overwrite)
93 if (sourceFileName == null)
94 throw new ArgumentNullException ("sourceFileName");
95 if (destFileName == null)
96 throw new ArgumentNullException ("destFileName");
97 if (sourceFileName.Length == 0)
98 throw new ArgumentException ("An empty file name is not valid.", "sourceFileName");
99 if (sourceFileName.Trim ().Length == 0 || sourceFileName.IndexOfAny (Path.InvalidPathChars) != -1)
100 throw new ArgumentException ("The file name is not valid.");
101 if (destFileName.Length == 0)
102 throw new ArgumentException ("An empty file name is not valid.", "destFileName");
103 if (destFileName.Trim ().Length == 0 || destFileName.IndexOfAny (Path.InvalidPathChars) != -1)
104 throw new ArgumentException ("The file name is not valid.");
106 if (!MonoIO.Exists (sourceFileName, out error))
107 throw new FileNotFoundException (Locale.GetText ("{0} does not exist", sourceFileName), sourceFileName);
108 if ((GetAttributes (sourceFileName) & FileAttributes.Directory) == FileAttributes.Directory)
109 throw new ArgumentException (Locale.GetText ("{0} is a directory", sourceFileName));
111 if (MonoIO.Exists (destFileName, out error)) {
112 if ((GetAttributes (destFileName) & FileAttributes.Directory) == FileAttributes.Directory)
113 throw new ArgumentException (Locale.GetText ("{0} is a directory", destFileName));
115 throw new IOException (Locale.GetText ("{0} already exists", destFileName));
118 string DirName = Path.GetDirectoryName (destFileName);
119 if (DirName != String.Empty && !Directory.Exists (DirName))
120 throw new DirectoryNotFoundException (Locale.GetText ("Destination directory not found: {0}",DirName));
122 if (!MonoIO.CopyFile (sourceFileName, destFileName, overwrite, out error)) {
123 string p = Locale.GetText ("{0}\" or \"{1}", sourceFileName, destFileName);
124 throw MonoIO.GetException (p, error);
128 public static FileStream Create (string path)
130 return Create (path, 8192);
133 public static FileStream Create (string path, int bufferSize)
135 return new FileStream (path, FileMode.Create, FileAccess.ReadWrite,
136 FileShare.None, bufferSize);
139 #if NET_2_0 && !NET_2_1
140 [MonoTODO ("options not implemented")]
141 public static FileStream Create (string path, int bufferSize,
144 return Create (path, bufferSize, options, null);
147 [MonoTODO ("options and fileSecurity not implemented")]
148 public static FileStream Create (string path, int bufferSize,
150 FileSecurity fileSecurity)
152 return new FileStream (path, FileMode.Create, FileAccess.ReadWrite,
153 FileShare.None, bufferSize, options);
157 public static StreamWriter CreateText (string path)
159 return new StreamWriter (path, false);
162 public static void Delete (string path)
165 throw new ArgumentNullException("path");
166 if (path.Trim().Length == 0 || path.IndexOfAny(Path.InvalidPathChars) >= 0)
167 throw new ArgumentException("path");
168 if (Directory.Exists (path))
169 throw new UnauthorizedAccessException(Locale.GetText ("{0} is a directory", path));
171 string DirName = Path.GetDirectoryName(path);
172 if (DirName != String.Empty && !Directory.Exists (DirName))
173 throw new DirectoryNotFoundException (Locale.GetText ("Could not find a part of the path \"{0}\".", path));
177 if (!MonoIO.DeleteFile (path, out error)){
178 if (error != MonoIOError.ERROR_FILE_NOT_FOUND)
179 throw MonoIO.GetException (path, error);
183 public static bool Exists (string path)
185 // For security reasons no exceptions are
186 // thrown, only false is returned if there is
187 // any problem with the path or permissions.
188 // Minimizes what information can be
189 // discovered by using this method.
190 if (path == null || path.Trim().Length == 0
191 || path.IndexOfAny(Path.InvalidPathChars) >= 0) {
196 return MonoIO.ExistsFile (path, out error);
199 #if NET_2_0 && !NET_2_1
200 public static FileSecurity GetAccessControl (string path)
202 throw new NotImplementedException ();
205 public static FileSecurity GetAccessControl (string path, AccessControlSections includeSections)
207 throw new NotImplementedException ();
211 public static FileAttributes GetAttributes (string path)
214 throw new ArgumentNullException("path");
215 if (path.Trim ().Length == 0)
216 throw new ArgumentException (Locale.GetText ("Path is empty"));
217 if (path.IndexOfAny (Path.InvalidPathChars) >= 0)
218 throw new ArgumentException (Locale.GetText ("Path contains invalid chars"));
221 FileAttributes attrs;
223 attrs = MonoIO.GetFileAttributes (path, out error);
224 if (error != MonoIOError.ERROR_SUCCESS)
225 throw MonoIO.GetException (path, error);
229 public static DateTime GetCreationTime (string path)
233 CheckPathExceptions (path);
235 if (!MonoIO.GetFileStat (path, out stat, out error)) {
237 if (error == MonoIOError.ERROR_PATH_NOT_FOUND || error == MonoIOError.ERROR_FILE_NOT_FOUND)
238 return DefaultLocalFileTime;
240 throw new IOException (path);
242 throw CreatePartOfPathNotFoundException (path);
245 return DateTime.FromFileTime (stat.CreationTime);
248 public static DateTime GetCreationTimeUtc (string path)
250 return GetCreationTime (path).ToUniversalTime ();
253 public static DateTime GetLastAccessTime (string path)
257 CheckPathExceptions (path);
259 if (!MonoIO.GetFileStat (path, out stat, out error)) {
261 if (error == MonoIOError.ERROR_PATH_NOT_FOUND || error == MonoIOError.ERROR_FILE_NOT_FOUND)
262 return DefaultLocalFileTime;
264 throw new IOException (path);
266 throw CreatePartOfPathNotFoundException (path);
269 return DateTime.FromFileTime (stat.LastAccessTime);
272 public static DateTime GetLastAccessTimeUtc (string path)
274 return GetLastAccessTime (path).ToUniversalTime ();
277 public static DateTime GetLastWriteTime (string path)
281 CheckPathExceptions (path);
283 if (!MonoIO.GetFileStat (path, out stat, out error)) {
285 if (error == MonoIOError.ERROR_PATH_NOT_FOUND || error == MonoIOError.ERROR_FILE_NOT_FOUND)
286 return DefaultLocalFileTime;
288 throw new IOException (path);
290 throw CreatePartOfPathNotFoundException (path);
293 return DateTime.FromFileTime (stat.LastWriteTime);
296 public static DateTime GetLastWriteTimeUtc (string path)
298 return GetLastWriteTime (path).ToUniversalTime ();
301 public static void Move (string sourceFileName, string destFileName)
305 if (sourceFileName == null)
306 throw new ArgumentNullException ("sourceFileName");
307 if (destFileName == null)
308 throw new ArgumentNullException ("destFileName");
309 if (sourceFileName.Length == 0)
310 throw new ArgumentException ("An empty file name is not valid.", "sourceFileName");
311 if (sourceFileName.Trim ().Length == 0 || sourceFileName.IndexOfAny (Path.InvalidPathChars) != -1)
312 throw new ArgumentException ("The file name is not valid.");
313 if (destFileName.Length == 0)
314 throw new ArgumentException ("An empty file name is not valid.", "destFileName");
315 if (destFileName.Trim ().Length == 0 || destFileName.IndexOfAny (Path.InvalidPathChars) != -1)
316 throw new ArgumentException ("The file name is not valid.");
317 if (!MonoIO.Exists (sourceFileName, out error))
318 throw new FileNotFoundException (Locale.GetText ("{0} does not exist", sourceFileName), sourceFileName);
320 // Don't check for this error here to allow the runtime
321 // to check if sourceFileName and destFileName are equal.
322 // Comparing sourceFileName and destFileName is not enough.
323 //if (MonoIO.Exists (destFileName, out error))
324 // throw new IOException (Locale.GetText ("{0} already exists", destFileName));
327 DirName = Path.GetDirectoryName (destFileName);
328 if (DirName != String.Empty && !Directory.Exists (DirName))
330 throw new DirectoryNotFoundException (Locale.GetText ("Could not find a part of the path."));
332 throw new DirectoryNotFoundException (Locale.GetText ("Could not find a part of the path '{0}'.", destFileName));
335 if (!MonoIO.MoveFile (sourceFileName, destFileName, out error)) {
336 if (error == MonoIOError.ERROR_ALREADY_EXISTS)
337 throw MonoIO.GetException (error);
338 else if (error == MonoIOError.ERROR_SHARING_VIOLATION)
339 throw MonoIO.GetException (sourceFileName, error);
341 throw MonoIO.GetException (error);
345 public static FileStream Open (string path, FileMode mode)
347 return new FileStream (path, mode, mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite, FileShare.None);
350 public static FileStream Open (string path, FileMode mode, FileAccess access)
352 return new FileStream (path, mode, access, FileShare.None);
355 public static FileStream Open (string path, FileMode mode, FileAccess access,
358 return new FileStream (path, mode, access, share);
361 public static FileStream OpenRead (string path)
363 return new FileStream (path, FileMode.Open, FileAccess.Read, FileShare.Read);
366 public static StreamReader OpenText (string path)
368 return new StreamReader (path);
371 public static FileStream OpenWrite (string path)
373 return new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
377 public static void Replace (string sourceFileName,
378 string destinationFileName,
379 string destinationBackupFileName)
381 Replace (sourceFileName, destinationFileName, destinationBackupFileName, false);
384 public static void Replace (string sourceFileName,
385 string destinationFileName,
386 string destinationBackupFileName,
387 bool ignoreMetadataErrors)
391 if (sourceFileName == null)
392 throw new ArgumentNullException ("sourceFileName");
393 if (destinationFileName == null)
394 throw new ArgumentNullException ("destinationFileName");
395 if (sourceFileName.Trim ().Length == 0 || sourceFileName.IndexOfAny (Path.InvalidPathChars) != -1)
396 throw new ArgumentException ("sourceFileName");
397 if (destinationFileName.Trim ().Length == 0 || destinationFileName.IndexOfAny (Path.InvalidPathChars) != -1)
398 throw new ArgumentException ("destinationFileName");
400 string fullSource = Path.GetFullPath (sourceFileName);
401 string fullDest = Path.GetFullPath (destinationFileName);
402 if (MonoIO.ExistsDirectory (fullSource, out error))
403 throw new IOException (Locale.GetText ("{0} is a directory", sourceFileName));
404 if (MonoIO.ExistsDirectory (fullDest, out error))
405 throw new IOException (Locale.GetText ("{0} is a directory", destinationFileName));
407 if (!Exists (fullSource))
408 throw new FileNotFoundException (Locale.GetText ("{0} does not exist", sourceFileName),
410 if (!Exists (fullDest))
411 throw new FileNotFoundException (Locale.GetText ("{0} does not exist", destinationFileName),
412 destinationFileName);
413 if (fullSource == fullDest)
414 throw new IOException (Locale.GetText ("Source and destination arguments are the same file."));
416 string fullBackup = null;
417 if (destinationBackupFileName != null) {
418 if (destinationBackupFileName.Trim ().Length == 0 ||
419 destinationBackupFileName.IndexOfAny (Path.InvalidPathChars) != -1)
420 throw new ArgumentException ("destinationBackupFileName");
422 fullBackup = Path.GetFullPath (destinationBackupFileName);
423 if (MonoIO.ExistsDirectory (fullBackup, out error))
424 throw new IOException (Locale.GetText ("{0} is a directory", destinationBackupFileName));
425 if (fullSource == fullBackup)
426 throw new IOException (Locale.GetText ("Source and backup arguments are the same file."));
427 if (fullDest == fullBackup)
428 throw new IOException (Locale.GetText (
429 "Destination and backup arguments are the same file."));
432 if (!MonoIO.ReplaceFile (fullSource, fullDest, fullBackup,
433 ignoreMetadataErrors, out error)) {
434 throw MonoIO.GetException (error);
438 #if NET_2_0 && !NET_2_1
439 public static void SetAccessControl (string path,
440 FileSecurity fileSecurity)
442 throw new NotImplementedException ();
446 public static void SetAttributes (string path,
447 FileAttributes fileAttributes)
450 CheckPathExceptions (path);
452 if (!MonoIO.SetFileAttributes (path, fileAttributes, out error))
453 throw MonoIO.GetException (path, error);
456 public static void SetCreationTime (string path, DateTime creationTime)
459 CheckPathExceptions (path);
460 if (!MonoIO.Exists (path, out error))
461 throw MonoIO.GetException (path, error);
462 if (!MonoIO.SetCreationTime (path, creationTime, out error))
463 throw MonoIO.GetException (path, error);
466 public static void SetCreationTimeUtc (string path, DateTime creationTimeUtc)
468 SetCreationTime (path, creationTimeUtc.ToLocalTime ());
471 public static void SetLastAccessTime (string path, DateTime lastAccessTime)
474 CheckPathExceptions (path);
475 if (!MonoIO.Exists (path, out error))
476 throw MonoIO.GetException (path, error);
477 if (!MonoIO.SetLastAccessTime (path, lastAccessTime, out error))
478 throw MonoIO.GetException (path, error);
481 public static void SetLastAccessTimeUtc (string path, DateTime lastAccessTimeUtc)
483 SetLastAccessTime (path, lastAccessTimeUtc.ToLocalTime ());
486 public static void SetLastWriteTime (string path,
487 DateTime lastWriteTime)
490 CheckPathExceptions (path);
491 if (!MonoIO.Exists (path, out error))
492 throw MonoIO.GetException (path, error);
493 if (!MonoIO.SetLastWriteTime (path, lastWriteTime, out error))
494 throw MonoIO.GetException (path, error);
497 public static void SetLastWriteTimeUtc (string path,
498 DateTime lastWriteTimeUtc)
500 SetLastWriteTime (path, lastWriteTimeUtc.ToLocalTime ());
505 private static void CheckPathExceptions (string path)
508 throw new System.ArgumentNullException("path");
509 if (path.Length == 0)
510 throw new System.ArgumentException(Locale.GetText ("Path is empty"));
511 if (path.Trim().Length == 0)
512 throw new ArgumentException (Locale.GetText ("Path is empty"));
513 if (path.IndexOfAny (Path.InvalidPathChars) != -1)
514 throw new ArgumentException (Locale.GetText ("Path contains invalid chars"));
518 private static IOException CreatePartOfPathNotFoundException (string path)
520 string msg = Locale.GetText ("Part of the path \"{0}\" could not be found.", path);
521 return new IOException (msg);
529 // The documentation for this method is most likely wrong, it
530 // talks about doing a "binary read", but the remarks say
531 // that this "detects the encoding".
533 // This can not detect and do anything useful with the encoding
534 // since the result is a byte [] not a char [].
536 public static byte [] ReadAllBytes (string path)
538 using (FileStream s = Open (path, FileMode.Open, FileAccess.Read, FileShare.Read)){
539 long size = s.Length;
542 // Is this worth supporting?
544 if (size > Int32.MaxValue)
545 throw new ArgumentException ("Reading more than 4gigs with this call is not supported");
547 byte [] result = new byte [s.Length];
549 s.Read (result, 0, (int) size);
555 public static string [] ReadAllLines (string path)
557 using (StreamReader reader = File.OpenText (path)) {
558 return ReadAllLines (reader);
562 public static string [] ReadAllLines (string path, Encoding encoding)
564 using (StreamReader reader = new StreamReader (path, encoding)) {
565 return ReadAllLines (reader);
569 static string [] ReadAllLines (StreamReader reader)
571 List<string> list = new List<string> ();
572 while (!reader.EndOfStream)
573 list.Add (reader.ReadLine ());
574 return list.ToArray ();
577 public static string ReadAllText (string path)
579 return ReadAllText (path, Encoding.UTF8Unmarked);
582 public static string ReadAllText (string path, Encoding encoding)
584 using (StreamReader sr = new StreamReader (path, encoding)) {
585 return sr.ReadToEnd ();
589 public static void WriteAllBytes (string path, byte [] bytes)
591 using (Stream stream = File.Create (path)) {
592 stream.Write (bytes, 0, bytes.Length);
596 public static void WriteAllLines (string path, string [] contents)
598 using (StreamWriter writer = new StreamWriter (path)) {
599 WriteAllLines (writer, contents);
603 public static void WriteAllLines (string path, string [] contents, Encoding encoding)
605 using (StreamWriter writer = new StreamWriter (path, false, encoding)) {
606 WriteAllLines (writer, contents);
610 static void WriteAllLines (StreamWriter writer, string [] contents)
612 foreach (string line in contents)
613 writer.WriteLine (line);
616 public static void WriteAllText (string path, string contents)
618 WriteAllText (path, contents, Encoding.UTF8Unmarked);
621 public static void WriteAllText (string path, string contents, Encoding encoding)
623 using (StreamWriter sw = new StreamWriter (path, false, encoding)) {
628 static DateTime? defaultLocalFileTime;
629 static DateTime DefaultLocalFileTime {
631 if (defaultLocalFileTime == null)
632 defaultLocalFileTime = new DateTime (1601, 1, 1).ToLocalTime ();
634 return defaultLocalFileTime.Value;
639 [MonoLimitation ("File encryption isn't supported (even on NTFS).")]
640 public static void Encrypt (string path)
642 // MS.NET support this only on NTFS file systems, i.e. it's a file-system (not a framework) feature.
643 // otherwise it throws a NotSupportedException (or a PlatformNotSupportedException on older OS).
644 // we throw the same (instead of a NotImplementedException) because most code should already be
645 // handling this exception to work properly.
646 throw new NotSupportedException (Locale.GetText ("File encryption isn't supported on any file system."));
649 [MonoLimitation ("File encryption isn't supported (even on NTFS).")]
650 public static void Decrypt (string path)
652 // MS.NET support this only on NTFS file systems, i.e. it's a file-system (not a framework) feature.
653 // otherwise it throws a NotSupportedException (or a PlatformNotSupportedException on older OS).
654 // we throw the same (instead of a NotImplementedException) because most code should already be
655 // handling this exception to work properly.
656 throw new NotSupportedException (Locale.GetText ("File encryption isn't supported on any file system."));