Saturday, July 18, 2009

Some FileInfo Extensions

I kept on needing the same stuff regarding files when writing C#, so I came up with a set of helpers implemented as extensions to the FileInfo class.

Nothing particularly earth-shattering, but you might find them useful.

  • IsDirectory - does the obvious
  • GetMimeType - uses Windows' urlmon.dll to magically determine a file's mime type.
  • GetFileBytes - gets a chunk off the front of a file.
  • GetSha1, and friends - Computes the SHA1 hash of a file. Configurable buffer size.
  • ApplyToFolder - accepts a function to be applied to every file in a hierarchy.

Latest version here.

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;

namespace QSha
{
public static class FileInfoExtensions
{
public static bool IsDirectory( this FileInfo fi )
{
if ( !( ( FileAttributes.Directory & fi.Attributes ) == FileAttributes.Directory ) )
{
return false;
}
return true;
}


public static byte[] GetFileBytes( this FileInfo fi, long maxBufSize )
{
byte[] buffer = new byte[( fi.Length > maxBufSize ? maxBufSize : fi.Length )];
using ( FileStream fs =
new FileStream( fi.FullName, FileMode.Open, FileAccess.Read, FileShare.Read, buffer.Length ) )
{
fs.Read( buffer, 0, buffer.Length );
fs.Close();
}

return buffer;
}

public static void ApplyToFolder( this FileInfo fi, Func fFileFound )
{
string[] subFolders;
try
{
subFolders = Directory.GetDirectories( fi.FullName );
}
catch ( UnauthorizedAccessException )
{
return;
}

string[] files;
foreach ( string folder in subFolders )
{
FileInfo tmpFi = new FileInfo( folder );
tmpFi.ApplyToFolder( fFileFound );

try
{
files = Directory.GetFiles( folder );
}
catch ( UnauthorizedAccessException )
{
continue;
}

foreach ( string file in files )
{
bool ffres = fFileFound( new FileInfo( file ) );

// we don't do any post-processing, so these are wasted cycles
/*
if ( !ffres )
continue;
*/
}
}
}

// mime-type stuff
public static string GetMimeType( this FileInfo fi )
{

if ( fi.IsDirectory() )
throw new FileNotFoundException( String.Format( "Is a directory, not a file: {0}", fi.FullName ) );

if ( !File.Exists( fi.FullName ) )
throw new FileNotFoundException( fi.FullName + " not found" );


byte[] buffer = new byte[256];
using ( FileStream fs = new FileStream( fi.FullName, FileMode.Open ) )
{
if ( fs.Length >= 256 )
fs.Read( buffer, 0, 256 );
else
fs.Read( buffer, 0, (int)fs.Length );
}
try
{
System.UInt32 mimetype;
FindMimeFromData( 0, null, buffer, 256, null, 0, out mimetype, 0 );
System.IntPtr mimeTypePtr = new IntPtr( mimetype );
string mime = Marshal.PtrToStringUni( mimeTypePtr );
Marshal.FreeCoTaskMem( mimeTypePtr );
return mime;
}
catch ( Exception )
{
return "unknown/unknown";
}
}

[DllImport( @"urlmon.dll", CharSet = CharSet.Auto )]
private extern static System.UInt32 FindMimeFromData(
System.UInt32 pBC,
[MarshalAs( UnmanagedType.LPStr )] System.String pwzUrl,
[MarshalAs( UnmanagedType.LPArray )] byte[] pBuffer,
System.UInt32 cbSize,
[MarshalAs( UnmanagedType.LPStr )] System.String pwzMimeProposed,
System.UInt32 dwMimeFlags,
out System.UInt32 ppwzMimeOut,
System.UInt32 dwReserverd
);
// /mime-type stuff

// hash stuff
public static string GetSha1Base64( this FileInfo fi, long maxBufSize )
{
return Convert.ToBase64String( fi.GetSha1( maxBufSize ) );
}

public static string GetSha1Hex( this FileInfo fi, long maxBufSize )
{
byte[] hash = fi.GetSha1(maxBufSize);
StringBuilder hex = new StringBuilder( hash.Length );
for ( int i = 0; i < hash.Length; i++ )
{
hex.Append( hash[i].ToString( "X2" ) );
}
return hex.ToString();
}

public static byte[] GetSha1( this FileInfo fi, long maxBufSize )
{
string ret = String.Empty;

if ( 0 == fi.Length )
return null;

if( 0 == maxBufSize )
{
maxBufSize = fi.Length;
}
byte[] buffer = fi.GetFileBytes( maxBufSize );

SHA1Managed sha1 = new SHA1Managed();
return sha1.ComputeHash( buffer );
}
}
}

No comments:

Post a Comment