2012-01-17 27 views
8

Tôi đã viết phương thức máy chủ DataSnap trả về một đối tượng TStream để truyền tệp. Ứng dụng khách gọi phương thức và đọc luồng tốt. Vấn đề của tôi là cuộc gọi phương thức mất một thời gian để hoàn thành trước khi đối tượng TStream có sẵn để đọc, nhưng ở phía máy chủ tôi có thể thấy rằng cuộc gọi phương thức chỉ mất một giây để tạo đối tượng trả về. Tôi đã hy vọng đối tượng luồng sẽ được trả lại ngay lập tức để tôi có thể đọc luồng và hiển thị thanh tiến trình cho tiến trình tải xuống. Có cách nào khác tôi có thể làm điều này không?Delphi XE2 DataSnap - Tải tập tin qua TStream Với thanh tiến trình

Phương pháp máy chủ là rất đơn giản:

function TServerMethods.DespatchDocument(sCompanyID, sDocOurRef: string): TStream; 
var 
    sSourceFilePath: string; 
    strFileStream: TFileStream; 
begin 
    sSourceFilePath := GetDocumentPDFFilePath(sCompanyID, sDocOurRef); 

    strFileStream := TFileStream.Create(sSourceFilePath, fmOpenRead); 
    Result := strFileStream; 
end; 
+0

thể trùng lặp của [ProgressBar cho TResourceStream (Delphi)] (http: // stackoverflow. com/questions/6081841/progressbar-for-tresourcestream-delphi) – NGLN

Trả lời

2

Đây là cách tôi đã làm nó một thời gian trở lại. Tôi đã sử dụng XE và không có cơ hội để làm sạch nó.

// Server side:

function TServerMethods1.DownloadFile(out Size: Int64): TStream; 
begin 
    Result := TFileStream.Create('upload.fil', fmOpenRead or fmShareDenyNone); 
    Size := Result.Size; 

    Result.Position := 0; 
end; 

// Khách hàng bên:

procedure TfMain.DownloadFile(Sender: TObject); 
var 
    RetStream: TStream; 
    Buffer: PByte; 
    Mem: TMemoryStream; 
    BytesRead: Integer; 
    DocumentId: Int64; 
    Size: Int64; 
    filename: WideString; 
    BufSize: Integer; 
begin 
    BufSize := 1024; 

    try 
     Mem := TMemoryStream.Create; 
     GetMem(Buffer, BufSize); 

     try 
     RetStream := FDownloadDS.DownloadFile(Size); 
     RetStream.Position := 0; 

     if (Size <> 0) then 
     begin 
      filename := 'download.fil'; 

      repeat 
      BytesRead := RetStream.Read(Pointer(Buffer)^, BufSize); 

      if (BytesRead > 0) then 
      begin 
       Mem.WriteBuffer(Pointer(Buffer)^, BytesRead); 
      end; 

      lStatus.Caption := IntToStr(Mem.Size) + '/' + IntToStr(Size); 
      Application.ProcessMessages; 

      until (BytesRead < BufSize); 

      if (Size <> Mem.Size) then 
      begin 
      raise Exception.Create('Error downloading file...'); 
      end; 
     end 
     else 
     begin 
      lStatus.Caption := ''; 
     end; 
     finally 
     FreeMem(Buffer, BufSize); 
     FreeAndNIl(Mem); 
     end; 
    except 
     on E: Exception do 
     begin 
     lErrorMessage.Caption := PChar(E.ClassName + ': ' + E.Message); 
     end; 
    end; 
end; 

Bạn có thể điều chỉnh BufSize tuy nhiên bạn muốn. Tôi đã gặp sự cố khi nhận kích thước luồng cho đến khi tôi thực hiện theo cách này. Tôi đã thử nghiệm với XE2 và dường như không có vấn đề tương tự nhưng tôi đã tải lên. Có lẽ là cách tốt hơn để truy xuất kích thước của luồng. Nếu tôi nhận được câu trả lời sớm, tôi sẽ cho bạn biết ....

Lưu ý khác - Tôi chưa tìm ra cách hiển thị thanh tiến trình ở phía máy chủ. Tôi vẫn đang cố gắng tìm ra điều này.

Tôi hy vọng điều này sẽ hữu ích! Hãy cho tôi biết nếu bạn có bất kỳ câu hỏi!

+0

Không, tôi không có bất kỳ sự chậm trễ nào. Tôi đã tải xuống các tệp có đủ kích thước (tối đa 5 megabyte). Chỉ báo tiến độ hoạt động tốt. Tôi biết điều này nghe có vẻ kỳ lạ nhưng đôi khi tôi gặp rắc rối với cách DataSnap hoạt động trên một số cổng nhất định. Tôi đã đổi sang một cổng khác và mọi thứ hoạt động tốt. Thật không may, tôi không bao giờ có cơ hội để tìm ra lý do tại sao hoặc tôi sẽ nói với bạn. Kích thước tệp của bạn là bao nhiêu? Và những gì cao và thấp phạm vi có bạn đã cố gắng cho BufSize? – Tadpole

+0

Tệp tôi đang thử nghiệm chỉ dưới 5 megabyte. Tôi đã tạo ra cùng một phương pháp DataSnap như bạn có, và cuộc gọi phương thức mất khoảng 40 giây để hoàn thành trước khi khách hàng có thể đọc luồng với thanh tiến trình. Tôi hiện đang chỉ sử dụng cổng 8080 qua HTTP, sử dụng TDSRESTConnection để gọi phương thức DataSnap. Bạn đang kết nối với dịch vụ DataSnap như thế nào? –

+0

Tôi chưa có cơ hội nhìn vào khả năng REST của DataSnap. Tôi đang kết nối qua TCP bằng cách sử dụng cổng mặc định 211 và TSQLConnection của máy khách.Các ứng dụng tôi đã gặp rắc rối với tôi thiết lập cổng 9999 (và một ứng dụng khác đến 9998) và các vấn đề đã biến mất. Tôi nghĩ đó là cơ chế lọc của ISP của tôi. Một điều - Tôi đang sử dụng XE2 Update 3. Bạn đã có điều này? Bạn làm bất cứ điều gì với JSON? Tôi cũng phải sửa một vài thứ với nó nhưng tôi không thể hình dung nó ảnh hưởng đến việc tải xuống của bạn. Nếu bạn có một mẫu nhỏ, tôi sẽ xây dựng nó và xem tôi có cùng một vấn đề hay không. – Tadpole

0

Rất vui khi bạn có một số may mắn! Đây là bản sửa lỗi khác mà tôi phải làm. Bạn có thể tham khảo link này https://forums.embarcadero.com/thread.jspa?threadID=66490&tstart=0

Sau khi lặn trong mã tôi tìm thấy trong "Data.DBXJSONReflect.pas"

thủ tục TJSONPopulationCustomizer.PrePopulate (dữ liệu: TObject; rttiContext: TRttiContext); ...

3473: rttiField.GetValue(Data).AsObject.Free; 
3474: rttiField.SetValue(Data, TValue.Empty); 

...

Tôi nghĩ rằng nó phải như thế này:

3473: rttiField.SetValue(Data, TValue.Empty); 
3474: rttiField.GetValue(Data).AsObject.Free; 
Các vấn đề liên quan