Windows下Perforce Command Line处理中文参数的两种方法
Windows下Command Line中的中文字符是采用ANSI编码来处理的,而Perforce command line要求传入的中文参数(文件(夹)名)为UTF-8编码,所以需要将中文参数转换为UTF-8后再做处理,下面介绍两种处理方法。
一、系统调用
通过使用WinExec、ShellExecute或system,如:
_snprintf(cmdbuf , 1024 , "p4 -c %s add \"%s\"" , argv[1] , ANSIToUTF8(path.c_str())); system(cmdbuf);
此方法的虽然简单,但存在效率问题,因为有创建进程的巨大开销。此外不同版本的Perforce也会出现不同的执行结果,针对特定的中文会出现操作失败的诡异问题。
二、Perforce SDK
Perforce提供有SDK用以扩展或集成到其他应用中,虽然没有详细的文档,但可以通过学习SDK中的sample文件来学习,此方法最稳定。
下面代码展示了通过SDK中ClientAPI来递归添加指定文件夹下的所有文件:
# include "clientapi.h" # include "i18napi.h" # include "CharSetConvertUtil.h" # include <string> # include <vector> # include <list> # include <io.h> using namespace std; // structure to hold a directory and all its filenames. struct FILELIST { string path; vector<string> theList; }; void TransverseDirectory(string path, list<FILELIST>& theList) { struct _finddatai64_t data; string fname = path + "\\*.*"; long h = _findfirsti64(fname.c_str(),&data); if(h >= 0) { FILELIST thisList; theList.push_back(thisList); list<FILELIST>::iterator it = theList.end(); it--; (*it).path = path; do { if( (data.attrib & _A_SUBDIR) ) { // make sure we skip "." and "..". Have to use strcmp here because // some file names can start with a dot, so just testing for the // first dot is not suffient. if( strcmp(data.name,".") != 0 &&strcmp(data.name,"..") != 0) { // We found a sub-directory, so get the files in it too fname = path + "\\" + data.name; // recurrsion here! TransverseDirectory(fname,theList); } } else { // this is just a normal filename. So just add it to our vector (*it).theList.push_back(data.name); } }while( _findnexti64(h,&data) == 0); _findclose(h); } } int main( int argc, char **argv ) { list<FILELIST> MyList; string path; ClientUser ui; ClientApi client; StrBuf msg; Error e; if(argc < 4) { fprintf( stderr , "P4 Transverse Add: Arguments Error!\n"); return -1; } client.SetPort(argv[1]); client.SetClient(argv[2]); client.SetTrans(CharSetApi::UTF_8 , CharSetApi::UTF_8 , CharSetApi::UTF_8, CharSetApi::UTF_8); TransverseDirectory(argv[3],MyList); // Connect to server client.Init( &e ); if( e.Test() ) { e.Fmt( &msg ); fprintf( stderr, "%s\n", msg.Text() ); return -1; } list<FILELIST>::iterator it; for(it = MyList.begin(); it != MyList.end(); it++) { vector<string>::iterator its; for(its = (*it).theList.begin(); its != (*it).theList.end(); its++) { path = (*it).path + "\\" + (*its); char* pText = ANSIToUTF8(path.c_str()); client.SetArgv( 1 , &pText); client.Run( "add" , &ui ); } } // Close connection client.Final( &e ); if( e.Test() ) { e.Fmt( &msg ); fprintf( stderr, "%s\n", msg.Text() ); return -1; } return 0; }
此方法省去了创建p4进程的开销,任务执行效率会提高不少,而且也不会出现执行结果不稳定的问题。
附一:SDK下载地址
ftp://ftp.perforce.com/perforce/
附二:附上ANSI转UTF-8代码
wchar_t* ANSIToUnicode( const char* str ) { int textlen ; wchar_t * result; textlen = MultiByteToWideChar( CP_ACP, 0, str,-1, NULL,0 ); result = (wchar_t *)malloc((textlen+1)*sizeof(wchar_t)); memset(result,0,(textlen+1)*sizeof(wchar_t)); MultiByteToWideChar(CP_ACP, 0,str,-1,(LPWSTR)result,textlen ); return result; } char* UnicodeToANSI( const wchar_t *str ) { char * result; int textlen; // wide char to multi char textlen = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL ); result =(char *)malloc((textlen+1)*sizeof(char)); memset( result, 0, sizeof(char) * ( textlen + 1 ) ); WideCharToMultiByte( CP_ACP, 0, str, -1, result, textlen, NULL, NULL ); return result; } wchar_t* UTF8ToUnicode( const char* str ) { int textlen ; wchar_t * result; textlen = MultiByteToWideChar( CP_UTF8, 0, str,-1, NULL,0 ); result = (wchar_t *)malloc((textlen+1)*sizeof(wchar_t)); memset(result,0,(textlen+1)*sizeof(wchar_t)); MultiByteToWideChar(CP_UTF8, 0,str,-1,(LPWSTR)result,textlen ); return result; } char* UnicodeToUTF8( const wchar_t *str ) { char * result; int textlen; // wide char to multi char textlen = WideCharToMultiByte( CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL ); result =(char *)malloc((textlen+1)*sizeof(char)); memset(result, 0, sizeof(char) * ( textlen + 1 ) ); WideCharToMultiByte( CP_UTF8, 0, str, -1, result, textlen, NULL, NULL ); return result; } char* ANSIToUTF8(const char* str) { wchar_t* pUnicodeBuff = ANSIToUnicode(str); char* pUtf8Buff = UnicodeToUTF8(pUnicodeBuff); free(pUnicodeBuff); return pUtf8Buff; }