使用kbmmw 的REST 服务实现上传大文件
我们在使用kbmmw的REST 服务时,经常会下载和上传大文件。例如100M以上的。kbmmw的rest服务中
提供标准的文件下载,上传功能,基本上就是打开文件,发送,接收,没有做特殊处理。这些对于文件比较小的
时候,问题不大,但是如果文件比较大,就会占用大量的服务器内存,导致服务器出现问题或者不响应。
为了解决这个问题,我们需要对文件上传、下载做特殊处理。以便节省服务器端的内存。
由于下载大文件有其他的一些方法,例如可以单独建立一个iis,apache,nginx等,或者可以利用httpsys 的静态文件
下载功能(以后有机会的话,我来讲一下)。
今天来实现以下大文件上传的方法,(当然,你也可以参照这个做一个大文件下载的功能)。主要思路是按照kbmmw 本身的
文件服务原理,把大文件切成小块,然后再上传。
首先在服务器端做一个上传文件服务。
[kbmMW_Rest('method:post, path:uploadfile,anonymousResult:False,freeResult:true')]
[kbmMW_Method]
function uploadfile(
[kbmMW_Rest('value: "$filepath", required: true')] const filepath:string;
[kbmMW_Rest('value: "$token", required: true')] const token:string;
[kbmMW_Rest('value: "$position", required: true')] const position:string;
[kbmMW_Rest('value: "$size", required: true')] const size:string;
[kbmMW_Rest('value: "$final", required: true')] const final:string):string;
function TkbmMWCustomHTTPSmartService1.uploadfile(const filepath, token,
position, size, final: string): string;
const
UPLOADPATH='d:\upload\';
MaxFileSize=**; //上传文件大小不能超过200M
errmsg='ERROR:';
var
fa:TkbmMWFileAccessPermissions;
h:THandle;
FileToken:integer;
path:string;
p:Pbyte;
// l:integer;
ref:TkbmMWFileReference;
fofs,sz,newofs,maxsize:int64;
bGC:boolean;
FFinal:boolean;
begin
if not Assigned(FilePool) then
begin
result:=errmsg+'No FilePool defined.';
exit;
end; if filepath='' then
begin
result:=errmsg+'No filepath.';
exit;
end;
if token='' then
begin
result:=errmsg+'No token.';
exit;
end; if position='' then
begin
result:=errmsg+'No position.';
exit;
end; fofs:=strtoint(position); if size='' then
begin
result:=errmsg+'No size.';
exit;
end; sz:=strtoint(size); if sz>** then
begin
result:=errmsg+'blocksize too big.';
exit;
end; if ((final<>'') and (final<>'')) then
begin
result:=errmsg+'final error.';
exit;
end; if final='' then
ffinal:=False
else
ffinal:=True; FileToken:=strtoint(token); path:= UPLOADPATH+filepath;
// Determine file mode.
if FileToken=- then
begin
// Check if file already exists and not overwrite permissions.
if FileExists(path) and (not (mwfapOverwrite in fa)) then
begin
result:=errmsg+'Permission denied';
exit;
end;
end; // Append block to file.
bGC:=false;
ref:=FilePool.Access(path,mwfamOpenWrite,FileToken,h);
try
ref.DuringUpdate:=true; maxsize:=MaxFileSize;
if FOfs>= then
begin
if (maxsize>) and (FOfs+sz>maxSize) then
begin
result:=errmsg+'File too big';
exit;
end; if FileSeek(h,FOfs,)< then
begin
result:=errmsg+'Cant position in file';
exit; end;
end
else
begin
newofs:=FileSeek(h,,);
if newofs< then
begin
result:=errmsg+'Cant append to file';
exit;
end; if (maxsize>) and (newofs+sz>maxSize) then
begin
result:=errmsg+'File too big';
exit;
end;
end; // Write requeststream to file.
p:=RequestStream.Memory;
if FileWrite(h,p^,sz)<>sz then
begin
ref.Invalidate; ref.DeleteOnGC:=true;
bGC:=true; result:=errmsg+'写文件失败.';
exit;
end;
finally
if FFinal then
ref.DuringUpdate:=false;
FilePool.ReleaseAccess(ref,h,FFinal);
if bGC then
FilePool.GarbageCollect;
end;
Result:=FileToken.ToString ; end;
编译运行即可。
客户端我们就直接增加一个上传过程。
procedure TForm1.Button3Click(Sender: TObject);
const
FBlockSize=**; baseurl='http://127.0.0.1/xalionrest';
basepath='d:\';
var
HttpClient:TNetHTTPClient;
requrl:string;
filetoken:string;
resp:IHTTPResponse;
final:string;
terminate:boolean;
Stream:TFileStream;
fm:integer;
position,sz:string;
pct:integer;
RequestStream:Tmemorystream;
LocalPath,filename:string;
n,bs,ofs:integer; begin filename:= 'delphi5.rar';
localpath:=basepath+filename; fm:=fmOpenRead+fmShareDenyWrite;
Stream:=TFileStream.Create(LocalPath,fm); HttpClient:= TNetHTTPClient.create(nil); RequestStream:= Tmemorystream.Create; filetoken:='-1';
final:='';
try
while true do
begin
if Stream.Size= then
pct:=
else
pct:=trunc((Stream.Position / Stream.Size) * ); position:=Stream.Position.ToString;
sz:=Stream.Size.ToString; RequestStream.Clear;
n:=FBlockSize;
ofs:=Stream.Position;
bs:=Stream.Size-ofs;
if bs<= then break;
if bs<=n then
begin
n:=bs;
final:='';
end;
RequestStream.CopyFrom(Stream,n); RequestStream.Position:=;
try requrl:= baseurl+'/uploadfile?'+'filepath='+filename+'&token='+filetoken+'&position='+position+'&size='+n.ToString+'&final='+final;
resp:=httpclient.Post(requrl,RequestStream);//
filetoken:=resp.ContentAsString(); if pos('ERROR:',filetoken)> then
begin
showmessage(filetoken);
exit; end; except
showmessage('上传失败!');
exit;
end; if n<FBlockSize then
break; end; showmessage('上传成功!'); finally Stream.Free; HttpClient.Free; RequestStream.free;
end; end;
运行起来。
我们看看服务器端的内存占用。
你可以看见服务的内存增长了,但是远远小于文件的大小。
使用kbmmw 的REST 服务实现上传大文件的更多相关文章
- IIS7下swfupload上传大文件出现404错误
要求上传附件大小限制在2G,原本以为可以轻松搞定.在编译模式下可以上传大文件,可是在IIS7下(自己架的服务器),一上传大的文件就会出现 Http 404错误,偶尔有的文件还有IO. error错误. ...
- tp5+layui 实现上传大文件
前言: 之前所写的文件上传类通常进行考虑的是文件的类型.大小是否符合要求条件.当上传大文件时就要考虑到php的配置和服务器的配置问题.之前简单的觉得只要将php.ini中的表单上传的 大小,单脚本执行 ...
- tornado上传大文件以及多文件上传
tornado上传大文件问题解决方法 tornado默认上传限制为低于100M,但是由于需要上传大文件需求,网上很多说是用nginx,但我懒,同时不想在搞一个服务了. 解决方法: server = H ...
- HTTP上传大文件的注意点
使用HttpWebRequest上传大文件时,服务端配置中需要进行以下节点配置: <system.web> <compilation debug="true" t ...
- asp.net core流式上传大文件
asp.net core流式上传大文件 首先需要明确一点就是使用流式上传和使用IFormFile在效率上没有太大的差异,IFormFile的缺点主要是客户端上传过来的文件首先会缓存在服务器内存中,任何 ...
- vue上传大文件的解决方案
众所皆知,web上传大文件,一直是一个痛.上传文件大小限制,页面响应时间超时.这些都是web开发所必须直面的. 本文给出的解决方案是:前端实现数据流分片长传,后面接收完毕后合并文件的思路. 实现文件夹 ...
- Web上传大文件的解决方案
需求:项目要支持大文件上传功能,经过讨论,初步将文件上传大小控制在500M内,因此自己需要在项目中进行文件上传部分的调整和配置,自己将大小都以501M来进行限制. 第一步: 前端修改 由于项目使用的是 ...
- JS上传大文件的解决方案
最近遇见一个需要上传百兆大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现. 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表 ...
- java上传大文件解决方案
需求:项目要支持大文件上传功能,经过讨论,初步将文件上传大小控制在10G内,因此自己需要在项目中进行文件上传部分的调整和配置,自己将大小都以10G来进行限制. 第一步: 前端修改 由于项目使用的是BJ ...
随机推荐
- js常用身份校验规则
js常用身份校验规则 var Validator = { extractBirth: function(id) { // 身份证提取出生年月 var re = null, split, year, m ...
- 接口--Comparable接口【哈夫曼树】
我们在字符串中见到过CompareTo方法,知道这个方法是用于比较字符串顺序的,根据字典顺序进行排序.Java中很多类也都有CompareTo方法,甚至于排序算法的底层组成也是依赖于比较的,而这个比较 ...
- 基于MPI的大规模矩阵乘法问题
转载请注明出处. /* Function:C++实现并行矩阵乘法; Time: 19/03/25; Writer:ZhiHong Cc; */ 运行方法:切到工程文件x64\Debug文件下,打开命令 ...
- 【396】python 递归练习题(COMP9021)
Merging two strings into a third one Say that two strings s1 and s2 can be merged into a third strin ...
- 1804.03235-Large scale distributed neural network training through online distillation.md
现有分布式模型训练的模式 分布式SGD 并行SGD: 大规模训练中,一次的最长时间取决于最慢的机器 异步SGD: 不同步的数据,有可能导致权重更新向着未知方向 并行多模型 :多个集群训练不同的模型,再 ...
- Task的在主线程处理异常信息的Helper类
最近使用task时候需要把异常记录日志,直接注入非单例模式的实例进入异步线程,在高并发情况下会出现一些问题. 所以需要把异常反馈给主线程 ,并且不在主线程里进行等待,研究相关资料后,自己写了一个简单的 ...
- tensorflow 升级到1.9-rc0,tensorboard 报错:TypeError: GetNext() takes exactly 1 argument (2 given)
Exception in thread Reloader:Traceback (most recent call last): File "/usr/lib/python2.7/threa ...
- 云笔记项目-Spring事务学习-传播NOT_SUPPORTED
接下来测试事务传播属性设置为NOT_SUPPORTED Service层 Service层主要设置如下,其中还插入了REQUIRED作为比较. package Service; import java ...
- 解题(DirGraCheckPath--有向图的遍历(深度搜索))
题目描述 对于一个有向图,请实现一个算法,找出两点之间是否存在一条路径. 给定图中的两个结点的指针DirectedGraphNode* a, DirectedGraphNode* b(请不要在意数据类 ...
- Python学习—基础篇之常用模块
常用模块 模块,用一砣代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合.而对于一个复杂的功能来,可能需要 ...