2022.1
安卓手机装了primitive ftpd的FTP服务器,方便管理文件。安卓都是UTF8。
WIN10是GB字符集,可以直接用WIN10的资源管理器直接看FTP服务器和下载,但无法上传,提示501 invalid character in command,应是字符集问题。
命令行的ftp,ls时就出现乱码,即服务器是UTF8,本地是GB,字符集不匹配。
用filezilla client软件,一切正常,会自动检测字符集。一般就用它。
用ncFTP,ncftpput上传单个文件,文件名是中文时不正常。放弃使用ncFTP。
FTP传输是支持8bit的,应该是ISO-8859-1扩展成UTF8,所以转成UTF8应就OK。于是自己编一个FTP简单上传程序。
采用WinInet比较简单。
但是,自编程序,转成UTF8后,竟然也有问题,出错,返回值是12003。
这个是WinInet的CFtpConnection::PutFile的问题。坑太多。
根据网友的经验解决。
参考:
http://cn.voidcc.com/question/p-zwzxiksr-bky.html
FTP协议在RFC 959,其结果发表在1985年 FTP协议被设计在原始Telnet协议的顶部上, 指定在RFC 854中指定的远程登录 的相关部分有关FTP的规范是涵盖Network Virtual 终端(NVT)的规范。
根据RFC 854,NVT要求使用 (7位)ASCII作为字符集。使用任何其他字符集 需要明确的协商。该字符集只包含127 不同的字符:英文字母和数字,标点符号 字符和一些控制字符。在ASCII字符集中不包含其他脚本的重音字母,变音符号或 。
为了支持非英文字符 ,1999年在RFC 2640中扩展了FTP规范 。该扩展需要使用UTF-8 作为字符集。该字符集是 ASCII的严格超集,每个有效的ASCII字符也是 UTF-8中的相同字符。 UTF-8字符集可以显示任何有效的Unicode 字符。这包括变音符号,重音字母以及不同的 脚本。此扩展与RFC 959完全向后兼容。由于只使用英文字符,所以您使用的软件是否支持RFC 2640并不重要。但是,如果在不使用RFC 2640兼容软件 的情况下使用非英文字符 ,则会出现问题 - 这些问题完全是由自己制定的,而不是由遵守规范的 来完成。
程序来自《vc实现简单的ftp上传和下载功能》:https://blog.csdn.net/fjssharpsword/article/details/6088500
《FTP采用UTF8编码上传文件名中含有奇数个汉字时出错的解决方法》:https://blog.csdn.net/lizhq007/article/details/8233515
《CFtpConnection PutFile 中文路径utf-8 转码后 上传失败》:https://bbs.csdn.net/topics/391844331
《WinInet 基础知识》:https://docs.microsoft.com/zh-cn/cpp/mfc/wininet-basics?view=msvc-170
程序如下:
MFC对话框,多字节字符工程环境,拖动文件过来后就上传:
#include /
void CDIAGMFCFTPDlg::onDropFiles(HDROP hDropInfo)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
char lpszFileName[MAX_PATH + 1] = { 0 };
CString str_file;
int nFileCount;
nFileCount = ::DragQueryFile(hDropInfo, 0xFFFFFFFF, NULL, 512);
if (nFileCount == 1)
{
::DragQueryFile(hDropInfo, 0, lpszFileName, MAX_PATH);
str_file = lpszFileName; //文件名
}
else
{
::AfxMessageBox("请勿拖放多个文件!");
}
::DragFinish(hDropInfo); //释放内存
myFTPupload(str_file);
CDialogEx::onDropFiles(hDropInfo);
}
void CDIAGMFCFTPDlg::myFTPupload(CString LocalPath)
{
// TODO: 在此处添加实现代码.
CString csdisplay="本地源文件: rn";
csdisplay += LocalPath;
csdisplay += "rnrn";
//CString LocalPath; //本地的文件名
CString FtpPath; //放在服务器的文件名
FtpPath = PathFindFileName(LocalPath);
//MessageBox(FtpPath);
csdisplay += "服务器目标文件: rn";
csdisplay += FtpPath;
csdisplay += "rnrn";
csdisplay += "结果: rn";
//我的FTP服务器是采用UTF8,这里将FTP路径改成UTF8格式。
//多字节字符先转UNICODE宽字符,再转UTF8
// 多字节字符 转 unicode宽字符
char wbuff[4000];
int wi;
wi = MultiByteToWideChar(CP_ACP, 0, FtpPath, -1, (LPWSTR)wbuff, 2000);
wbuff[wi * 2] = 0;
wbuff[wi * 2 + 1] = 0;
if (wi == 0) //转换不成功
{
//MessageBox("error 文件名转换成UTF8不成功");
csdisplay += "error 文件名转换成UTF8不成功rn";
goto WOUT;
}
//unicode宽字符 转 UTF8
char wbuff2[4000];
wi = WideCharToMultiByte(CP_UTF8, NULL, (LPCWCH)wbuff, -1, wbuff2, 4000, 0, 0);
wbuff2[wi] = 0;
if (wi == 0)
{
//MessageBox("error 文件名转换成UTF8不成功");
csdisplay += "error 文件名转换成UTF8不成功rn";
goto WOUT;
}
char csserver[2000];
int myport;
GetDlgItemText(IDC_EDIT1, csserver, 2000);
myport = GetDlgItemInt(IDC_EDIT2);
//程序来自《vc实现简单的ftp上传和下载功能》
CInternetSession *m_pInternetSession = new CInternetSession(AfxGetAppName(), 1, PRE_CONFIG_INTERNET_ACCESS);
CFtpConnection *m_pFtpConnection = NULL;
try
{
m_pFtpConnection = m_pInternetSession->GetFtpConnection(csserver, "anonymous", "", myport, 1);
// LPCTSTR pstrServer, LPCTSTR pstrUserName, LPCTSTR pstrPassword , INTERNET_PORT nPort, BOOL bPassive
// 被动是服务器开2个端口。 主动是服务器要连接到client另一个口(有防火墙问题)
if (m_pFtpConnection != NULL) //链接成功
{
// CFtpFileFind FtpFinder(m_pFtpConnection);
//这里仅做上传。FTP上传文件名称中文乱码,二个方法解决
// 方法一 成功,先上传一个假文件名,再重命名。
//《FTP采用UTF8编码上传文件名中含有奇数个汉字时出错的解决方法》:先弄个临时的文件名,不要含有中文,待他上传完成后,调用rename把刚才的临时文件名重命名为自己想要的名字。在上传完成后马上进行重命名 *** 作会失败,是间隔时间上的问题,需要在rename之前加上延时或者循环直至成功。
//上传文件,用特定文件名
if (!(m_pFtpConnection->PutFile(LocalPath, "~_T1e2M3p4_~.wxlftp", FTP_TRANSFER_TYPE_BINARY, 1)))
{
DWORD dErr = GetLastError();
CString sErr;
sErr.Format("上传失败: ERROR %d", dErr);
//AfxMessageBox(sErr);
csdisplay += sErr; csdisplay += "rn";
}
//重命名文件
int isleep = 0;
while (!m_pFtpConnection->Rename("~_T1e2M3p4_~.wxlftp", wbuff2))
{
Sleep(1); //1ms
if (isleep++ > 5000)
{
//MessageBox("error rename file.");
csdisplay += "error rename file."; csdisplay += "rn";
break;
}
}
csdisplay += "成功!rn";
}
}
catch (CInternetException *pEx)
{
TCHAR szError[1024];
if (pEx->GetErrorMessage(szError, 1024))
{
//AfxMessageBox(szError);
csdisplay += "ERROR: "; csdisplay += szError; csdisplay += "rn";
}
else
{
//AfxMessageBox("There was an exception");
csdisplay += "ERROR: There was an exception"; csdisplay += "rn";
}
pEx->Delete();
}
if (m_pFtpConnection != NULL)
{
m_pFtpConnection->Close();
delete m_pFtpConnection;
}
delete m_pInternetSession;
WOUT:
CTime t1 = CTime::GetCurrentTime();
csdisplay += t1.Format("%Y-%m-%d %H:%M:%S -%A");
csdisplay += "rn";
SetDlgItemText(IDC_EDIT3, csdisplay);
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)