Recuperare estensione file da byte array

lunedì 13 gennaio 2014 - 17.15
Tag Elenco Tags  C#  |  .NET 3.5  |  Visual Studio 2008

volperubbia Profilo | Senior Member

Ciao a tutti,
devo creare un metodo per un web service che faccia l'upload di un file sul server, da quello che ho capito bisogna usare un paramatro di tipo byte[]. Fin qui tutto ok, l'upload va a buon fine. Ora vorrei limitare la possibilità di upload a solo determinati tipi di file, ad esempio jpg, pdf ... ovvero "desumere" dal byte[] l'estensione del file. Quindi da codice impostare nome del file e concatenarci l'estensione recuperata.

Ho provato nel seguente modo:

public class MiaClasse
{
private static readonly byte[] BMP = { 66, 77 };
private static readonly byte[] DOC = { 208, 207, 17, 224, 161, 177, 26, 225 };
private static readonly byte[] GIF = { 71, 73, 70, 56 };
private static readonly byte[] ICO = { 0, 0, 1, 0 };
private static readonly byte[] JPG = { 255, 216, 255 };
private static readonly byte[] MP3 = { 255, 251, 48 };
private static readonly byte[] OGG = { 79, 103, 103, 83, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0 };
private static readonly byte[] PDF = { 37, 80, 68, 70, 45, 49, 46 };
private static readonly byte[] PNG = { 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82 };
private static readonly byte[] RAR = { 82, 97, 114, 33, 26, 7, 0 };
private static readonly byte[] SWF = { 70, 87, 83 };
private static readonly byte[] TIFF = { 73, 73, 42, 0 };
private static readonly byte[] TORRENT = { 100, 56, 58, 97, 110, 110, 111, 117, 110, 99, 101 };
private static readonly byte[] TTF = { 0, 1, 0, 0, 0 };
private static readonly byte[] EXE_DLL = { 77, 90 };
private static readonly byte[] WAV_AVI = { 82, 73, 70, 70 };
private static readonly byte[] WMV_WMA = { 48, 38, 178, 117, 142, 102, 207, 17, 166, 217, 0, 170, 0, 98, 206, 108 };
private static readonly byte[] ZIP_DOCX = { 80, 75, 3, 4 };

public static string GetFileExtension(byte[] file) {
string extension = null;
if (file.Take(2).SequenceEqual(BMP)) {
extension = "bmp";
} else if (file.Take(8).SequenceEqual(DOC)) {
extension = "doc";
} else if (file.Take(2).SequenceEqual(EXE_DLL)) {
// COME DIFFERENZIARE?
} else if (file.Take(4).SequenceEqual(GIF)) {
extension = "gif";
} else if (file.Take(4).SequenceEqual(ICO)) {
extension = "ico";
} else if (file.Take(3).SequenceEqual(JPG)) {
extension = "jpg";
} else if (file.Take(3).SequenceEqual(MP3)) {
extension = "mp3";
} else if (file.Take(14).SequenceEqual(OGG)) {
extension = "ogg";
} else if (file.Take(7).SequenceEqual(PDF)) {
extension = "pdf";
} else if (file.Take(16).SequenceEqual(PNG)) {
extension = "png";
} else if (file.Take(7).SequenceEqual(RAR)) {
extension = "rar";
} else if (file.Take(3).SequenceEqual(SWF)) {
extension = "swf";
} else if (file.Take(4).SequenceEqual(TIFF)) {
extension = "tiff";
} else if (file.Take(11).SequenceEqual(TORRENT)) {
extension = "torrent";
} else if (file.Take(5).SequenceEqual(TTF)) {
extension = "ttf";
} else if (file.Take(4).SequenceEqual(WAV_AVI)) {
// COME DIFFERENZIARE?
} else if (file.Take(16).SequenceEqual(WMV_WMA)) {
// COME DIFFERENZIARE?
} else if (file.Take(4).SequenceEqual(ZIP_DOCX)) {
// COME DIFFERENZIARE?
};
return extension;
}
}

Anche questo funziona, ma non so come differenziare txt, zip, ... Qualche idea? Esistono altri modi per gestire l'upload via ws?

Grazie per l'attenzione,
Davide

0v3rCl0ck Profilo | Guru

esiste una funzione di sistema FindMimeFromData che è capace di trovare 26 tipi di file sniffando dai prima 256 bytes, con il compromesso di utilizzare un po' di unmanaged code:

http://msdn.microsoft.com/en-us/library/ms775147%28VS.85%29.aspx#Known_MimeTypes

using System.Runtime.InteropServices; [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 ); // leggi nel buffer i primi 256 byte del file 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);

altrimenti, per gli zip dalla wiki ho letto "when a .ZIP file is viewed in a text editor the first two bytes of the file are usually "PK"" http://en.wikipedia.org/wiki/Zip_(file_format) sezione struttura, subito dopo c'è la tabella dell'header dove dice che i primi 4 bytes dovrebbero essere 0x04034b50. Io aprendo qualche zip di fatto mi ritrovo con "PK" all'inizio, sicuramente il metodo FindMimeFromData sarà più accurato ma non ne conosco il codice.

comunque un possibile codice (preso da http://stackoverflow.com/questions/11996299/c-net-identify-zip-file) basandosi sull'header della wiki pyò essere così:

abstract class Expander { private const int ZIP_LEAD_BYTES = 0x04034b50; private const ushort GZIP_LEAD_BYTES = 0x8b1f; public abstract MemoryStream Expand(Stream stream); internal static bool IsPkZipCompressedData(byte[] data) { Debug.Assert(data != null && data.Length >= 4); // if the first 4 bytes of the array are the ZIP signature then it is compressed data return (BitConverter.ToInt32(data, 0) == ZIP_LEAD_BYTES); } internal static bool IsGZipCompressedData(byte[] data) { Debug.Assert(data != null && data.Length >= 2); // if the first 2 bytes of the array are theG ZIP signature then it is compressed data; return (BitConverter.ToUInt16(data, 0) == GZIP_LEAD_BYTES); } public static bool IsCompressedData(byte[] data) { return IsPkZipCompressedData(data) || IsGZipCompressedData(data); } public static Expander GetExpander(Stream stream) { Debug.Assert(stream != null); Debug.Assert(stream.CanSeek); stream.Seek(0, 0); try { byte[] bytes = new byte[4]; stream.Read(bytes, 0, 4); if (IsGZipCompressedData(bytes)) return new GZipExpander(); if (IsPkZipCompressedData(bytes)) return new ZipExpander(); return new NullExpander(); } finally { stream.Seek(0, 0); // set the stream back to the begining } } }

poi è anche vero che dalla stessa wiki si legge: "Tools that correctly read .ZIP archives must scan for the end of central directory record signature, and then, as appropriate, the other, indicated, central directory records." quindi spostarsi in fondo al file e controllare se esiste questo central directory signature, quindi diciamo per l'header non è un metodo completamente affidabile, ma molto probabilmente ti può bastare come basta a windows internet explorer (dato che controlla solo i primi 256 byte).

altre info sugli zip: http://petlibrary.tripod.com/ZIP.HTM


ciao,
Michael Denny
Software Developer & Architect
http://blogs.dotnethell.it/Regulator/
http://dennymichael.wordpress.com
Twitter: @dennymic
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2025
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5