2010-11-14 71 views
2

我有一个网站,我让会员可以上传照片。在MVC控制器中,我将FormCollection作为Action的参数。然后我读取第一个文件,类型为HttpPostedFileBase。我用它来生成缩略图。这一切工作正常。System.IO.Stream赞成HttpPostedFileBase

除了让会员上传自己的照片,我想用System.Net.WebClient导入照片自己。

我想概括处理上传的照片(文件),以便它可以采取一般的流对象,而不是具体的HttpPostedFileBase的方法。

我想因为HttpPostedFileBase立足事事休流的具有包含该文件流的InputStream属性和WebClient有一个OpenRead方法,返回流。

但是,通过与流在HttpPostedFileBase,看起来像我丢失ContentTypeContentLength属性,我用于验证该文件。

之前没有使用二进制流,有没有办法从Stream中获取ContentTypeContentLength?或者有没有办法使用Stream创建一个HttpPostedFileBase对象?

回答

3

你说得对看它从原始流的角度,因为你可以创建一个处理流,因此很多情况下他们所来自的一种方法。

在文件上传的情况下,你获取流是从内容类型一个单独的属性。有时magic numbersalso a great source here)可以被用来检测由流头字节的数据类型,但由于该数据是通过其他途径已经提供给你(这可能是矫枉过正,即Content-Type头,或.EXT文件扩展名等)。

可以仅仅凭借阅读它测量流的字节长度,所以你并不真正需要的Content-Length头:浏览器只是发现它有用事先知道会发生什么大小的文件。

如果您WebClient的在互联网上访问资源URI,它会知道文件扩展名状http://www.example.com/imagegif,这可以是一个很好的文件类型标识符。

由于文件资料已经提供给你,为什么不开多一个论点上的自定义处理方法接受类似的内容类型的字符串标识符:

public static class Custom { 

    // Works with a stream from any source and a content type string indentifier. 

    static public void SavePicture(Stream inStream, string contentIdentifer) { 

     // Parse and recognize contentIdentifer to know the kind of file. 
     // Read the bytes of the file in the stream (while counting them). 
     // Write the bytes to wherever the destination is (e.g. disk) 

     // Example: 

     long totalBytesSeen = 0L; 

     byte[] bytes = new byte[1024]; //1K buffer to store bytes. 
     // Read one chunk of bytes at a time. 

     do 
     { 
      int num = inStream.Read(bytes, 0, 1024); // read up to 1024 bytes 

      // No bytes read means end of file. 
      if (num == 0) 
       break; // good bye 

      totalBytesSeen += num; //Actual length is accumulating. 

      /* Can check for "magic number" here, while reading this stream 
      * in the case the file extension or content-type cannot be trusted. 
      */ 

      /* Write logic here to write the byte buffer to 
      * disk or do what you want with them. 
      */ 

     } while (true); 

    } 

} 

一些有用的文件名解析功能在IO命名空间:

using System.IO; 

使用您自定义的方法在你所提到的,像这样的场景:

HttpPostedFileBase实例名为myPostedFile

Custom.SavePicture(myPostedFile.InputStream, myPostedFile.ContentType); 

当使用webClient1一个WebClient的实例名为:

var imageFilename = "pic.gif"; 
var stream = webClient1.DownloadFile("http://www.example.com/images/", imageFilename) 
//... 
Custom.SavePicture(stream, Path.GetExtension(imageFilename)); 

或处理从磁盘上的文件,即使:

Custom.SavePicture(File.Open(pathToFile), Path.GetExtension(pathToFile)); 

调用相同的自定义方法适用于任何可以匹配内容标识符的流并承认。

+0

我试图远离检查文件扩展名,因为它很容易伪造。但是,看起来不是另一种方式。谢谢! – 2010-11-14 06:53:45

+0

如果您不相信文件扩展名或它不存在,您可以始终使用幻数。以同样的方式,您不一定信任浏览器标题的内容类型。这里的文件sigs的示例http://en.wikipedia.org/wiki/List_of_file_signatures – 2010-11-14 06:56:02

+0

我刚刚将这个幻数表添加到答案中 - 它看起来相当全面:http://www.garykessler.net/library/file_sigs html的 – 2010-11-14 07:01:41