c4ed76b34bfb513728eed443ef12e521b1e1dc03
[mono.git] / mcs / class / corlib / System.IO / File.cs
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)
10 //
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)
14 //
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.
33 //
34
35 using System;
36 using System.Collections.Generic;
37 using System.Diagnostics;
38 using System.Security;
39 using System.Text;
40 using System.Runtime.InteropServices;
41
42 #if !NET_2_1
43 using System.Security.AccessControl;
44 #endif
45
46 namespace System.IO
47 {
48         [ComVisible (true)]
49         public static class File
50         {
51                 public static void AppendAllText (string path, string contents)
52                 {
53                         using (TextWriter w = new StreamWriter (path, true)) {
54                                 w.Write (contents);
55                         }
56                 }
57
58                 public static void AppendAllText (string path, string contents, Encoding encoding)
59                 {
60                         using (TextWriter w = new StreamWriter (path, true, encoding)) {
61                                 w.Write (contents);
62                         }
63                 }
64
65                 public static StreamWriter AppendText (string path)
66                 {
67                         return new StreamWriter (path, true);
68                 }
69
70                 public static void Copy (string sourceFileName, string destFileName)
71                 {
72                         Copy (sourceFileName, destFileName, false);
73                 }
74
75                 public static void Copy (string sourceFileName, string destFileName, bool overwrite)
76                 {
77                         MonoIOError error;
78
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.");
91
92                         SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
93
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));
98
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));
102                                 if (!overwrite)
103                                         throw new IOException (Locale.GetText ("{0} already exists", destFileName));
104                         }
105
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));
109
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);
113                         }
114                 }
115
116                 public static FileStream Create (string path)
117                 {
118                         return Create (path, 8192);
119                 }
120
121                 public static FileStream Create (string path, int bufferSize)
122                 {
123                         return new FileStream (path, FileMode.Create, FileAccess.ReadWrite,
124                                 FileShare.None, bufferSize);
125                 }
126
127                 [MonoLimitation ("FileOptions are ignored")]
128                 public static FileStream Create (string path, int bufferSize,
129                                                  FileOptions options)
130                 {
131                         return new FileStream (path, FileMode.Create, FileAccess.ReadWrite,
132                                 FileShare.None, bufferSize, options);
133                 }
134                 
135 #if !NET_2_1
136                 [MonoLimitation ("FileOptions and FileSecurity are ignored")]
137                 public static FileStream Create (string path, int bufferSize,
138                                                  FileOptions options,
139                                                  FileSecurity fileSecurity)
140                 {
141                         return new FileStream (path, FileMode.Create, FileAccess.ReadWrite,
142                                 FileShare.None, bufferSize, options);
143                 }
144 #endif
145
146                 public static StreamWriter CreateText (string path)
147                 {
148                         return new StreamWriter (path, false);
149                 }
150
151                 public static void Delete (string path)
152                 {
153                         Path.Validate (path);
154                         if (Directory.Exists (path))
155                                 throw new UnauthorizedAccessException(Locale.GetText ("{0} is a directory", path));
156
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));
160
161                         SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
162
163                         MonoIOError error;
164                         
165                         if (!MonoIO.DeleteFile (path, out error)){
166                                 if (error != MonoIOError.ERROR_FILE_NOT_FOUND)
167                                         throw MonoIO.GetException (path, error);
168                         }
169                 }
170
171                 public static bool Exists (string path)
172                 {
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)
179                                 return false;
180
181                         // on Moonlight this does not throw but returns false
182                         if (!SecurityManager.CheckElevatedPermissions ())
183                                 return false;
184
185                         MonoIOError error;
186                         return MonoIO.ExistsFile (path, out error);
187                 }
188
189 #if !NET_2_1
190                 public static FileSecurity GetAccessControl (string path)
191                 {
192                         // AccessControlSections.Audit requires special permissions.
193                         return GetAccessControl (path,
194                                                  AccessControlSections.Owner |
195                                                  AccessControlSections.Group |
196                                                  AccessControlSections.Access);
197                 }
198                 
199                 public static FileSecurity GetAccessControl (string path, AccessControlSections includeSections)
200                 {
201                         return new FileSecurity (path, includeSections);
202                 }
203 #endif
204
205                 public static FileAttributes GetAttributes (string path)
206                 {
207                         Path.Validate (path);
208                         SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
209
210                         MonoIOError error;
211                         FileAttributes attrs;
212                         
213                         attrs = MonoIO.GetFileAttributes (path, out error);
214                         if (error != MonoIOError.ERROR_SUCCESS)
215                                 throw MonoIO.GetException (path, error);
216                         return attrs;
217                 }
218
219                 public static DateTime GetCreationTime (string path)
220                 {
221                         MonoIOStat stat;
222                         MonoIOError error;
223                         Path.Validate (path);
224                         SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
225
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;
229                                 else
230                                         throw new IOException (path);
231                         }
232                         return DateTime.FromFileTime (stat.CreationTime);
233                 }
234
235                 public static DateTime GetCreationTimeUtc (string path)
236                 {
237                         return GetCreationTime (path).ToUniversalTime ();
238                 }
239
240                 public static DateTime GetLastAccessTime (string path)
241                 {
242                         MonoIOStat stat;
243                         MonoIOError error;
244                         Path.Validate (path);
245                         SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
246
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;
250                                 else
251                                         throw new IOException (path);
252                         }
253                         return DateTime.FromFileTime (stat.LastAccessTime);
254                 }
255
256                 public static DateTime GetLastAccessTimeUtc (string path)
257                 {
258                         return GetLastAccessTime (path).ToUniversalTime ();
259                 }
260
261                 public static DateTime GetLastWriteTime (string path)
262                 {
263                         MonoIOStat stat;
264                         MonoIOError error;
265                         Path.Validate (path);
266                         SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
267
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;
271                                 else
272                                         throw new IOException (path);
273                         }
274                         return DateTime.FromFileTime (stat.LastWriteTime);
275                 }
276
277                 public static DateTime GetLastWriteTimeUtc (string path)
278                 {
279                         return GetLastWriteTime (path).ToUniversalTime ();
280                 }
281
282                 public static void Move (string sourceFileName, string destFileName)
283                 {
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.");
296
297                         SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
298
299                         MonoIOError error;
300                         if (!MonoIO.Exists (sourceFileName, out error))
301                                 throw new FileNotFoundException (Locale.GetText ("{0} does not exist", sourceFileName), sourceFileName);
302
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));
308
309                         string DirName;
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."));
313
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);
319                                 
320                                 throw MonoIO.GetException (error);
321                         }
322                 }
323                 
324                 public static FileStream Open (string path, FileMode mode)
325                 {
326                         return new FileStream (path, mode, mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite, FileShare.None);
327                 }
328                 
329                 public static FileStream Open (string path, FileMode mode, FileAccess access)
330                 {
331                         return new FileStream (path, mode, access, FileShare.None);
332                 }
333
334                 public static FileStream Open (string path, FileMode mode, FileAccess access,
335                                                FileShare share)
336                 {
337                         return new FileStream (path, mode, access, share);
338                 }
339                 
340                 public static FileStream OpenRead (string path)
341                 {
342                         return new FileStream (path, FileMode.Open, FileAccess.Read, FileShare.Read);
343                 }
344
345                 public static StreamReader OpenText (string path)
346                 {
347                         return new StreamReader (path);
348                 }
349
350                 public static FileStream OpenWrite (string path)
351                 {
352                         return new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
353                 }
354
355                 public static void Replace (string sourceFileName,
356                                             string destinationFileName,
357                                             string destinationBackupFileName)
358                 {
359                         Replace (sourceFileName, destinationFileName, destinationBackupFileName, false);
360                 }
361                 
362                 public static void Replace (string sourceFileName,
363                                             string destinationFileName,
364                                             string destinationBackupFileName,
365                                             bool ignoreMetadataErrors)
366                 {
367                         MonoIOError error;
368
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");
377
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));
384
385                         if (!Exists (fullSource))
386                                 throw new FileNotFoundException (Locale.GetText ("{0} does not exist", sourceFileName), 
387                                                                  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."));
393
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");
399
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."));
408                         }
409
410                         if (!MonoIO.ReplaceFile (fullSource, fullDest, fullBackup, 
411                                                  ignoreMetadataErrors, out error)) {
412                                 throw MonoIO.GetException (error);
413                         }
414                 }
415
416 #if !NET_2_1
417                 public static void SetAccessControl (string path,
418                                                      FileSecurity fileSecurity)
419                 {
420                         if (null == fileSecurity)
421                                 throw new ArgumentNullException ("fileSecurity");
422
423                         fileSecurity.PersistModifications (path);
424                 }
425 #endif
426
427                 public static void SetAttributes (string path,
428                                                   FileAttributes fileAttributes)
429                 {
430                         MonoIOError error;
431                         Path.Validate (path);
432
433                         if (!MonoIO.SetFileAttributes (path, fileAttributes, out error))
434                                 throw MonoIO.GetException (path, error);
435                 }
436
437                 public static void SetCreationTime (string path, DateTime creationTime)
438                 {
439                         MonoIOError error;
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);
445                 }
446
447                 public static void SetCreationTimeUtc (string path, DateTime creationTimeUtc)
448                 {
449                         SetCreationTime (path, creationTimeUtc.ToLocalTime ());
450                 }
451
452                 public static void SetLastAccessTime (string path, DateTime lastAccessTime)
453                 {
454                         MonoIOError error;
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);
460                 }
461
462                 public static void SetLastAccessTimeUtc (string path, DateTime lastAccessTimeUtc)
463                 {
464                         SetLastAccessTime (path, lastAccessTimeUtc.ToLocalTime ());
465                 }
466
467                 public static void SetLastWriteTime (string path,
468                                                      DateTime lastWriteTime)
469                 {
470                         MonoIOError error;
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);
476                 }
477
478                 public static void SetLastWriteTimeUtc (string path,
479                                                      DateTime lastWriteTimeUtc)
480                 {
481                         SetLastWriteTime (path, lastWriteTimeUtc.ToLocalTime ());
482                 }
483
484                 //
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".
488                 //
489                 // This can not detect and do anything useful with the encoding
490                 // since the result is a byte [] not a char [].
491                 //
492                 public static byte [] ReadAllBytes (string path)
493                 {
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");
499
500                                 int pos = 0;
501                                 int count = (int) size;
502                                 byte [] result = new byte [size];
503                                 while (count > 0) {
504                                         int n = s.Read (result, pos, count);
505                                         if (n == 0)
506                                                 throw new IOException ("Unexpected end of stream");
507                                         pos += n;
508                                         count -= n;
509                                 }
510                                 return result;
511                         }
512                 }
513
514                 public static string [] ReadAllLines (string path)
515                 {
516                         using (StreamReader reader = File.OpenText (path)) {
517                                 return ReadAllLines (reader);
518                         }
519                 }
520
521                 public static string [] ReadAllLines (string path, Encoding encoding)
522                 {
523                         using (StreamReader reader = new StreamReader (path, encoding)) {
524                                 return ReadAllLines (reader);
525                         }
526                 }
527
528                 static string [] ReadAllLines (StreamReader reader)
529                 {
530                         List<string> list = new List<string> ();
531                         while (!reader.EndOfStream)
532                                 list.Add (reader.ReadLine ());
533                         return list.ToArray ();
534                 }
535
536                 public static string ReadAllText (string path)
537                 {
538                         using (StreamReader sr = new StreamReader (path)) {
539                                 return sr.ReadToEnd ();
540                         }
541                 }
542
543                 public static string ReadAllText (string path, Encoding encoding)
544                 {
545                         using (StreamReader sr = new StreamReader (path, encoding)) {
546                                 return sr.ReadToEnd ();
547                         }
548                 }
549
550                 public static void WriteAllBytes (string path, byte [] bytes)
551                 {
552                         using (Stream stream = File.Create (path)) {
553                                 stream.Write (bytes, 0, bytes.Length);
554                         }
555                 }
556
557                 public static void WriteAllLines (string path, string [] contents)
558                 {
559                         using (StreamWriter writer = new StreamWriter (path)) {
560                                 WriteAllLines (writer, contents);
561                         }
562                 }
563
564                 public static void WriteAllLines (string path, string [] contents, Encoding encoding)
565                 {
566                         using (StreamWriter writer = new StreamWriter (path, false, encoding)) {
567                                 WriteAllLines (writer, contents);
568                         }
569                 }
570
571                 static void WriteAllLines (StreamWriter writer, string [] contents)
572                 {
573                         foreach (string line in contents)
574                                 writer.WriteLine (line);
575                 }
576
577                 public static void WriteAllText (string path, string contents)
578                 {
579                         WriteAllText (path, contents, Encoding.UTF8Unmarked);
580                 }
581
582                 public static void WriteAllText (string path, string contents, Encoding encoding)
583                 {
584                         using (StreamWriter sw = new StreamWriter (path, false, encoding)) {
585                                 sw.Write (contents);
586                         }
587                 }
588
589                 static DateTime? defaultLocalFileTime;
590                 static DateTime DefaultLocalFileTime {
591                         get {
592                                 if (defaultLocalFileTime == null)
593                                         defaultLocalFileTime = new DateTime (1601, 1, 1).ToLocalTime ();
594                                         
595                                 return defaultLocalFileTime.Value;
596                         }
597                 }
598
599
600                 [MonoLimitation ("File encryption isn't supported (even on NTFS).")]
601                 public static void Encrypt (string path)
602                 {
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."));
608                 }
609
610                 [MonoLimitation ("File encryption isn't supported (even on NTFS).")]
611                 public static void Decrypt (string path)
612                 {
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."));
618                 }
619
620 #if NET_4_0
621                 public static IEnumerable<string> ReadLines (string path)
622                 {
623                         return ReadLines (File.OpenText (path));
624                 }
625
626                 public static IEnumerable<string> ReadLines (string path, Encoding encoding)
627                 {
628                         return ReadLines (new StreamReader (path, encoding));
629                 }
630
631                 // refactored in order to avoid compiler-generated names for Moonlight tools
632                 static IEnumerable<string> ReadLines (StreamReader reader)
633                 {
634                         using (reader) {
635                                 string s;
636                                 while ((s = reader.ReadLine ()) != null) {
637                                         yield return s;
638                                 }
639                         }
640                 }
641
642                 public static void AppendAllLines (string path, IEnumerable<string> contents)
643                 {
644                         Path.Validate (path);
645
646                         if (contents == null)
647                                 return;
648
649                         using (TextWriter w = new StreamWriter (path, true)) {
650                                 foreach (var line in contents)
651                                         w.WriteLine (line);
652                         }
653                 }
654
655                 public static void AppendAllLines (string path, IEnumerable<string> contents, Encoding encoding)
656                 {
657                         Path.Validate (path);
658
659                         if (contents == null)
660                                 return;
661
662                         using (TextWriter w = new StreamWriter (path, true, encoding)) {
663                                 foreach (var line in contents)
664                                         w.WriteLine (line);
665                         }
666                 }
667
668                 public static void WriteAllLines (string path, IEnumerable<string> contents)
669                 {
670                         Path.Validate (path);
671
672                         if (contents == null)
673                                 return;
674
675                         using (TextWriter w = new StreamWriter (path, false)) {
676                                 foreach (var line in contents)
677                                         w.WriteLine (line);
678                         }
679                 }
680
681                 public static void WriteAllLines (string path, IEnumerable<string> contents, Encoding encoding)
682                 {
683                         Path.Validate (path);
684
685                         if (contents == null)
686                                 return;
687
688                         using (TextWriter w = new StreamWriter (path, false, encoding)) {
689                                 foreach (var line in contents)
690                                         w.WriteLine (line);
691                         }
692                 }
693 #endif
694         }
695 }