本文使用Qt Creator用HTTP POST的方法上傳文件,並給出一個上傳文件的例程。
本文主要客戶端,所以對於服務器端程序編寫的描述會比較簡略
服務器使用Django編寫,django服務器接收文件的方法在文章http://www.cnblogs.com/fnng/p/3740274.html中有較為清晰的講解,我搭建的服務器端程序除了沒有網頁客戶端以及部分變量名稱不同以外,基本上與這篇文章的服務器搭建過程一樣。
如果服務器端程序發生變化,這篇文章后面給出的客戶端例程可能就不再適用。因此如果運行客戶端程序之后發現服務器端不能接收到文件,不要直接認為這篇文章給出的客戶端例程是錯誤的,也可能是其他問題導致的。
在制作程序時,我並沒有嘗試上傳大文件、同時上傳多個文件以及文件名中包含中文這三種情況。因此在這三種情況下程序很有可能出現BUG。
示例程序鏈接:http://pan.baidu.com/s/1i5NWsHR
1. 服務器端
服務器端程序基本參照http://www.cnblogs.com/fnng/p/3740274.html。這里直接貼出代碼,搭建過程以及代碼描述等就不進行說明了。
disk/views.py:
from django.shortcuts import render,render_to_response
from django.http import HttpResponse
from django import forms
from .models import User
import os
# Create your views here.
class UserForm(forms.Form):
username=forms.CharField()
upload_file=forms.FileField()
def index(request):
if request.method=="POST":
uf=UserForm(request.POST,request.FILES)
print(str(request.POST))
print(str(request.FILES))
if uf.is_valid():
username=uf.cleaned_data['username']
upload_file=uf.cleaned_data['upload_file']
dir_name='./upload/'+username
if os.path.exists(dir_name)==False:
os.mkdir(dir_name)
user=User()
user.username=username
user.upload_file=upload_file
user.save()
return HttpResponse('upload ok!')
else:
uf=UserForm()
return HttpResponse('000!')
disk/models.py:
from django.db import models
# Create your models here.
def content_file_name(instance,filename):
s='/'.join(['upload',instance.username,filename])
return s
class User(models.Model):
username=models.CharField(max_length=30)
upload_file=models.FileField(upload_to=content_file_name)
def __unicode__(self):
return self.username
disk/urls.py:
from django.conf.urls import url
from . import views
urlpatterns=[
#View the information of user.
url(r'^$',views.index,name='index'),
]
2. 客戶端程序應該上傳的數據
客戶端程序在向服務器端上傳文件時,不能只上傳文件的內容。如果上傳的數據中只有文件的內容,那么服務器端是不能正常接收到文件的。客戶端上傳的內容應該包括普通的表單數據、文件頭部以及文件內容三大部分,並對需要傳輸的數據進行規范化地拼接,按照特定的格式上傳數據。
對於我用django制作的這個服務器端程序來說,客戶端需要上傳一個name為username的普通數據,以及一個name為upload_file的文件數據。下面的代碼將需要發送的數據進行拼接並使用POST請求將數據發送給服務器。
3. 新建工程過程中需要注意的地方
在pro文件中要加上QT += network 如果不添加會報錯
在代碼文件的最前面添加包含 #include 。(不添加的話程序會編譯失敗)我自己在學習使用Qt進行HTTP通信時發現網上的很多文章在貼出代碼時並沒有貼出前面的#include部分,導致我花了很長時間去找需要引用的文件。
4. 客戶端上傳文件的代碼
void UpLoadForm(QString Path,QMap<</span>QString,QString> params,QStringfileFormName,QFile *uploadFile,QString newFileName){
QString BOUNDARY=QUuid::createUuid().toString();
QByteArray sb=QByteArray();
//先上傳普通的表單數據
for(QMap<</span>QString,QString>::Iteratort=params.begin();t!=params.end();t++){
sb.append("--"+BOUNDARY+"\r\n");
sb.append(QString("Content-Disposition: form-data;name=\"")+t.key()+QString("\"")+QString("\r\n"));
sb.append("\r\n");
sb.append(t.value()+"\r\n");
}
//上傳文件的頭部
sb.append("--"+BOUNDARY+"\r\n");
sb.append(QString("Content-Disposition: form-data;name=\"")+fileFormName+QString("\";filename=\"")+newFileName+QString("\"")+QString("\r\n"));
sb.append("\r\n");
//上傳文件內容
if(!uploadFile->open(QIODevice::ReadOnly)){
return;
}
sb.append(uploadFile->readAll());
sb.append("\r\n");
sb.append("--"+BOUNDARY+"\r\n");
//編輯HTTP頭部
QNetworkAccessManager *_uploadManager=new QNetworkAccessManager();
QNetworkRequest request=QNetworkRequest(QUrl(Path));
request.setRawHeader(QString("Content-Type").toLatin1(),QString("multipart/form-data;boundary="+BOUNDARY).toLatin1());
request.setRawHeader(QString("Content-Length").toLatin1(),QString::number(sb.length()).toLatin1());
//執行post請求
_uploadManager->post(request,sb);
}
5. 編寫main函數調用前面上傳文件的代碼,完成測試。
在這里,我們提交了一個name為username的普通表單數據,它的值為10005。我們同時還提交了一個name為upload_file的文件數據。我們上傳了本地的”:/Untitled.png”文件,上傳成功之后服務器會接收到這個文件,保存時命名為”1A.png”
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString path="http://192.168.252.2:8000/disk/"; //服務器的url
QMap<</span>QString,QString> params_send; //上傳的普通參數 在本程序中 需要上傳一個普通參數為"username"
params_send.insert("username","10005");
QString fileFormName="upload_file"; //上傳文件表單中的名字
QFile *file=new QFile(":/Untitled.png");
QString newFileName="1A.png";
UpLoadForm(path,params_send,fileFormName,file,newFileName);
return a.exec();
}
6. 效果
我們把這張圖片”untitled.png”上傳給服務器
服務器接收到了客戶端發來的圖片,表單數據中username=10005,所以新建了一個文件夾”10005”,將接收到的圖片保存在了這個文件夾中並命名為”1A.png”
7. 參考資料
http://www.cnblogs.com/fnng/p/3740274.html
https://forum.qt.io/topic/11086/solved-qnetworkaccessmanager-uploading-files
http://blog.csdn.net/lmj623565791/article/details/23781773
如果發現問題歡迎在下面留言或私信我
http://blog.sina.com.cn/s/blog_15d207b300102xvqz.html


