ファイルの MD5 (でなくても全然かまわないんだけど)によるハッシュ値が欲しいんだけど、System.IO.FileInfo クラスにはそういうフィールドがないので「継承して追加しよう」と思ったら、Not Inheritable だったという罠。
仕方がないので、より上位の System.IO.FileSystemInfo クラスから継承し、FileInfo と同等のメソッドも実装することにする。
新しいクラス名は、安直に FileInfoEx。
とりあえず、書く。すると、親クラスの抽象メソッドを実装するように言われるので、実装する。MSDN をよく読むと、幸い同じ動作をさせるための静的メソッドが存在しているので、それを利用する。
class FileInfoEx : System.IO.FileSystemInfo
{
#region FileSystemInfo クラスの抽象メンバ
public override void Delete() {
System.IO.File.Delete(base.FullPath);
}
public override bool Exists {
get {
return System.IO.File.Exists(base.FullPath);
}
}
public override string Name {
get {
return Path.GetFileName(base.FullPath);
}
}
#endregion
}
次、コンストラクタ。とりあえず、FileInfo クラスのコンストラクタと同じものを用意することにする。で、MSDN を読む。string クラスの引数をひとつ受け取るコンストラクタがあればいいらしい。でも、その引数を、きちんとチェックしなければならん、らしい。
public FileInfoEx(string fileName) : base() {
if (fileName == null) {
throw new ArgumentNullException("fileName");
}
if (fileName.Trim() == string.Empty) {
throw new ArgumentException("fileName");
}
string fullPath = Path.GetFullPath(fileName);
if (Path.GetFileName(fullPath).IndexOfAny(Path.GetInvalidFileNameChars()) >= 0
|| Path.GetDirectoryName(fullPath).IndexOfAny(Path.GetInvalidPathChars()) >= 0) {
throw new ArgumentException("パス名に、使用してはいけない文字が含まれています。");
}
this._directory = null;
base.FullPath = fullPath;
base.Refresh();
}
それで、FileInfo と同等にすべく、FileInfo クラスのメンバ一覧を見て、足りない分、つまり「FileSystemInfo から継承しています」という記述のないメンバを実装する。
#region System.IO.FileInfo クラスと同等のプロパティ宣言
private DirectoryInfo _directory;
/// <summary>
/// 親ディレクトリのインスタンスを取得します。
/// </summary>
public DirectoryInfo Directory {
get {
if (this._directory == null) {
this._directory = new DirectoryInfo(Path.GetDirectoryName(base.FullPath));
}
return this._directory;
}
}
/// <summary>
/// ディレクトリの絶対パスを表す文字列を取得します。
/// </summary>
public string DirectoryName {
get {
return Path.GetDirectoryName(base.FullPath);
}
}
/// <summary>
/// 現在のファイルが読み取り専用であるかどうかを判断する値を取得または設定します。
/// </summary>
public bool IsReadOnly {
get {
base.Refresh();
return ((base.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly);
}
set {
base.Refresh();
FileAttributes attributes = File.GetAttributes(base.FullPath);
if (value == true) {
attributes |= FileAttributes.ReadOnly;
} else {
attributes = (attributes & ~FileAttributes.ReadOnly);
}
File.SetAttributes(base.FullPath, attributes);
}
}
#endregion
で、肝心の、ハッシュ値を求めるところ。一応、デフォルトを MD5 とし、プロバイダを指定すれば他のアルゴリズムも使えるようにする。
#region GetFileHashCode のオーバー ロード
/// <summary>
/// MD5 アルゴリズムを使用して、ファイルのハッシュ値を取得します。
/// </summary>
/// <returns>MD5 アルゴリズムによる、ファイルのハッシュ値</returns>
public byte[] GetFileHashCode() {
return GetFileHashCode(new System.Security.Cryptography.MD5CryptoServiceProvider());
}
/// <summary>
/// 指定した暗号化サービス プロバイダを使用して、ファイルのハッシュ値を取得します。
/// </summary>
/// <param name="cryptoServiceProvider">ハッシュ値計算のために使用する暗号化サービス プロバイダ</param>
/// <returns>ファイルのハッシュ値</returns>
public byte[] GetFileHashCode(System.Security.Cryptography.HashAlgorithm cryptoServiceProvider) {
if (cryptoServiceProvider == null) {
throw new ArgumentNullException("cryptoServiceProvider");
}
return cryptoServiceProvider.ComputeHash(File.ReadAllBytes(base.FullPath));
}
#endregion
一応、これで揃った。さらに、よく読んで、抜けがないか確認する。というか、FileSystemInfo って、IDisposable を継承しているんですよ。Dispose をオーバーロードする必要があるのか、確認する。
うむ。IDispose.Dispose は明示実装され、Clear メソッドに名称変更されていますね。Dispose というと Close ばかり取り上げられますが、ここに Clear という因子も発見(←実は、これが書きたかっただけ)。
どうも、関係なさそうですね。はい、お終い。
使用するものは、よく確認してから使いましょう。
あ・・・。FileInfo を引数にするコンストラクタを作ってもよかったか。。。しかし、どっちにしても、System.IO.DirectoryInfo.GetFileSystemInfos メソッドからの戻り値を、そのまま使うことは出来ないorz
投稿日時 : 2006年11月8日 21:35