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.
37 using System
.Collections
.Generic
;
38 using System
.Runtime
.InteropServices
;
41 using System
.Security
;
43 using System
.Security
.AccessControl
;
49 public static class File
51 static void ValidatePath (string path
)
54 throw new ArgumentNullException ("path");
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");
63 public static void AppendAllText (string path
, string contents
)
67 using (TextWriter w
= new StreamWriter (path
, true)) {
72 public static void AppendAllText (string path
, string contents
, Encoding encoding
)
76 using (TextWriter w
= new StreamWriter (path
, true, encoding
)) {
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
)
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
));
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
);
142 [MonoLimitation ("FileOptions are ignored")]
143 public static FileStream
Create (string path
, int bufferSize
,
146 return Create (path
, bufferSize
, options
, null);
149 [MonoLimitation ("FileOptions and FileSecurity are ignored")]
150 public static FileStream
Create (string path
, int bufferSize
,
152 FileSecurity fileSecurity
)
154 return new FileStream (path
, FileMode
.Create
, FileAccess
.ReadWrite
,
155 FileShare
.None
, bufferSize
, options
);
159 public static StreamWriter
CreateText (string path
)
161 return new StreamWriter (path
, false);
164 public static void Delete (string path
)
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
));
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) {
198 return MonoIO
.ExistsFile (path
, out error
);
202 public static FileSecurity
GetAccessControl (string path
)
204 throw new NotImplementedException ();
207 public static FileSecurity
GetAccessControl (string path
, AccessControlSections includeSections
)
209 throw new NotImplementedException ();
213 public static FileAttributes
GetAttributes (string path
)
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"));
223 FileAttributes attrs
;
225 attrs
= MonoIO
.GetFileAttributes (path
, out error
);
226 if (error
!= MonoIOError
.ERROR_SUCCESS
)
227 throw MonoIO
.GetException (path
, error
);
231 public static DateTime
GetCreationTime (string path
)
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
;
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
)
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
;
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
)
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
;
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
)
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));
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
,
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
)
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
),
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
);
424 public static void SetAccessControl (string path
,
425 FileSecurity fileSecurity
)
427 throw new NotImplementedException ();
431 public static void SetAttributes (string path
,
432 FileAttributes fileAttributes
)
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
)
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
)
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
)
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 ());
490 private static void CheckPathExceptions (string path
)
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"));
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");
521 int count
= (int) size
;
522 byte [] result
= new byte [size
];
524 int n
= s
.Read (result
, pos
, count
);
526 throw new IOException ("Unexpected end of stream");
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
)
560 using (StreamReader sr
= new StreamReader (path
)) {
561 return sr
.ReadToEnd ();
565 public static string ReadAllText (string path
, Encoding encoding
)
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
)) {
613 static DateTime
? defaultLocalFileTime
;
614 static DateTime DefaultLocalFileTime
{
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
)
649 using (StreamReader reader
= File
.OpenText (path
)) {
650 return ReadLines (reader
);
654 public static IEnumerable
<string> ReadLines (string path
, Encoding encoding
)
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
)
667 while ((s
= reader
.ReadLine ()) != null)
671 public static void AppendAllLines (string path
, IEnumerable
<string> contents
)
675 if (contents
== null)
678 using (TextWriter w
= new StreamWriter (path
, true)) {
679 foreach (var line
in contents
)
684 public static void AppendAllLines (string path
, IEnumerable
<string> contents
, Encoding encoding
)
688 if (contents
== null)
691 using (TextWriter w
= new StreamWriter (path
, true, encoding
)) {
692 foreach (var line
in contents
)
697 public static void WriteAllLines (string path
, IEnumerable
<string> contents
)
701 if (contents
== null)
704 using (TextWriter w
= new StreamWriter (path
, false)) {
705 foreach (var line
in contents
)
710 public static void WriteAllLines (string path
, IEnumerable
<string> contents
, Encoding encoding
)
714 if (contents
== null)
717 using (TextWriter w
= new StreamWriter (path
, false, encoding
)) {
718 foreach (var line
in contents
)