文件上传的问题,wininet中的http协议(internetwritefile方法),高手请入,200大洋(200分)

  • 主题发起人 主题发起人 aq100
  • 开始时间 开始时间
A

aq100

Unregistered / Unconfirmed
GUEST, unregistred user!
程序通过客户端向WEB服务器端上传文件
比如把本地的文件dd.doc上传到WEB服务器的根目录temp下,Tinternet采用http协议方式
我在向远端写入文件时总是不成功internetwriterfile的结果为false;

下面是整体流程代码,望大拿指点




const
Buffsize = 1024;
var
HINTERNET : Pointer;
httpContext: Integer;
HttpServer,UserID,Passwd:String;
BufferIn:INTERNET_BUFFERS;

RemoteFile:String;
LocalFile:String;
httpFile:Thandle;


readInF:DWORD;
oBytesWritten:DWORD;

ReadOut:DWORD;
cRead, rRead:bool;

iStart, iCount, Count: DWORD;

begin
LocalFile:='c:/dd.doc';
RemoteFile:='//temp//dd.doc';
//创建以HTTP的协议连接方式
HttpNet := InternetOpen('127.0.0.1', INTERNET_OPEN_TYPE_PRECONFIG,nil,nil,0);
HttpConnect := InternetConnect(HttpNet, PChar(HttpServer), 0, PChar(UserID),
PChar(Passwd), INTERNET_SERVICE_HTTP, 0, httpContext);
//打开远端目录并设置传输数据
HttpRequest:= HttpOpenRequest (HttpConnect,'PUT',Pchar(RemoteFile),
nil, nil, nil, 0,0); //'GET'

//打开本地文件获得handle
httpFile := CreateFile(Pchar(LocalFile), GENERIC_READ, FILE_SHARE_READ,
nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0);
//文件大小
BufferIn.dwBufferTotal:= GetFileSize(httpFile, nil);
//发送请求写入的数据缓存大小
HttpSendRequestEx(HttpRequest, @BufferIn, nil, HSR_INITIATE, 0);

ReadInF:=0;
iCount := 1024;
repeat
//读本地文件
ReadFile(httpFile,pBuffer, iCount, Count,nil);
ReadInF:=ReadInF+Count;
//写到远端服务器
rRead:=InternetWriteFile(httpRequest,@pBuffer,Count,oBytesWritten);
//这里没有成功,疑点一是在连接服务器,设置读写文件等参数出错,疑点二是读本地文件数据写到远端服务器出错,可能还有其他的未知因数,请大拿指点。
if(rRead) then
showmessage('internetWriteFile success!');
until ReadInF=BufferIn.dwBufferTotal;


{
function InternetWriteFile(
hFile: HINTERNET;
lpBuffer: Pointer;
dwNumberOfBytesToWrite: DWORD;
var lpdwNumberOfBytesWritten: DWORD): BOOL; stdcall;

BOOL WriteFile(
HANDLE hFile, //写入文件句柄
LPCVOID lpBuffer, //写入数据指针
DWORD nNumberOfBytesToWrite, //要写入字节数量
LPDWORD lpNumberOfBytesWritten, //已写入字节数地址
LPOVERLAPPED lpOverlapped ); //异步I/O结构指针
}

CloseHandle (httpFile);
HttpEndRequest(HttpRequest, nil, 0, 0);
InternetCloseHandle(HttpRequest);
InternetCloseHandle(HttpConnect);
InternetCloseHandle(HttpNet);
end;
end;
end;
end;


备注,这里引用的是wininet单元,我只针对以http协议中的internetwriterfile方式进行上传,所以看管只需UP,俺就非常感谢了.

如果大家看不明白,我下次给你们VC的源码,我是看着它改的,只是不成功,如果大家需要,给个mail,我给你们发过去。
 
附加VC原代码


/*************************************************************************
函数名称: 内部函数:HttpUploadFile
函数功能: 通过http上传文件
输入参数:
TCHAR *pcsLocalFile : 上传文件名
VARIANT& vtPOSTerParas(SafeArray of VARIANTs) : 上传参数设置,包括:
1、vtHost
// no more needed 2、vtPostAcceptor
3、vtRemoteFile
4、vtProxy
5、vtSSL
6、vtUser
7、vtPassword
TO DOs for yt: many error handle code must be added for this func.
for every possible exit from this func we must close any
network connection and release any allocated resources.
输出参数: 无
函数作者:
创建日期: 2001年11月30日 22:15:11
修改日志:
*************************************************************************/
BOOL CX_OADocRenderDoc::HttpUploadFile(TCHAR *pcsLocalFile, VARIANT& vtPOSTerParas)
{
VARIANT* pvtArray = vtPOSTerParas.pvarVal;
long nIndex = -1;
_variant_t vtHost, vtPostAcceptor, vtRemoteFile, vtProxy, vtSSL, vtUser,vtPassword;

if ((nIndex++, FAILED(SafeArrayGetElement(pvtArray->parray, &nIndex, &vtHost))) ||
// (nIndex++, FAILED(SafeArrayGetElement(pvtArray->parray, &nIndex, &vtPostAcceptor))) ||
(nIndex++, FAILED(SafeArrayGetElement(pvtArray->parray, &nIndex, &vtRemoteFile))) ||
(nIndex++, FAILED(SafeArrayGetElement(pvtArray->parray, &nIndex, &vtProxy))) ||
(nIndex++, FAILED(SafeArrayGetElement(pvtArray->parray, &nIndex, &vtSSL))) ||
(nIndex++, FAILED(SafeArrayGetElement(pvtArray->parray, &nIndex, &vtUser))) ||
(nIndex++, FAILED(SafeArrayGetElement(pvtArray->parray, &nIndex, &vtPassword))))
{
RP_IDS_MESSAGE(IDS_CX_OADocRenderDoc_UploadFileToWebServer)
return FALSE;
}

HINTERNET hOpen, hConnect;

// here we didn't use any proxy, if needed, add it after it, ok?
if ( !(hOpen = InternetOpen("SCC Uploader", INTERNET_OPEN_TYPE_PRECONFIG, NULL, 0, 0)))
{
RP_MESSAGE("InternetOpen Failed")
return FALSE;
}
if ( !(hConnect = InternetConnect(hOpen,
(LPCTSTR)(_bstr_t)vtHost,
INTERNET_DEFAULT_HTTP_PORT,
(LPCTSTR)(_bstr_t)vtUser,
(LPCTSTR)(_bstr_t)vtPassword,
INTERNET_SERVICE_HTTP, 0, NULL) ))
{
RP_MESSAGE("InternetConnect Failed")
InternetCloseHandle(hOpen);
return FALSE;
}

INTERNET_BUFFERS BufferIn = {0};
DWORD dwBytesRead;
DWORD dwBytesWritten;
BYTE pBuffer[8192]; // Read from file in 1K chunks
BOOL bRead, bRet;

BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS );

_bstr_t bstrRemoteFile = vtRemoteFile;
bstrRemoteFile += _T("/");
bstrRemoteFile += (LPTSTR)(_tcsrchr(pcsLocalFile, _T('//')) + 1);

HINTERNET hRequest = HttpOpenRequest (hConnect,
_T("PUT"),
(LPCTSTR)bstrRemoteFile,
NULL, NULL, NULL, 0, 0);
if (!hRequest)
{
RP_TEMPMESSAGE("Failed to open request handle")
InternetCloseHandle(hConnect);
InternetCloseHandle(hOpen);
return FALSE;
}

HANDLE hFile = CreateFile (pcsLocalFile, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
RP_MESSAGE("Failed to open local file")
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hOpen);
return FALSE;
}

BufferIn.dwBufferTotal = GetFileSize (hFile, NULL);

if(!HttpSendRequestEx( hRequest, &BufferIn, NULL, HSR_INITIATE, 0))
{
RP_MESSAGE( "Error on HttpSendRequestEx")
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hOpen);
return FALSE;
}

DWORD sum = 0;
do
{
if (!(bRead = ReadFile (hFile, pBuffer, sizeof(pBuffer),
&dwBytesRead, NULL)))
{
RP_MESSAGE ("ReadFile failed on buffer ")
break;
}
if (!(bRet=InternetWriteFile( hRequest, pBuffer, dwBytesRead,
&dwBytesWritten)))
{
//RP_MESSAGE ("InternetWriteFile failed ")
break;
}
sum += dwBytesWritten;
} while (dwBytesRead == sizeof(pBuffer)) ;

CloseHandle (hFile);

if(!HttpEndRequest(hRequest, NULL, 0, 0))
{
RP_MESSAGE( "Error on HttpEndRequest ")
#pragma chMSG(不管是否正常关闭都返回TRUE)
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hOpen);
return TRUE;
}

InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hOpen);

return TRUE;
}
 
to:垃圾清洁工
斑竹请入,帮忙搞定,万分感谢!
 
你上传的文件有多大 我以前做的时候用的是indyhttp控件

上传的文件大小有个限制 (好像是48k左右)超过了就报错 后来只有把大文件拆分了
 
这种块数据就写(传输)一块数据,所以没有传输大小的限制,只是这种方式比较难以实现,希望大家多调试调试,帮忙搞定。
 
测试通过的代码:
const
cBuffsize = 1024 * 64;
var
httpContext: Integer;
HttpServer, UserID, Passwd: string;
BufferIn: INTERNET_BUFFERS;

RemoteFile: string;
LocalFile: string;
httpFile: THandle;

readInF: DWORD;
oBytesWritten: DWORD;

rRead: BOOL;

Count: DWORD;

HttpNet, HttpConnect, HttpRequest: HINTERNET;
pBuffer: string;
begin
LocalFile := 'W:/ccc.txt';
RemoteFile := '/aaaaa.txt';
HttpServer := '127.0.0.1';
UserID := 'anonymous';
Passwd := 'on@the.net';
HttpNet := InternetOpen(PChar(HttpServer), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
httpContext := 0;
HttpConnect := InternetConnect(HttpNet, PChar(HttpServer), 0, PChar(UserID),
PChar(Passwd), INTERNET_SERVICE_HTTP, 0, httpContext);

HttpRequest := HttpOpenRequest(HttpConnect, 'PUT', PChar(RemoteFile),
nil, nil, nil, 0, 0); //'GET'

httpFile := CreateFile(PChar(LocalFile), GENERIC_READ, FILE_SHARE_READ,
nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

ReadInF := 0;

FillChar(BufferIn, SizeOf(BufferIn), 0);
BufferIn.dwStructSize := SizeOf(BufferIn);
BufferIn.dwBufferLength := cBuffsize;
BufferIn.dwBufferTotal := GetFileSize(httpFile, nil);
HttpSendRequestEx(HttpRequest, @BufferIn, nil, HSR_INITIATE, 0);

repeat
SetLength(pBuffer, cBuffsize);
ReadFile(httpFile, Pointer(pBuffer)^, cBuffsize, Count, nil);
ReadInF := ReadInF + Count;
rRead := InternetWriteFile(httpRequest, Pointer(pBuffer), Count, oBytesWritten);
until ReadInF = BufferIn.dwBufferTotal;

CloseHandle(httpFile);
HttpEndRequest(HttpRequest, nil, 0, 0);
InternetCloseHandle(HttpRequest);
InternetCloseHandle(HttpConnect);
InternetCloseHandle(HttpNet);
end;
 
用GetLastError返回什么类型的错误呢?
 
to:xianjun
看到你的代码,心情真是愉快,我马上回去测试,结果晚上在告诉你
 
上面的代码是测试通过的,基本没有问题
我在 http://www.678910.net/forum_view.asp?forum_id=6&view_id=31 发了一篇
《使用WinINet进行HTTP上传、下载文件(函数)》
封装了一下,你可以参考一二。
 
怎么不用cuteftp来上传呢?
这个软件很好使的简单明了
 
to:xianjun
这么晚才回复真是不好意思,我测试了你的代码,还是不行,我用的是jbulid7和它内置的tomcat来做web服务器的,端口为8080,单步调试到internetwritefile时,第一次可以成功,等到第二次的时候,就失败了,我也不太清楚具体的原因,还望老大多多援助。
 
如果你不是使用默认端口,那么要在InternetConnect的第三个参数指明你的端口
 
我指定了端口号,因为我用jbulider7.0里自带的tomcat来建立模拟web环境的,用户名和密码好像不起作用,在前面的连接和声明请求过程都比较顺利,只是在写远端的时候出现了问题,在第一遍的时候还是可以成功的,在第二次以后internetwriterfile就写不成功了,所以我对此特别郁闷,我没有在IIS的环境下测试,因为上网不太方面,真是很抱歉。
 
时间这么长,分钱罗,感谢xiaojun的帮助,大餐200
 
后退
顶部