2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / class / corlib / System.IO / File.cs
blobd183c19eddd80bc5c7dd6421fcd01cf8af60f2a2
1 //
2 // System.IO.File.cs
3 //
4 //
5 // Authors:
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:
22 //
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 //
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.
35 using System;
36 using System.Text;
37 using System.Collections.Generic;
38 using System.Runtime.InteropServices;
40 #if NET_2_1
41 using System.Security;
42 #else
43 using System.Security.AccessControl;
44 #endif
46 namespace System.IO
48 [ComVisible (true)]
49 public static class File
51 static void ValidatePath (string path)
53 if (path == null)
54 throw new ArgumentNullException ("path");
55 if (path.Length == 0)
56 throw new ArgumentException ("path");
57 #if MOONLIGHT && !DEBUG
58 // On Moonlight (SL4+) this is possible, with limitations, in "Elevated Trust"
59 throw new SecurityException ("we're not ready to enable this SL4 feature yet");
60 #endif
63 public static void AppendAllText (string path, string contents)
65 ValidatePath (path);
67 using (TextWriter w = new StreamWriter (path, true)) {
68 w.Write (contents);
72 public static void AppendAllText (string path, string contents, Encoding encoding)
74 ValidatePath (path);
76 using (TextWriter w = new StreamWriter (path, true, encoding)) {
77 w.Write (contents);
81 public static StreamWriter AppendText (string path)
83 return new StreamWriter (path, true);
86 public static void Copy (string sourceFileName, string destFileName)
88 Copy (sourceFileName, destFileName, false);
91 public static void Copy (string sourceFileName, string destFileName, bool overwrite)
93 MonoIOError error;
95 if (sourceFileName == null)
96 throw new ArgumentNullException ("sourceFileName");
97 if (destFileName == null)
98 throw new ArgumentNullException ("destFileName");
99 if (sourceFileName.Length == 0)
100 throw new ArgumentException ("An empty file name is not valid.", "sourceFileName");
101 if (sourceFileName.Trim ().Length == 0 || sourceFileName.IndexOfAny (Path.InvalidPathChars) != -1)
102 throw new ArgumentException ("The file name is not valid.");
103 if (destFileName.Length == 0)
104 throw new ArgumentException ("An empty file name is not valid.", "destFileName");
105 if (destFileName.Trim ().Length == 0 || destFileName.IndexOfAny (Path.InvalidPathChars) != -1)
106 throw new ArgumentException ("The file name is not valid.");
108 if (!MonoIO.Exists (sourceFileName, out error))
109 throw new FileNotFoundException (Locale.GetText ("{0} does not exist", sourceFileName), sourceFileName);
110 if ((GetAttributes (sourceFileName) & FileAttributes.Directory) == FileAttributes.Directory)
111 throw new ArgumentException (Locale.GetText ("{0} is a directory", sourceFileName));
113 if (MonoIO.Exists (destFileName, out error)) {
114 if ((GetAttributes (destFileName) & FileAttributes.Directory) == FileAttributes.Directory)
115 throw new ArgumentException (Locale.GetText ("{0} is a directory", destFileName));
116 if (!overwrite)
117 throw new IOException (Locale.GetText ("{0} already exists", destFileName));
120 string DirName = Path.GetDirectoryName (destFileName);
121 if (DirName != String.Empty && !Directory.Exists (DirName))
122 throw new DirectoryNotFoundException (Locale.GetText ("Destination directory not found: {0}",DirName));
124 if (!MonoIO.CopyFile (sourceFileName, destFileName, overwrite, out error)) {
125 string p = Locale.GetText ("{0}\" or \"{1}", sourceFileName, destFileName);
126 throw MonoIO.GetException (p, error);
130 public static FileStream Create (string path)
132 return Create (path, 8192);
135 public static FileStream Create (string path, int bufferSize)
137 return new FileStream (path, FileMode.Create, FileAccess.ReadWrite,
138 FileShare.None, bufferSize);
141 #if !NET_2_1
142 [MonoLimitation ("FileOptions are ignored")]
143 public static FileStream Create (string path, int bufferSize,
144 FileOptions options)
146 return Create (path, bufferSize, options, null);
149 [MonoLimitation ("FileOptions and FileSecurity are ignored")]
150 public static FileStream Create (string path, int bufferSize,
151 FileOptions options,
152 FileSecurity fileSecurity)
154 return new FileStream (path, FileMode.Create, FileAccess.ReadWrite,
155 FileShare.None, bufferSize, options);
157 #endif
159 public static StreamWriter CreateText (string path)
161 return new StreamWriter (path, false);
164 public static void Delete (string path)
166 if (path == null)
167 throw new ArgumentNullException("path");
168 if (path.Trim().Length == 0 || path.IndexOfAny(Path.InvalidPathChars) >= 0)
169 throw new ArgumentException("path");
170 if (Directory.Exists (path))
171 throw new UnauthorizedAccessException(Locale.GetText ("{0} is a directory", path));
173 string DirName = Path.GetDirectoryName(path);
174 if (DirName != String.Empty && !Directory.Exists (DirName))
175 throw new DirectoryNotFoundException (Locale.GetText ("Could not find a part of the path \"{0}\".", path));
177 MonoIOError error;
179 if (!MonoIO.DeleteFile (path, out error)){
180 if (error != MonoIOError.ERROR_FILE_NOT_FOUND)
181 throw MonoIO.GetException (path, error);
185 public static bool Exists (string path)
187 // For security reasons no exceptions are
188 // thrown, only false is returned if there is
189 // any problem with the path or permissions.
190 // Minimizes what information can be
191 // discovered by using this method.
192 if (path == null || path.Trim().Length == 0
193 || path.IndexOfAny(Path.InvalidPathChars) >= 0) {
194 return false;
197 MonoIOError error;
198 return MonoIO.ExistsFile (path, out error);
201 #if !NET_2_1
202 public static FileSecurity GetAccessControl (string path)
204 throw new NotImplementedException ();
207 public static FileSecurity GetAccessControl (string path, AccessControlSections includeSections)
209 throw new NotImplementedException ();
211 #endif
213 public static FileAttributes GetAttributes (string path)
215 if (path == null)
216 throw new ArgumentNullException("path");
217 if (path.Trim ().Length == 0)
218 throw new ArgumentException (Locale.GetText ("Path is empty"));
219 if (path.IndexOfAny (Path.InvalidPathChars) >= 0)
220 throw new ArgumentException (Locale.GetText ("Path contains invalid chars"));
222 MonoIOError error;
223 FileAttributes attrs;
225 attrs = MonoIO.GetFileAttributes (path, out error);
226 if (error != MonoIOError.ERROR_SUCCESS)
227 throw MonoIO.GetException (path, error);
228 return attrs;
231 public static DateTime GetCreationTime (string path)
233 MonoIOStat stat;
234 MonoIOError error;
235 CheckPathExceptions (path);
237 if (!MonoIO.GetFileStat (path, out stat, out error)) {
238 if (error == MonoIOError.ERROR_PATH_NOT_FOUND || error == MonoIOError.ERROR_FILE_NOT_FOUND)
239 return DefaultLocalFileTime;
240 else
241 throw new IOException (path);
243 return DateTime.FromFileTime (stat.CreationTime);
246 public static DateTime GetCreationTimeUtc (string path)
248 return GetCreationTime (path).ToUniversalTime ();
251 public static DateTime GetLastAccessTime (string path)
253 MonoIOStat stat;
254 MonoIOError error;
255 CheckPathExceptions (path);
257 if (!MonoIO.GetFileStat (path, out stat, out error)) {
258 if (error == MonoIOError.ERROR_PATH_NOT_FOUND || error == MonoIOError.ERROR_FILE_NOT_FOUND)
259 return DefaultLocalFileTime;
260 else
261 throw new IOException (path);
263 return DateTime.FromFileTime (stat.LastAccessTime);
266 public static DateTime GetLastAccessTimeUtc (string path)
268 return GetLastAccessTime (path).ToUniversalTime ();
271 public static DateTime GetLastWriteTime (string path)
273 MonoIOStat stat;
274 MonoIOError error;
275 CheckPathExceptions (path);
277 if (!MonoIO.GetFileStat (path, out stat, out error)) {
278 if (error == MonoIOError.ERROR_PATH_NOT_FOUND || error == MonoIOError.ERROR_FILE_NOT_FOUND)
279 return DefaultLocalFileTime;
280 else
281 throw new IOException (path);
283 return DateTime.FromFileTime (stat.LastWriteTime);
286 public static DateTime GetLastWriteTimeUtc (string path)
288 return GetLastWriteTime (path).ToUniversalTime ();
291 public static void Move (string sourceFileName, string destFileName)
293 MonoIOError error;
295 if (sourceFileName == null)
296 throw new ArgumentNullException ("sourceFileName");
297 if (destFileName == null)
298 throw new ArgumentNullException ("destFileName");
299 if (sourceFileName.Length == 0)
300 throw new ArgumentException ("An empty file name is not valid.", "sourceFileName");
301 if (sourceFileName.Trim ().Length == 0 || sourceFileName.IndexOfAny (Path.InvalidPathChars) != -1)
302 throw new ArgumentException ("The file name is not valid.");
303 if (destFileName.Length == 0)
304 throw new ArgumentException ("An empty file name is not valid.", "destFileName");
305 if (destFileName.Trim ().Length == 0 || destFileName.IndexOfAny (Path.InvalidPathChars) != -1)
306 throw new ArgumentException ("The file name is not valid.");
307 if (!MonoIO.Exists (sourceFileName, out error))
308 throw new FileNotFoundException (Locale.GetText ("{0} does not exist", sourceFileName), sourceFileName);
310 // Don't check for this error here to allow the runtime
311 // to check if sourceFileName and destFileName are equal.
312 // Comparing sourceFileName and destFileName is not enough.
313 //if (MonoIO.Exists (destFileName, out error))
314 // throw new IOException (Locale.GetText ("{0} already exists", destFileName));
316 string DirName;
317 DirName = Path.GetDirectoryName (destFileName);
318 if (DirName != String.Empty && !Directory.Exists (DirName))
319 throw new DirectoryNotFoundException (Locale.GetText ("Could not find a part of the path."));
321 if (!MonoIO.MoveFile (sourceFileName, destFileName, out error)) {
322 if (error == MonoIOError.ERROR_ALREADY_EXISTS)
323 throw MonoIO.GetException (error);
324 else if (error == MonoIOError.ERROR_SHARING_VIOLATION)
325 throw MonoIO.GetException (sourceFileName, error);
327 throw MonoIO.GetException (error);
331 public static FileStream Open (string path, FileMode mode)
333 return new FileStream (path, mode, mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite, FileShare.None);
336 public static FileStream Open (string path, FileMode mode, FileAccess access)
338 return new FileStream (path, mode, access, FileShare.None);
341 public static FileStream Open (string path, FileMode mode, FileAccess access,
342 FileShare share)
344 return new FileStream (path, mode, access, share);
347 public static FileStream OpenRead (string path)
349 return new FileStream (path, FileMode.Open, FileAccess.Read, FileShare.Read);
352 public static StreamReader OpenText (string path)
354 return new StreamReader (path);
357 public static FileStream OpenWrite (string path)
359 return new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
362 public static void Replace (string sourceFileName,
363 string destinationFileName,
364 string destinationBackupFileName)
366 Replace (sourceFileName, destinationFileName, destinationBackupFileName, false);
369 public static void Replace (string sourceFileName,
370 string destinationFileName,
371 string destinationBackupFileName,
372 bool ignoreMetadataErrors)
374 MonoIOError error;
376 if (sourceFileName == null)
377 throw new ArgumentNullException ("sourceFileName");
378 if (destinationFileName == null)
379 throw new ArgumentNullException ("destinationFileName");
380 if (sourceFileName.Trim ().Length == 0 || sourceFileName.IndexOfAny (Path.InvalidPathChars) != -1)
381 throw new ArgumentException ("sourceFileName");
382 if (destinationFileName.Trim ().Length == 0 || destinationFileName.IndexOfAny (Path.InvalidPathChars) != -1)
383 throw new ArgumentException ("destinationFileName");
385 string fullSource = Path.GetFullPath (sourceFileName);
386 string fullDest = Path.GetFullPath (destinationFileName);
387 if (MonoIO.ExistsDirectory (fullSource, out error))
388 throw new IOException (Locale.GetText ("{0} is a directory", sourceFileName));
389 if (MonoIO.ExistsDirectory (fullDest, out error))
390 throw new IOException (Locale.GetText ("{0} is a directory", destinationFileName));
392 if (!Exists (fullSource))
393 throw new FileNotFoundException (Locale.GetText ("{0} does not exist", sourceFileName),
394 sourceFileName);
395 if (!Exists (fullDest))
396 throw new FileNotFoundException (Locale.GetText ("{0} does not exist", destinationFileName),
397 destinationFileName);
398 if (fullSource == fullDest)
399 throw new IOException (Locale.GetText ("Source and destination arguments are the same file."));
401 string fullBackup = null;
402 if (destinationBackupFileName != null) {
403 if (destinationBackupFileName.Trim ().Length == 0 ||
404 destinationBackupFileName.IndexOfAny (Path.InvalidPathChars) != -1)
405 throw new ArgumentException ("destinationBackupFileName");
407 fullBackup = Path.GetFullPath (destinationBackupFileName);
408 if (MonoIO.ExistsDirectory (fullBackup, out error))
409 throw new IOException (Locale.GetText ("{0} is a directory", destinationBackupFileName));
410 if (fullSource == fullBackup)
411 throw new IOException (Locale.GetText ("Source and backup arguments are the same file."));
412 if (fullDest == fullBackup)
413 throw new IOException (Locale.GetText (
414 "Destination and backup arguments are the same file."));
417 if (!MonoIO.ReplaceFile (fullSource, fullDest, fullBackup,
418 ignoreMetadataErrors, out error)) {
419 throw MonoIO.GetException (error);
423 #if !NET_2_1
424 public static void SetAccessControl (string path,
425 FileSecurity fileSecurity)
427 throw new NotImplementedException ();
429 #endif
431 public static void SetAttributes (string path,
432 FileAttributes fileAttributes)
434 MonoIOError error;
435 CheckPathExceptions (path);
437 if (!MonoIO.SetFileAttributes (path, fileAttributes, out error))
438 throw MonoIO.GetException (path, error);
441 public static void SetCreationTime (string path, DateTime creationTime)
443 MonoIOError error;
444 CheckPathExceptions (path);
445 if (!MonoIO.Exists (path, out error))
446 throw MonoIO.GetException (path, error);
447 if (!MonoIO.SetCreationTime (path, creationTime, out error))
448 throw MonoIO.GetException (path, error);
451 public static void SetCreationTimeUtc (string path, DateTime creationTimeUtc)
453 SetCreationTime (path, creationTimeUtc.ToLocalTime ());
456 public static void SetLastAccessTime (string path, DateTime lastAccessTime)
458 MonoIOError error;
459 CheckPathExceptions (path);
460 if (!MonoIO.Exists (path, out error))
461 throw MonoIO.GetException (path, error);
462 if (!MonoIO.SetLastAccessTime (path, lastAccessTime, out error))
463 throw MonoIO.GetException (path, error);
466 public static void SetLastAccessTimeUtc (string path, DateTime lastAccessTimeUtc)
468 SetLastAccessTime (path, lastAccessTimeUtc.ToLocalTime ());
471 public static void SetLastWriteTime (string path,
472 DateTime lastWriteTime)
474 MonoIOError error;
475 CheckPathExceptions (path);
476 if (!MonoIO.Exists (path, out error))
477 throw MonoIO.GetException (path, error);
478 if (!MonoIO.SetLastWriteTime (path, lastWriteTime, out error))
479 throw MonoIO.GetException (path, error);
482 public static void SetLastWriteTimeUtc (string path,
483 DateTime lastWriteTimeUtc)
485 SetLastWriteTime (path, lastWriteTimeUtc.ToLocalTime ());
488 #region Private
490 private static void CheckPathExceptions (string path)
492 if (path == null)
493 throw new System.ArgumentNullException("path");
494 if (path.Length == 0)
495 throw new System.ArgumentException(Locale.GetText ("Path is empty"));
496 if (path.Trim().Length == 0)
497 throw new ArgumentException (Locale.GetText ("Path is empty"));
498 if (path.IndexOfAny (Path.InvalidPathChars) != -1)
499 throw new ArgumentException (Locale.GetText ("Path contains invalid chars"));
502 #endregion
505 // The documentation for this method is most likely wrong, it
506 // talks about doing a "binary read", but the remarks say
507 // that this "detects the encoding".
509 // This can not detect and do anything useful with the encoding
510 // since the result is a byte [] not a char [].
512 public static byte [] ReadAllBytes (string path)
514 using (FileStream s = OpenRead (path)) {
515 long size = s.Length;
516 // limited to 2GB according to http://msdn.microsoft.com/en-us/library/system.io.file.readallbytes.aspx
517 if (size > Int32.MaxValue)
518 throw new IOException ("Reading more than 2GB with this call is not supported");
520 int pos = 0;
521 int count = (int) size;
522 byte [] result = new byte [size];
523 while (count > 0) {
524 int n = s.Read (result, pos, count);
525 if (n == 0)
526 throw new IOException ("Unexpected end of stream");
527 pos += n;
528 count -= n;
530 return result;
534 public static string [] ReadAllLines (string path)
536 using (StreamReader reader = File.OpenText (path)) {
537 return ReadAllLines (reader);
541 public static string [] ReadAllLines (string path, Encoding encoding)
543 using (StreamReader reader = new StreamReader (path, encoding)) {
544 return ReadAllLines (reader);
548 static string [] ReadAllLines (StreamReader reader)
550 List<string> list = new List<string> ();
551 while (!reader.EndOfStream)
552 list.Add (reader.ReadLine ());
553 return list.ToArray ();
556 public static string ReadAllText (string path)
558 ValidatePath (path);
560 using (StreamReader sr = new StreamReader (path)) {
561 return sr.ReadToEnd ();
565 public static string ReadAllText (string path, Encoding encoding)
567 ValidatePath (path);
569 using (StreamReader sr = new StreamReader (path, encoding)) {
570 return sr.ReadToEnd ();
574 public static void WriteAllBytes (string path, byte [] bytes)
576 using (Stream stream = File.Create (path)) {
577 stream.Write (bytes, 0, bytes.Length);
581 public static void WriteAllLines (string path, string [] contents)
583 using (StreamWriter writer = new StreamWriter (path)) {
584 WriteAllLines (writer, contents);
588 public static void WriteAllLines (string path, string [] contents, Encoding encoding)
590 using (StreamWriter writer = new StreamWriter (path, false, encoding)) {
591 WriteAllLines (writer, contents);
595 static void WriteAllLines (StreamWriter writer, string [] contents)
597 foreach (string line in contents)
598 writer.WriteLine (line);
601 public static void WriteAllText (string path, string contents)
603 WriteAllText (path, contents, Encoding.UTF8Unmarked);
606 public static void WriteAllText (string path, string contents, Encoding encoding)
608 using (StreamWriter sw = new StreamWriter (path, false, encoding)) {
609 sw.Write (contents);
613 static DateTime? defaultLocalFileTime;
614 static DateTime DefaultLocalFileTime {
615 get {
616 if (defaultLocalFileTime == null)
617 defaultLocalFileTime = new DateTime (1601, 1, 1).ToLocalTime ();
619 return defaultLocalFileTime.Value;
624 [MonoLimitation ("File encryption isn't supported (even on NTFS).")]
625 public static void Encrypt (string path)
627 // MS.NET support this only on NTFS file systems, i.e. it's a file-system (not a framework) feature.
628 // otherwise it throws a NotSupportedException (or a PlatformNotSupportedException on older OS).
629 // we throw the same (instead of a NotImplementedException) because most code should already be
630 // handling this exception to work properly.
631 throw new NotSupportedException (Locale.GetText ("File encryption isn't supported on any file system."));
634 [MonoLimitation ("File encryption isn't supported (even on NTFS).")]
635 public static void Decrypt (string path)
637 // MS.NET support this only on NTFS file systems, i.e. it's a file-system (not a framework) feature.
638 // otherwise it throws a NotSupportedException (or a PlatformNotSupportedException on older OS).
639 // we throw the same (instead of a NotImplementedException) because most code should already be
640 // handling this exception to work properly.
641 throw new NotSupportedException (Locale.GetText ("File encryption isn't supported on any file system."));
644 #if MOONLIGHT || NET_4_0
645 public static IEnumerable<string> ReadLines (string path)
647 ValidatePath (path);
649 using (StreamReader reader = File.OpenText (path)) {
650 return ReadLines (reader);
654 public static IEnumerable<string> ReadLines (string path, Encoding encoding)
656 ValidatePath (path);
658 using (StreamReader reader = new StreamReader (path, encoding)) {
659 return ReadLines (reader);
663 // refactored in order to avoid compiler-generated names for Moonlight tools
664 static IEnumerable<string> ReadLines (StreamReader reader)
666 string s;
667 while ((s = reader.ReadLine ()) != null)
668 yield return s;
671 public static void AppendAllLines (string path, IEnumerable<string> contents)
673 ValidatePath (path);
675 if (contents == null)
676 return;
678 using (TextWriter w = new StreamWriter (path, true)) {
679 foreach (var line in contents)
680 w.Write (line);
684 public static void AppendAllLines (string path, IEnumerable<string> contents, Encoding encoding)
686 ValidatePath (path);
688 if (contents == null)
689 return;
691 using (TextWriter w = new StreamWriter (path, true, encoding)) {
692 foreach (var line in contents)
693 w.Write (line);
697 public static void WriteAllLines (string path, IEnumerable<string> contents)
699 ValidatePath (path);
701 if (contents == null)
702 return;
704 using (TextWriter w = new StreamWriter (path, false)) {
705 foreach (var line in contents)
706 w.Write (line);
710 public static void WriteAllLines (string path, IEnumerable<string> contents, Encoding encoding)
712 ValidatePath (path);
714 if (contents == null)
715 return;
717 using (TextWriter w = new StreamWriter (path, false, encoding)) {
718 foreach (var line in contents)
719 w.Write (line);
722 #endif