|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using System.Runtime.Versioning;
using System.Text;
namespace System.IO
{
// Class for creating FileStream objects, and some basic file management
// routines such as Delete, etc.
public sealed class FileInfo : FileSystemInfo
{
private FileInfo() { }
public FileInfo(string fileName)
: this(fileName ?? throw new ArgumentNullException(nameof(fileName)), isNormalized: false)
{
}
internal FileInfo(string originalPath, string? fullPath = null, string? fileName = null, bool isNormalized = false)
{
OriginalPath = originalPath;
fullPath ??= originalPath;
Debug.Assert(!isNormalized || !PathInternal.IsPartiallyQualified(fullPath.AsSpan()), "should be fully qualified if normalized");
FullPath = isNormalized ? fullPath ?? originalPath : Path.GetFullPath(fullPath);
_name = fileName;
}
public override string Name => _name ??= Path.GetFileName(OriginalPath);
public long Length
{
get
{
if ((Attributes & FileAttributes.Directory) == FileAttributes.Directory)
{
throw new FileNotFoundException(SR.Format(SR.IO_FileNotFound_FileName, FullPath), FullPath);
}
return LengthCore;
}
}
public string? DirectoryName => Path.GetDirectoryName(FullPath);
public DirectoryInfo? Directory
{
get
{
string? dirName = DirectoryName;
if (dirName == null)
return null;
return new DirectoryInfo(dirName);
}
}
public bool IsReadOnly
{
get
{
return (Attributes & FileAttributes.ReadOnly) != 0;
}
set
{
if (value)
Attributes |= FileAttributes.ReadOnly;
else
Attributes &= ~FileAttributes.ReadOnly;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="FileStream" /> class with the specified creation mode, read/write and sharing permission, the access other FileStreams can have to the same file, the buffer size, additional file options and the allocation size.
/// </summary>
/// <remarks><see cref="FileStream(string,FileStreamOptions)"/> for information about exceptions.</remarks>
public FileStream Open(FileStreamOptions options)
{
FileStream fileStream = File.Open(NormalizedPath, options);
Invalidate();
return fileStream;
}
public StreamReader OpenText()
{
StreamReader reader = new StreamReader(NormalizedPath, Encoding.UTF8, detectEncodingFromByteOrderMarks: true);
Invalidate();
return reader;
}
public StreamWriter CreateText()
=> CreateStreamWriter(append: false);
public StreamWriter AppendText()
=> CreateStreamWriter(append: true);
public FileInfo CopyTo(string destFileName) => CopyTo(destFileName, overwrite: false);
public FileInfo CopyTo(string destFileName, bool overwrite)
{
ArgumentException.ThrowIfNullOrEmpty(destFileName);
string destinationPath = Path.GetFullPath(destFileName);
FileSystem.CopyFile(FullPath, destinationPath, overwrite);
return new FileInfo(destinationPath, isNormalized: true);
}
public FileStream Create()
{
FileStream fileStream = File.Create(NormalizedPath);
Invalidate();
return fileStream;
}
public override void Delete()
{
FileSystem.DeleteFile(FullPath);
Invalidate();
}
public override bool Exists
{
get
{
try
{
return ExistsCore;
}
catch
{
return false;
}
}
}
public FileStream Open(FileMode mode)
=> Open(mode, (mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite), FileShare.None);
public FileStream Open(FileMode mode, FileAccess access)
=> Open(mode, access, FileShare.None);
public FileStream Open(FileMode mode, FileAccess access, FileShare share)
{
FileStream fileStream = new FileStream(NormalizedPath, mode, access, share);
Invalidate();
return fileStream;
}
public FileStream OpenRead()
{
FileStream fileStream = new FileStream(NormalizedPath, FileMode.Open, FileAccess.Read, FileShare.Read, File.DefaultBufferSize, false);
Invalidate();
return fileStream;
}
public FileStream OpenWrite()
{
FileStream fileStream = new FileStream(NormalizedPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
Invalidate();
return fileStream;
}
// Moves a given file to a new location and potentially a new file name.
// This method does work across volumes.
public void MoveTo(string destFileName)
{
MoveTo(destFileName, false);
}
// Moves a given file to a new location and potentially a new file name.
// Optionally overwrites existing file.
// This method does work across volumes.
public void MoveTo(string destFileName, bool overwrite)
{
ArgumentException.ThrowIfNullOrEmpty(destFileName);
string fullDestFileName = Path.GetFullPath(destFileName);
// These checks are in place to ensure Unix error throwing happens the same way
// as it does on Windows.These checks can be removed if a solution to
// https://github.com/dotnet/runtime/issues/14885 is found that doesn't require
// validity checks before making an API call.
string? directoryPath = Path.GetDirectoryName(FullName);
if (!System.IO.Directory.Exists(directoryPath))
throw new DirectoryNotFoundException(SR.Format(SR.IO_PathNotFound_Path, directoryPath), directoryPath);
if (!Exists)
throw new FileNotFoundException(SR.Format(SR.IO_FileNotFound_FileName, FullName), FullName);
FileSystem.MoveFile(FullPath, fullDestFileName, overwrite);
FullPath = fullDestFileName;
OriginalPath = destFileName;
_name = Path.GetFileName(fullDestFileName);
// Flush any cached information about the file.
Invalidate();
}
public FileInfo Replace(string destinationFileName, string? destinationBackupFileName)
=> Replace(destinationFileName, destinationBackupFileName, ignoreMetadataErrors: false);
public FileInfo Replace(string destinationFileName, string? destinationBackupFileName, bool ignoreMetadataErrors)
{
ArgumentNullException.ThrowIfNull(destinationFileName);
FileSystem.ReplaceFile(
FullPath,
Path.GetFullPath(destinationFileName),
destinationBackupFileName != null ? Path.GetFullPath(destinationBackupFileName) : null,
ignoreMetadataErrors);
Invalidate();
return new FileInfo(destinationFileName);
}
[SupportedOSPlatform("windows")]
public void Decrypt()
{
File.Decrypt(FullPath);
Invalidate();
}
[SupportedOSPlatform("windows")]
public void Encrypt()
{
File.Encrypt(FullPath);
Invalidate();
}
private StreamWriter CreateStreamWriter(bool append)
{
StreamWriter streamWriter = new StreamWriter(NormalizedPath, append);
Invalidate();
return streamWriter;
}
/// <summary>
/// Creates a hard link located in <see cref="Name"/> that refers to the same file content as <paramref name="pathToTarget"/>.
/// </summary>
/// <param name="pathToTarget">The path of the hard link target.</param>
/// <exception cref="ArgumentNullException"><paramref name="pathToTarget"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentException"><paramref name="pathToTarget"/> is empty.
/// -or-
/// <paramref name="pathToTarget"/> contains invalid path characters.</exception>
/// <exception cref="FileNotFoundException">The file specified by <paramref name="pathToTarget"/> does not exist.</exception>
/// <exception cref="IOException">A file or directory already exists in the location of <see cref="Name"/>.
/// -or-
/// An I/O error occurred.</exception>
public void CreateAsHardLink(string pathToTarget)
{
FileSystem.VerifyValidPath(pathToTarget, nameof(pathToTarget));
FileSystem.CreateHardLink(OriginalPath, pathToTarget);
Invalidate();
}
}
}
|