『壹』 怎麼獲取HTTP 302重定向的header信息
翻到以前有人發帖問過類似問題,有人回答或NULL, // proxy name. NULL indicates use default.
使用非同步的請求就可以了
m_session = ::InternetOpen (agent_name,
INTERNET_OPEN_TYPE_PRECONFIG, // use registry settings.
只要HttpQueryInfo(...,HTTP_QUERY_LOCATION,...)就行了
NULL, // list of local servers. NULL indicates default.
INTERNET_FLAG_ASYNC) ;
但以上兩種方法都試過,無效,求教。
如果只是想獲取到被重定向到哪去,而不需要訪問被重定向後的頁
那麼就在調用HttpOpenRequest時,dwFlags參數加上INTERNET_FLAG_NO_AUTO_REDIRECT
然後用HttpQueryInfo去獲取信息
如果又要知道重定向去哪,又要訪問最終目標頁,那就要在CallBack里獲取了
當InternetStatusCallback的dwInternetStatus為INTERNET_STATUS_REDIRECT,就是重定向
是第二種情況用httpsendrequest 發送HTTP包時,如遇到網站響應是HTTP302,不能獲取到302頭信息和Location地址,只能獲取到重定向後的結果200和重寫向後的網頁內容。
問題就是Callback中得到的 dwInternetStatus 的值不是INTERNET_STATUS_REDIRECT
使用location標簽,就可以取得
提出這個問題,就是因為從location 這里取不到,location 也是從HttpQueryInfo去獲取的返回信息里提取的值,現在是返回信息里沒有。
『貳』 如何從Internet上有效而穩定地下載文件
為了使用這個函數,只需要提供一個有效的HINTERNET句柄,這個句柄可以通過標準的InternetOpen()掉用來獲 得。如果你願意的話,你還可以將一個句柄提供給進度窗口(ID為一靜態控制的標示符,用來顯示狀態 ),在這個函數的頭幾行代碼中聲明一些變數。Dword dwSize;這個變數被用於存儲每次 調用InternetReadFile讀取了多少數據。CHAR szHead[] = "Accept: */*\r\n\r\n";用於存儲多個HTTP頭信息。如果在調用InternetOpenUrl時不傳遞著個頭信 息,則只允許你打開文本文件!VOID* szTemp[16384];緩沖變數,可以存儲來自 Internet的16KB的文件數據。HINTERNET hConnect;這是一個HINTERNET句柄,包含請求結果(來自InternetOpenUrl)FILE * pFile;標準的C文件句柄(必須包含stdio.h)。 如果你願意,可以使用Win32處理文件的APIif (!(hConnect = InternetOpenUrlA (hOpen, szUrl, szHead, lstrlenA (szHead), INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD, 0))){return INTERNET_ERROR_OPENURL; }此調用可以打開一個使用URL的Internet文件句柄。標 志表示這個文件總是被讀取,而不是緩存(cache)。如果失敗,則此函數返回錯誤,你可以給定 INTERNET_ERROR_OPENURL任何值。必須為這個函數定義所有的錯誤信息。也可以用一個數字替代。if(!(pFile = fopen(szFileName, "wb" ))){return INTERNET_ERROR_FILEOPEN; }此調用根據給定的文件名打開文件。如果失敗則返回 另一個用戶定義的錯誤。DWORD dwByteToRead = 0; DWORD dwSizeOfRq = 4; DWORD dwBytes = 0;這三個值分別存儲文件的大小,HttpQueryInfo內容的大小和總共 讀取的位元組數。if (!HttpQueryInfo(hConnect, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwByteToRead, &dwSizeOfRq, NULL)){dwByteToRead = 0; }此調用可以獲得文件的大小。如果失敗則dwByteToRead被 置為0,並且當文件被下載時不會顯示百分比和總數DWORD start;DWORD end;DWORD time;time = 10;start = timeGetTime();使用這些bit必須包含mmsystem.h並鏈接winmm.lib,它們用於時間選擇,告訴用戶下載的速度。例子代碼只統計了下載速度,你可以擴展這個功能,比如估計還剩多少時間。do{if (! InternetReadFile(hConnect, szTemp, 16384, &dwSize)){fclose (pFile); return INTERNET_ERROR_READFILE; }此調用循環中,每次下載一個16KB的數據 塊。如果download請求失敗,則文件被關閉並返回錯誤。if (!dwSize)break;elsefwrite(szTemp, sizeof(char), dwSize, pFile);如果dwSize為0,則意味著一個EOF,循環退出。否則由InternetReadFile讀取的數據內容被寫到本地文件中。dwBytes+=dwSize; if(dwByteToRead && hwndProgress){SendDlgItemMessageA(hwndProgress, idProgressBar, WM_USER+2, (dwBytes*100)/dwByteToRead, 0); UpdateWindow(hwndProgress); }這個代碼中,dwBytes是從文件讀取的數據量,它不斷增加,如果文件長度是有效的,則進度窗口句柄被指定,進度條被更新已表示下載進度 。FLOAT fSpeed = 0; fSpeed = (float)dwBytes; fSpeed /= ((float) time)/1000.0f; fSpeed /= 1024.0f;這些bit代碼用於根據所花時間計算下載速度 和讀取的數據量。if(hwndProgress){char s[260]; sprintf(s, "%d KB / %d KB @ %1.1f KB/s", dwBytes/1024, dwByteToRead/1024, fSpeed); SetDlgItemTextA(hwndProgress, idStatusText, s); UpdateWindow(hwndProgress); } 設置和處理進度窗口的狀態文本,表示下載的文件大小和下載速度。end = timeGetTime(); time = end - start; if(time == 0)time = 10;時間被更 新} // dowhile (TRUE);循環結束fflush (pFile); fclose (pFile);return 0;}最後,函數結束,關閉文件並清除硬體驅動的緩沖。返回0表示成功。使用這個代碼段,按照本文所描述的那樣,你可以自己編寫一個程序來從 Internet上有效地、穩定地下載文件。實現細節請參見例子。
『叄』 VC++怎麼獲取FTP上的文件大小信息
通過CFtpFileFind 得到文件的URL之後,然後通過CHttpFile::QueryInfo 得到文件大小。
『肆』 在微擎中如何使用fansQueryInfo函數
1、數據基本操作
tablename()
$sql = "SELECT * FROM ".tablename('users');
echo $sql;
//輸出 SELECT * FROM ims_users
2、范圍條件操作
array('>', '<', '<>', '!=', '>=', '<=', 'NOT IN', 'not in', '+=', '-=');
//獲取adid大於269的公眾號
$accout = pdo_get('account', array('acid >' => '269'));
//增加一次用戶的錯誤登錄次數,兩次變為2即可
pdo_update('users_failed_login', array('count +=' => 1),array('username' => 'qiuweinan'));
3、查詢
pdo_get:根據條件(AND連接)到指定的表中獲取一條記錄
array | boolean pdo_get($tablename, $condition = array(), $fields = array());
//根據uid獲取用戶的用戶名和用戶Id信息
//生成的SQL等同於:SELECT username,uid FROM ims_users WHERE uid = '1' LIMIT 1
$user = pdo_get('users', array('uid' => 1), array('username', 'uid'));
//生成的SQL等同於:SELECT username FROM ims_users WHERE username = 'qiuweinan' AND status = '1' LIMIT 1
$user = pdo_get('users', array('username' => 'qiuweinan', 'status' => 1), array('username'));
pdo_getcolumn:根據條件(AND連接)到指定的表中獲取一條記錄的指定欄位
string | int pdo_getcolumn($tablename, $condition = array(), $field);
//根據uid獲取用戶的用戶名
//生成的SQL等同於:SELECT username FROM ims_users WHERE uid = '1' LIMIT1
$username = pdo_getcolumn('users', array('uid' => 1), 'username');
pdo_getall:根據條件(AND連接)到指定的表中獲取全部記錄
array | boolean pdo_getall($tablename, $condition = array(), $fields = array(), $keyfiled = '');
//獲取全部啟用的用戶
//生成的SQL等同於:SELECT * FROM ims_users WHERE status = '1'
$user = pdo_getall('users', array('status' => 1));
pdo_getslice:根據條件(AND連接)到指定的表中獲取某個區間的記錄,此函數和pdo_getall的區別是可以指定limit的值
array | boolean pdo_getslice($tablename, $condition = array(), $limit = array(), &$total = null, $fileds = array(), $keyfield = '');
$user = pdo_getslice('users', array(), array(0,10), $total);
echo $total;
pdo_fetch:根據SQL語句,查詢一條記錄
array | boolean pdo_fetch($sql, $params = array());
// :uid 是參數的一個點位符,沒有使用引號,傳入的第二個參數中要與SQL中的佔位名稱相同
$user = pdo_fetch("SELECT username, uid FROM ".tablename('users')." WHERE uid = :uid LIMIT 1", array(':uid' => 1));
// LIKE 佔位的使用方法
$user = pdo_fetch("SELECT * FROM ".tablename('users')." WHERE username LIKE :username", array(':username' => '%qiuweinan%'));
pdo_fetchcolumn:根據SQL語句,查詢第一條記錄的第N列的值,此語句與pdo_fetch使用相同,只是此函數返回的不是一個數組而是一個字元串
string | boolean pdo_fetchcolumn($sql, $params = array(), $column = 0);
//獲取用戶的總數,返回的值是一個數字
$user_total = pdo_fetchcolumn("SELECT COUNT(*) FROM ".tablename('users'));
pdo_feachall:根據SQL語句,查詢全部記錄,使用方法與pdo_feach相同
array | boolean pdo_fetchall($sql, $params = array(), $keyfield = '');
//需要注意的是,返回的數組的鍵值為用戶的uid
$user = pdo_fetchall("SELECT username,uid FROM ".tablename('users'), array(), 'uid');
4、變更
pdo_insert:對指定數據表插入一條新記錄
int | boolean pdo_insert($tablename, $data = array(), $replace = false);
//添加一條用戶記錄,並判斷是否成功
$user_data = array(
'username' => 'qiuweinan1',
'status' => '1',
);
$result = pdo_insert('users', $user_data);
if(!empty($result)){
$uid = pdo_insertid();
message('添加用戶成功,UID為' .$uid);
}
pdo_update:更新指定的數據表記錄
array | boolean pdo_updata($tablename, $data = array(), $condition, $glue = 'AND');
//更新uid=2的用戶的用戶名
$user_data = array(
'username' => 'qiuweinan2',
);
$result = pdo_update('users', $user_data, array('id' =>2));
if(!empty($result)){
message('更新成功');
}
pdo_delete:刪除指定條件的數據
int | boolean pdo_delete($tablename, $condition = array(), $glue = 'AND');
//刪除用戶名為qiuweinan2的記錄
$result = pdo_delete('users', array('username' => 'qiuweinan2'));
if(!empty($result)){
message('刪除成功');
}
5、運行SQL
pdo_query:運行一條SQL語句
int | boolean pdo_query($sql, $params = array());
//更新uid=2的用戶的用戶名
$result = pdo_query("UPDATA ".tablename('users')." SET username = :username, age = :age WHERE uid = :uid", array(':username' => 'qiuweinan2', ':age' => 18, ':uid' => 2));
//刪除用戶名為qiuweinan2的記錄
$result = pdo_query("DELETE FROM ".tablename('users')." WHERE username = :username", array(':username' => 'qiuweinan2'));
if(!empty($result)){
message('刪除成功');
}
pdo_run:批量執行語句
boolean run($sql, $stuff = 'ims_');
$sql = <<<EOF
CREATE TABLE IF NOT EXISTS `ims_multisearch` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`weid` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `ims_multisearch_fields` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`reid` int(10) unsigned NOT NULL,
`type` tinyint(1) unsigned NOT NULL DEFAULT `1`,
PRIMARY KEY(`id`),
KEY 'idx_reid' (`reid`)
)ENGINE=MyISAM DEFAULT CHARSET=utf8;
EOF;
pdo_run($sql);
6、輔助函數
pdo_fieldexists:檢查表中是否存在某個欄位
boolean pdo_fieldexists($tablename, $fieldname);
//如果shopping_goods表中不存在credit欄位,則新增credit欄位
if(!pdo_fieldexists('shopping_goods', 'credit')) {
pdo_query("ALTER TABLE ".tablename('shopping_goods')." ADD `credit` int(11) NOT NULL DEFAULT '0';");
}
pdo_indexexists:檢查表中是否存在某個索引
boolean pdo_indexexists($tablename, $indexname);
//如果site_slide表中不存在multiid索引,則新增multiid索引
if(!pdo_indexexists('site_slide', 'multiid')) {
pdo_query("ALTER TABLE ".tablename('site_slide')." ADD INDEX `multiid` (`multid`);")
}
pdo_tableexists:檢查資料庫中是否存在某個表
boolean pdo_tableexists($tablename);
pdo_debug:調試運行SQL語句,顯示執行過的SQL的棧情況
array pdo_debug($output = true, $append = array());
pdo_debug();
//調用該函數結果如下
Array
(
[0] => Array
(
[sql] => SET NAMES 'utf8';
[error] => Array
(
[0] => 00000
[1] =>
[2] =>
)
)
[1] => Array
(
[sql] => SELECT `value` FROM `ims_core_cache` WHERE `key`=:key
[params] => Array
(
[:key] => setting
)
[error] => Array
(
[0] => 00000
[1] =>
[2] =>
)
)
)
『伍』 urldownloadfile是否會用系統代理
使用java的HttpURLConnection類可以實現HttpClient的功能,而不需要依賴任何其他類庫。所有有時候大家就直接使用它來完成一些簡單(或復雜)的功能。但是你活在偉大的{print G.F.W}後面,如果你需要訪問的網站被牆了,那HttpURLConnection類就會出現連接超時的錯誤。這時候就需要給他設置代理(Proxy)了。
設置代理(Proxy)可以有兩種方式:
1、通過設置系統屬性(System.setPropery(String key, String value)的方式
首先你可以在這里看到Java支持的屬性。我們可以使用其中的http.proxyHost,http.proxyPort這兩個屬性。顧名思義,就是分別設置代理伺服器地址和代理埠。
[c-sharp] view plainprint?
//在你發起Http請求之前設置一下屬性
System.setProperty("http.proxyHost", "www.proxy.com");
System.setProperty("http.proxyPort", "8080");
[c-sharp] view plainprint?
//在你發起Http請求之前設置一下屬性
System.setProperty("http.proxyHost", "www.proxy.com");
System.setProperty("http.proxyPort", "8080");
替換上面的www.proxy.com為你的代理伺服器地址或IP地址,以及相應的埠為真實埠,Http連接及可以工作了。需要注意的是如果你設置了這些屬性,那麼所有的Http請求都會通過代理伺服器。這些屬性是JVM級別的,設置了以後對所有的同類請求都有效。比如上面的是關於http的,還有關於ftp的等等。
如果你的代理伺服器不需要驗證,那到此就結束了。但一般都是需要驗證的。但是你要是看了上面Java支持的屬性列表,你就會發現那裡面並沒有期望中的
[c-sharp] view plainprint?
http.proxyUserName=username
http.proxyPassword=password
[c-sharp] view plainprint?
http.proxyUserName=username
http.proxyPassword=password
這兩個屬性。 這時就需要java.net.Authenticator類來完成一般的Http驗證。但是java.net.Authenticator這個類卻是個抽象類,我們要使用還需要實例化一下子自己的類。個人覺得這里很不方便。如下:
[java] view plainprint?
public class BasicAuthenticator extends Authenticator {
String userName;
String password;
public BasicAuthenticator(String userName, String password) {
this.userName = userName;
this.password = password;
}
/**
* Called when password authorization is needed. Subclasses should
* override the default implementation, which returns null.
*
* @return The PasswordAuthentication collected from the
* user, or null if none is provided.
*/
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(userName, password.toCharArray());
}
}
[java] view plainprint?
public class BasicAuthenticator extends Authenticator {
String userName;
String password;
public BasicAuthenticator(String userName, String password) {
this.userName = userName;
this.password = password;
}
/**
* Called when password authorization is needed. Subclasses should
* override the default implementation, which returns null.
*
* @return The PasswordAuthentication collected from the
* user, or null if none is provided.
*/
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(userName, password.toCharArray());
}
}
我們需要覆蓋java.net.Authenticator類的getPasswordAuthentication()方法,並返回一個PasswordAuthentication實例。要使他起作用,還需要設置
[java] view plainprint?
Authenticator.setDefault(new BasicAuthenticator(userName, password));
[java] view plainprint?
Authenticator.setDefault(new BasicAuthenticator(userName, password));
這樣就提供了基於Http Basic的驗證,接著就可以順暢的使用需要驗證的代理了。
2、通過java.net.Proxy類。
這種方式是實例化一個Proxy類提供代理伺服器的信息,如埠和地址。
[java] view plainprint?
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port));
URLConnection conn = url.openConnection(proxy);
[java] view plainprint?
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port));
URLConnection conn = url.openConnection(proxy);
使用代理的方式是在打開Http連接的時候同時傳遞一個Proxy參數。如果需要驗證信息的話我們可以添加一個Http頭參數來實現。
[java] view plainprint?
//格式如下:
"Proxy-Authorization"= "Basic Base64.encode(user:password)"
String headerKey = "Proxy-Authorization";
String headerValue = "Basic " + Base64.encode(user+":"+password);
conn.setRequestProperty(headerKey, headerValue);
//..........
[java] view plainprint?
//格式如下:
"Proxy-Authorization"= "Basic Base64.encode(user:password)"
String headerKey = "Proxy-Authorization";
String headerValue = "Basic " + Base64.encode(user+":"+password);
conn.setRequestProperty(headerKey, headerValue);
//..........
其中的Base64.encode(user:password)是指把用戶名和密碼用冒號連接起來之後使用Base64編碼後的值作為值的一部分。
通過這種方式隻影響特定的Http連接,但是需要對代碼進行修改。這種方式下是否可以使用Authenticator還未做驗證。
文章知識點與官方知識檔案匹配
網路技能樹首頁概覽
19296 人正在系統學習中
『陸』 C++ 怎麼獲取FTP上所有的文件夾還有所有文件
通過CFtpFileFind遞歸進行查詢,如果沒有文件,會返回false,就不用進行再查找了。如果有文件或文件夾,通過getnext進行遍歷查看就行
『柒』 求助,wininet post後HttpQueryInfo獲取不到東西
錯誤情況是:未定義操作,請返回。 抓包看看你發出的數據,跟DZ注冊發送的數據是否一樣。 有些系統的cookie,可以是通過頁面的js生成的。一般dz肯定會有一個session來標識當前用戶(不管是登陸還是未登錄)。
『捌』 怎麼讀取HttpSendRequest獲取的數據
// Open Internet session.
HINTERNET hSession = ::InternetOpen("MSDN SurfBear",
PRE_CONFIG_INTERNET_ACCESS,
NULL,
INTERNET_INVALID_PORT_NUMBER,
0) ;
// Connect to http://www.microsoft.com/.
HINTERNET hConnect = ::InternetConnect(hSession,
"http://www.microsoft.com/",
INTERNET_INVALID_PORT_NUMBER,
"",
"",
INTERNET_SERVICE_HTTP,
0,
0) ;
// Request the file /MSDN/MSDNINFO/ from the server.
HINTERNET hHttpFile = ::HttpOpenRequest(hConnect,
"GET",
"/MSDN/MSDNINFO/",
HTTP_VERSION,
NULL,
0,
INTERNET_FLAG_DONT_CACHE,
0) ;
// Send the request.
BOOL bSendRequest = ::HttpSendRequest(hHttpFile, NULL, 0, 0, 0);
// Get the length of the file.
char bufQuery[32] ;
DWORD dwLengthBufQuery = sizeof(bufQuery);
BOOL bQuery = ::HttpQueryInfo(hHttpFile,
HTTP_QUERY_CONTENT_LENGTH,
bufQuery,
&dwLengthBufQuery) ;
// Convert length from ASCII string to a DWORD.
DWORD dwFileSize = (DWORD)atol(bufQuery) ;
// Allocate a buffer for the file.
char* buffer = new char[dwFileSize+1] ;
// Read the file into the buffer.
DWORD dwBytesRead ;
BOOL bRead = ::InternetReadFile(hHttpFile,
buffer,
dwFileSize+1,
&dwBytesRead);
// Put a zero on the end of the buffer.
buffer[dwBytesRead] = 0 ;
// Close all of the Internet handles.
::InternetCloseHandle(hHttpFile);
::InternetCloseHandle(hConnect) ;
::InternetCloseHandle(hSession) ;
// Display the file in an edit control.
pEditCtrl->SetWindowText(buffer) ;
『玖』 presto(七)——restful api之cluster
有三個狀態:節點管理器、查詢管理器、是否包含協調器
由兩個最開始ClusterStatsResource中的兩個狀態提供:
看最後一行,refreshNodesInternal。
每隔5秒來,由協調器節點主動去查詢workers狀態。而且在更新完成5s之後,就調用上面的refreshNodesInternal方法。通過/v1/service來獲取節點信息,把新節點加入到DiscoveryNodeManager的一個map中nodeStates。
QueryManager提供了getAllQueryInfo方法給ClusterStatsResource來獲取ClusterStats中的狀態信息。
這個類在創建query時候,加入到 queries中
同時對每一個query添加監聽器,一旦執行狀態改變,就更新狀態query狀態即:QueryInfo
我們看到大量的信息是來自query.QueryInfo中的信息。
待續~~~
『拾』 用wininet的InternetReadFile如何得知文件大小
Visual C++
如何:讀取二進制文件
下面的代碼示例演示如何從文件中讀取二進制數據。使用了 System.IO 命名空間中的兩個類:FileStream 和 BinaryReader。FileStream 表示實際的文件。BinaryReader 為允許二進制訪問的流提供介面。
下面的代碼示例使用由如何:編寫二進制文件中的代碼創建的稱為 data.bin 的文件。
示例
// binary_read.cpp
// compile with: /clr
#using<system.dll>
using namespace System;
using namespace System::IO;
int main()
{
String^ fileName = "data.bin";
try
{
FileStream^ fs = gcnew FileStream(fileName, FileMode::Open);
BinaryReader^ br = gcnew BinaryReader(fs);
Console::WriteLine("contents of :", fileName);
while (br->BaseStream->Position < br->BaseStream->Length)
Console::WriteLine(br->ReadInt32().ToString());
fs->Close( );
}
catch (Exception^ e)
{
if (dynamic_cast<FileNotFoundException^>(e))
Console::WriteLine("File '' not found", fileName);
else
Console::WriteLine("Exception: ()", e);
return -1;
}
return 0;
}
★★補充★★
手上的一個VB項目(過程中發現,.Net果然是好啊),需要在一個ActiveX中實現HTTP下載功能,我是採用InternetreadFile這個API來實現,一開始的代碼我是這么寫的
Function Gethttpdownload(sUrl As String) As boolen
Dim s As String
Dim hOpen As Long
Dim hOpenUrl As Long
Dim bDoLoop As Boolean
Dim bRet As Boolean
Dim sReadBuffer As String * 2048
Dim lNumberOfBytesRead As Long
hOpen = InternetOpen(scUserAgent, INTERNET_OPEN_TYPE_PRECONFIG, vbNullString, vbNullString, 0)
hOpenUrl = InternetOpenUrl(hOpen, sUrl, vbNullString, 0, INTERNET_FLAG_RELOAD, 0)
bDoLoop = True
Do While bDoLoop
sReadBuffer = vbNullString
bRet = InternetReadFile(hOpenUrl, sReadBuffer, Len(sReadBuffer), lNumberOfBytesRead)
s = s & Left$(sReadBuffer, lNumberOfBytesRead)
If Not CBool(lNumberOfBytesRead) Then bDoLoop = False
Loop
FileName = "E:\BitSpirit\Torrent\121212.torrent"
F1 = FreeFile
Open FileName For Binary As F1
Put F1, , s
Close F1
If hOpen <> 0 Then InternetCloseHandle (hOpen)
Gethttpdownload = true
End Function
上面方法,用來獲取伺服器上的文本類型的文件一點問題,都沒有,但是用來下載二進制文件的時候 就出現問題了,裡面的數據怎麼也不對,研究了下載下來的文件後發現,問題外話應該是在接收數據的變數是個STRING的定長字元串上。但是在網上查了好久,甚至M$ MSDN上的一個用VB來實現下載的程也是用 string類型來接收數據的而且網上的代碼寫法,基本上也都是這個樣,好來才好現,都是從MSDN上的哪個常式上演變過來的.
我想如果能用一個byte數組來代替定長字元串,哪可能就沒有問題了,但是查看了一個VB 對Internetreadfile的申明
Public Declare Function InternetReadFile Lib "wininet.dll" (ByVal hFile As Long, ByVal sBuffer As String, ByVal lNumBytesToRead As Long, lNumberOfBytesRead As Long) As Integer
發現其定義ByVal sBuffer As String 看來只能用String了,在網上查找過程中,發現人家用VC寫的程序中這人參數可以是其它的,所以查看了一下Internetreadfile的原型。發現的確可以, 所以我把internetreadfile的定義修改了一下,為了通用,我為新的internetreadfile定義了一個別名。Internetreadfilebyte申明如下:
Public Declare Function InternetReadFileByte Lib "wininet.dll" Alias "InternetReadFile" (ByVal hFile As Long, ByRef sBuffer As Byte, ByVal lNumBytesToRead As Long, lNumberOfBytesRead As Long) As Integer
試了一下的確可以,重新修改函數,(在這過程中發現,如果要取到正確數據,還必須取得文件大小。所以增加了HttpQueryInfo的定義)最後完整的函數
Function FileDownload(sUrl As Variant) As Boolean
Dim b(99) As Byte
Dim EndByte() As Byte
Dim s As String
Dim hOpen As Long
Dim hOpenUrl As Long
Dim bDoLoop As Boolean
Dim bRet As Boolean
Dim bbuffer As Byte
Dim sReadBuffer As String
Dim FileName As String
Dim lNumberOfBytesRead As Long
Dim F1 As Integer
Dim strsize As String
Dim size As Long
strsize = String$(1024, " ")
F1 = FreeFile
stTotal = vbNullString
FileName = "E:\BitSpirit\Torrent\121212.torrent"
Open FileName For Binary As F1
hOpen = InternetOpen(scUserAgent, INTERNET_OPEN_TYPE_PRECONFIG, vbNullString, vbNullString, 0)
hOpenUrl = InternetOpenUrl(hOpen, sUrl, vbNullString, 0, INTERNET_FLAG_RELOAD, 0)
bDoLoop = True
HttpQueryInfo hOpenUrl, HTTP_QUERY_CONTENT_LENGTH Or HTTP_QUERY_FLAG_NUMBER, ByVal strsize, Len(strsize), 0
size = CLng(Trim(strsize))
For j = 1 To size \ 100
bDoLoop = InternetReadFileByte(hOpenUrl, b(0), 100, lNumberOfBytesRead)
Put F1, , b
If Not CBool(lNumberOfBytesRead) Then Exit For
Next
If size Mod 100 <> 0 Then
tmp = (size Mod 100) - 1
ReDim EndByte(tmp)
bDoLoop = InternetReadFileByte(hOpenUrl, EndByte(0), tmp + 1, lNumberOfBytesRead)
Put F1, , EndByte
End If
If hOpenUrl <> 0 Then InternetCloseHandle (hOpenUrl)
If hOpen <> 0 Then InternetCloseHandle (hOpen)
Close #1
FileDownload = True
End Function
測試了一下,完全成功:)