2009-10-31 11 views
12

Czy istnieje sposób na przesłanie pliku, zapisanie go w strumieniu, ten strumień, który go tymczasowo zapisuję w sesji, a na koniec spróbuję wyświetlić podgląd tego przesłanego pliku, który znajduje się w tej sesji?Jak mogę przesłać plik i zapisać go w strumieniu, aby uzyskać jego podgląd za pomocą C#?

Na przykład plik pdf.

Dzięki!

EDITED

Oto, co usiłuję zrobić:

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(); 

A w inny sposób, to robię:

byte[] imageByte = null; 

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

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

Ale nic happends .. Moja przeglądarka otwiera nawet stronę nem, aby wyświetlić plik PDF, ale wyświetlane jest okno informujące, że plik nie jest plikiem pdf (lub czymś takim, jak plik nie inicjuje z pdf, I tego nie rozumiem)

+0

Patrz moim przykładzie poniżej, która zapisuje bajt array jako FileResult. Jest bezpieczniejszy niż Response.BinaryWrite, ponieważ używasz aspneta mvc. Zastosuj także lepszy czytnik strumienia (zobacz moją edycję poniżej) i przejdź przez kod, aby sprawdzić, czy przesłany plik faktycznie został zrzucony w sesji. ;) –

+1

Głównym problemem z Twoim kodem jest to, że nigdy nie czytasz ze strumienia wejściowego. Tworzysz bufor o odpowiednim rozmiarze, ale czytasz z pustego strumienia pamięci do bufora zamiast ze strumienia wejściowego. Otrzymasz tylko tablicę pełną zer, która oczywiście nie działa jako plik PDF. – Guffa

Odpowiedz

15

Pewnie. Przesyłam pliki (PDF/obrazy) do mojej bazy danych w mojej app. Mój obiekt modelu faktycznie przechowuje plik jako tablicę bajtów, ale dla innych funkcji muszę konwertować do i ze strumieni, więc jestem pewien, że równie łatwo można go zachować w strumieniu.

Oto niektóre przykłady kodu (kopia n wklej) z mojego app-

Przedmiotem File że mogę używać, aby przenieść pliki (pliki PDF/images) wokół:

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; } 
} 

..the PdfDoc typ specjalnie dla plików PDF:

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; 
    } 
} 

.. przykładem działania, który odbiera wieloczęściowe POST do wysyłania pliku:

// 
    // 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 }); 
    } 

Teraz możesz zobaczyć, że przekazuję obiekt pliku do mojej usługi, ale możesz dodać go do sesji i przekazać identyfikator z powrotem do widoku podglądu.

Wreszcie, tutaj jest ogólnym działanie użyć do renderowania plików się do klienta (można mieć coś podobnego uczynić pliki/strumieniowych z sesji):

// 
    // 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); 
    } 

EDIT:
I zauważyłem, że potrzebuję więcej próbek wyjaśnić wyŜej

dla działania wysyłania powyżej, klasa FileUploadResultDTO:

public class FileUploadResultDTO 
    { 
     public List<File> Files { get; set; } 
     public Int32 TotalBytes { get; set; } 
     public string ErrorMessage { get; set; } 
    } 

A GetFilesFromRequest funkcja:

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; 
    } 

I wreszcie (mam nadzieję, że wszystko, czego potrzeba teraz) to ReadFully funkcyjny. To nie jest mój projekt. Mam to z sieci - czytanie strumienia może być trudne.Uważam, że ta funkcja jest najbardziej skutecznym sposobem na całkowite odczytanie strumienia:

/// <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

Edytowałem moje pytanie! Spójrz! :-) – AndreMiranda

+0

Thaaaaaaats dużo cottsak! Zadziałało!! :-) A ja zmieniłem również na Plik wynik, aby być więcej MVC! -) – AndreMiranda

+0

@AndreMiranda: hi 5 ;-) –

2

Tak, ale nie można zapisać go do strumienia. Strumień nie zawiera żadnych danych, jest tylko środkiem dostępu do faktycznego magazynu.

Pobierz dane w postaci tablicy bajtów, a następnie umieść w zmiennej sesji, zapisz ją jako plik i wyślij jako odpowiedź.

Użyj BinaryReader aby uzyskać dane ze strumienia wejściowego do tablicy bajtów:

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

(Edycja: Zmieniono z StreamReader do BinaryReader)

+0

dane = read.ReadToEnd() nie będzie działać, ponieważ ReadToEnd() zwraca ciąg znaków – AndreMiranda

+0

@AndreMiranda: odnieś się do mojej powyższej edycji. czytanie strumienia może być trudne –

+0

@AndreMiranda: Tak, masz rację. Po prostu użyj BinaryReadera zamiast StreamReadera. Zobacz moją edycję powyżej. – Guffa

Powiązane problemy