2009-10-31 4 views
12

파일을 업로드하고 스트림에 저장하는 방법이 있습니까?이 스트림에서 세션에 임시 저장하고 마지막으로이 세션에있는 업로드 된 파일을 미리 봅니다.C#을 사용하여 추가 미리보기를 위해 파일을 업로드하고 스트림에 저장하려면 어떻게해야합니까?

예를 들어, pdf 파일.

감사합니다.

HttpPostedFileBase hpf = Request.Files[0] as HttpPostedFileBase; 
byte[] buffer = new byte[hpf.InputStream.Length]; 
MemoryStream ms = new MemoryStream(buffer); 
ms.Read(buffer, 0, (int)ms.Length); 
Session["pdf"] = ms.ToArray(); 
ms.Close(); 

을 그리고 다른 방법으로, 나는이 일을 해요 : 수정 됨

는 여기에 내가 할 노력하고있어 무엇

byte[] imageByte = null; 

imageByte = (byte[])Session["pdf"]; 

Response.ContentType = "application/pdf"; 
Response.Buffer = true; 
Response.Clear(); 
Response.BinaryWrite(imageByte); 

그러나 아무것도 happends 없습니다 .. 내 브라우저는 pdf 파일을 보여주기 위해 nem 페이지를 열지 만 파일이 pdf가 아님을 나타내는 창이 표시됩니다 (또는 파일이 pdf로 시작하지 않으면 이해가되지 않았다)

+0

그 아래에있는 내 예를 참조가 바이트를 기록 배열을 FileResult로 설정합니다. aspnet mvc를 사용하고 있기 때문에 Response.BinaryWrite보다 안전합니다. 또한 더 나은 스트림 리더 (아래 편집 참조)를 사용하고 코드를 단계별로 실행하여 업로드 된 파일이 실제로 세션에 버려지는지 확인하십시오. ;) –

+1

코드의 주요 문제점은 입력 스트림에서 전혀 읽지 않는다는 것입니다. 올바른 크기의 버퍼를 만들고 있지만 빈 메모리 스트림에서 입력 스트림 대신 버퍼로 읽습니다. 당신이 얻는 것은 분명히 0으로 가득 찬 배열 일뿐입니다. 분명히 PDF 파일로 작동하지 않습니다. – Guffa

답변

15

확실히입니다. 내 app 내 db에 파일 (PDF/이미지)를 업로드합니다. 내 모델 개체는 실제로 파일을 바이트 배열로 저장하지만 스트림 형식으로 유지하기 쉽도록 스트림간에 변환해야하는 다른 함수에 대해서도 마찬가지입니다.

public class File : CustomValidation, IModelBusinessObject 
{ 
    public int ID { get; set; } 
    public string MimeType { get; set; } 
    public byte[] Data { get; set; } 
    public int Length { get; set; } 
    public string MD5Hash { get; set; } 
    public string UploadFileName { get; set; } 
} 

용맹 한 PdfDoc 종류 : 여기

내가 주위에 파일 (PDF 파일/이미지)를 이동하는 데 사용할 내 APP-

File 개체에서 일부 코드 예제 (N 붙여 복사)입니다

public class PdfDoc : File 
{ 
    public int ID { get; set; } 
    public int FileID 
    { 
     get { return base.ID; } 
     set { base.ID = value; } 
    } 
    [StringLength(200, ErrorMessage = "The Link Text must not be longer than 200 characters")] 
    public string LinkText { get; set; } 


    public PdfDoc() { } 

    public PdfDoc(File file) 
    { 
     MimeType = file.MimeType; 
     Data = file.Data; 
     Length = file.Length; 
     MD5Hash = file.MD5Hash; 
     UploadFileName = file.UploadFileName; 
    } 

    public PdfDoc(File file, string linkText) 
    { 
     MimeType = file.MimeType; 
     Data = file.Data; 
     Length = file.Length; 
     MD5Hash = file.MD5Hash; 
     UploadFileName = file.UploadFileName; 

     LinkText = linkText; 
    } 
} 

.. 파일 업로드에 대한 여러 부분 POST를 수신 동작의 예 :

특히 PDF 파일
// 
    // POST: /Announcements/UploadPdfToAnnouncement/ID 
    [KsisAuthorize(Roles = "Admin, Announcements")] 
    [AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult UploadPdfToAnnouncement(int ID) 
    { 
     FileManagerController.FileUploadResultDTO files = 
      FileManagerController.GetFilesFromRequest((HttpContextWrapper)HttpContext); 
     if (String.IsNullOrEmpty(files.ErrorMessage) && files.TotalBytes > 0) 
     { 
      // add SINGLE file to the announcement 
      try 
      { 
       this._svc.AddAnnouncementPdfDoc(
        this._svc.GetAnnouncementByID(ID), 
        new PdfDoc(files.Files[0]), 
        new User() { UserName = User.Identity.Name }); 
      } 
      catch (ServiceExceptions.KsisServiceException ex) 
      { 
       // only handle our exceptions 
       base.AddErrorMessageLine(ex.Message); 
      } 
     } 

     // redirect back to detail page 
     return RedirectToAction("Detail", "Announcements", new { id = ID }); 
    } 

이제 서비스 개체를 내 서비스에 전달할 수 있지만 세션에 추가하고 ID를 '미리보기'보기로 다시 전달하도록 선택할 수 있습니다.

// 
    // GET: /FileManager/GetFile/ID 
    [OutputCache(Order = 2, Duration = 600, VaryByParam = "ID")] 
    public ActionResult GetFile(int ID) 
    { 
     FileService svc = ObjectFactory.GetInstance<FileService>(); 

     KsisOnline.Data.File result = svc.GetFileByID(ID); 

     return File(result.Data, result.MimeType, result.UploadFileName); 
    } 

편집 :
내가 마지막으로

, 여기에 (당신이 파일 세션에서/스트림을 렌더링 비슷한 가질 수) 내가 클라이언트에 파일을 렌더링하는 데 사용하는 일반적인 작업입니다

public class FileUploadResultDTO 
    { 
     public List<File> Files { get; set; } 
     public Int32 TotalBytes { get; set; } 
     public string ErrorMessage { get; set; } 
    } 
: 나는 FileUploadResultDTO 클래스 위의 업로드 작업에 대한 전술

을 설명하기 위해 더 많은 샘플을 필요 눈치

그리고 GetFilesFromRequest 기능 :

public static FileUploadResultDTO GetFilesFromRequest(HttpContextWrapper contextWrapper) 
    { 
     FileUploadResultDTO result = new FileUploadResultDTO(); 
     result.Files = new List<File>(); 

     foreach (string file in contextWrapper.Request.Files) 
     { 
      HttpPostedFileBase hpf = contextWrapper.Request.Files[file] as HttpPostedFileBase; 
      if (hpf.ContentLength > 0) 
      { 
       File tempFile = new File() 
       { 
        UploadFileName = Regex.Match(hpf.FileName, @"(/|\\)?(?<fileName>[^(/|\\)]+)$").Groups["fileName"].ToString(), // to trim off whole path from browsers like IE 
        MimeType = hpf.ContentType, 
        Data = FileService.ReadFully(hpf.InputStream, 0), 
        Length = (int)hpf.InputStream.Length 
       }; 
       result.Files.Add(tempFile); 
       result.TotalBytes += tempFile.Length; 
      } 
     } 

     return result; 
    } 

그리고 마지막으로이 ReadFully 기능 (나는 당신이 지금 필요로하는 모든 것을 갖추고 바랍니다). 내 디자인이 아니야. 나는 인터넷에서 그것을 얻었다 - 독서는 까다로울 수있다.나는이 기능을 완전히 스트림을 읽을 수있는 가장 성공적인 방법입니다 찾을 :

/// <summary> 
    /// Reads data from a stream until the end is reached. The 
    /// data is returned as a byte array. An IOException is 
    /// thrown if any of the underlying IO calls fail. 
    /// </summary> 
    /// <param name="stream">The stream to read data from</param> 
    /// <param name="initialLength">The initial buffer length</param> 
    public static byte[] ReadFully(System.IO.Stream stream, long initialLength) 
    { 
     // reset pointer just in case 
     stream.Seek(0, System.IO.SeekOrigin.Begin); 

     // If we've been passed an unhelpful initial length, just 
     // use 32K. 
     if (initialLength < 1) 
     { 
      initialLength = 32768; 
     } 

     byte[] buffer = new byte[initialLength]; 
     int read = 0; 

     int chunk; 
     while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0) 
     { 
      read += chunk; 

      // If we've reached the end of our buffer, check to see if there's 
      // any more information 
      if (read == buffer.Length) 
      { 
       int nextByte = stream.ReadByte(); 

       // End of stream? If so, we're done 
       if (nextByte == -1) 
       { 
        return buffer; 
       } 

       // Nope. Resize the buffer, put in the byte we've just 
       // read, and continue 
       byte[] newBuffer = new byte[buffer.Length * 2]; 
       Array.Copy(buffer, newBuffer, buffer.Length); 
       newBuffer[read] = (byte)nextByte; 
       buffer = newBuffer; 
       read++; 
      } 
     } 
     // Buffer is now too big. Shrink it. 
     byte[] ret = new byte[read]; 
     Array.Copy(buffer, ret, read); 
     return ret; 
    } 
+0

내 질문을 편집했습니다. 보세요! :-) – AndreMiranda

+0

Thaaaaaanks 많이 cottsak! 그것은 일했다!! :-) 그리고 나는 또한 MVC가되도록 File을 결과로 변경했습니다! -) – AndreMiranda

+0

@AndreMiranda : hi 5 ;-) –

2

네,하지만 당신은 스트림에 저장할 수 없습니다. 스트림에는 데이터가 포함되어 있지 않으며 실제 저장소에 액세스하기위한 수단 일뿐입니다.

데이터를 바이트 배열로 가져온 다음 세션 변수에 저장하고 파일로 저장 한 다음 응답으로 보낼 수 있습니다.

바이트 배열로 입력 스트림에서 데이터를 얻을 수있는 BinaryReader를 사용 :

byte[] data; 
using (BinaryReader reader = new BinaryReader(uploadedFile.InputStream)) { 
    data = reader.ReadBytes((int) uploadedFile.InputStream.Length); 
} 

(편집합니다 BinaryReader를에 위해 StreamReader에서 변경)

+0

ReadToEnd()가 문자열을 반환하기 때문에 data = reader.ReadToEnd()가 작동하지 않습니다. – AndreMiranda

+0

@AndreMiranda : 위의 편집을 참조하십시오. 스트림 읽기가 까다로울 수 있습니다. –

+0

@AndreMiranda : 네, 맞습니다. 그냥 StreamReader 대신 BinaryReader를 사용하십시오. 위의 편집을 참조하십시오. – Guffa

관련 문제