tar.gz
文章目录
- 现象
- 原因与分析
- 解决办法
- 第一步
- 第二步
- 代码
- 测试结果
现象
.tar.gz文件是linux下标准的打包+压缩格式。
在windows下处理时,发现一个小问题。
比如一个400MB的压缩包xxxx.tar.gz。
- 步骤1,通过采集并解压,得到8000MB的xxxx.tar文件。
- 步骤2,通过文件解压缩(7z),得到8000MB的多个解后文件。
过程中不仅临时所需空间大(需要8000MB+8000MB),而且速度比较慢。
原因与分析
简单说就是未能一次解压,将.tar.gz分成了2步解压导致。
经过测试,Winrar可以一次解压,可以通过调用Winrar简单实现。
但是Winrar是商业软件,客户如未购买,则无法在服务器上安装。
解决办法
第一步
安装cygwin(windows下使用的Linux开源工具)
官方解释:a large collection of GNU and Open Source tools which provide functionality similar to a Linux distribution on Windows.
具体安装配置过程请参考其它文档。
第二步
修改程序代码,使其可以兼容调用winrar, 7z, tar(cygwin)…
代码
下述代码包括可以选择调用
- Winrar(如果客户购买了)
- 7z
- linux 的 tar(cygwin)
全部三种方式,并考虑了错误信息输出等。
同时也考虑了服务程序处于0层无法调用外部exe的问题。
所以有点长。。。呵呵。
函数 DeCompressExternalAll 是功能入口。
char* ColThread::GetLastERRORmessage(String aCaption)
{
char ErrorMsg[512];
Dword dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM, NULL, dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &ErrorMsg,
512, NULL );
return (aCaption+":("+IntToStr(dw)+")"+String(ErrorMsg)).c_str();
}
int ColThread::DeCompressExternalAll(String AFileName,String aDestPath)
{
String CMDRet="";
String cmdline;
int result = -1;
bool isRetMsg=false;
if (EXEType==0)
{
isRetMsg=true;
cmdline = String("7z -y x -o" ) + aDestPath + " " + AFileName;
/*
//无法使用7z的重定向标准输入输出功能一次性解压Tar.gz
String DualDecCmdline = String("7z x ")+AFileName+" -so | 7z x -si -ttar -o"+aDestPath;
if (AnsiEndsText(".TAR.GZ",AFileName))
cmdline=DualDecCmdline;
*/
}
else if (EXEType==1)
{
isRetMsg=false;
cmdline = String("winrar x -ibck -inul -ilog")+ aDestPath +"wrerr.log " + AFileName + " " + aDestPath;
}
else if (EXEType==2)
{
isRetMsg=true;
if ((UpperCase(RightStr(AFileName, 7))==".TAR.GZ") || (UpperCase(RightStr(AFileName, 4))==".TGZ"))
{
cmdline = String("tar -zxf " ) + extractFileName(AFileName) + " -C " + aDestPath;
}
else
{
OutAlarm("File type not supported!");
return result;
}
TReplaceFlags FLG;
FLG<<rfReplaceAll<<rfignoreCase;
cmdline=StringReplace(cmdline, "\\", "\\\\",FLG);
}
else
{
OutAlarm("解压程序类型配置无法识别!");
return -1;
}
SetCurrentDir(extractfilepath(AFileName));
bool UserLvlOK=false;
handle hRead, hWrite;
if (isRetMsg)
{//需要打开管道读取返回文本信息并关闭。
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof( SECURITY_ATTRIBUTES );
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
if ( !CreatePipe( &hRead, &hWrite, &sa, 0 ) )
{
AlarmList->Add(GetLastErrorMessage("用户层::CreatePipe"));
result=-1;
}
}
STARTUPINFO StartupInfo;
zeromemory( & StartupInfo, sizeof( STARTUPINFO ) );
StartupInfo.cb = sizeof( STARTUPINFO );
StartupInfo.wShowWindow = SW_HIDE;
if (isRetMsg)
{//需要打开管道读取返回文本信息并关闭。
//StartupInfo.hStdInput = hRead;
StartupInfo.hStdError = hWrite;
StartupInfo.hStdOutput = hWrite;
}
StartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
PROCESS_INFORMATION ProcessInfo;
ZeroMemory( & ProcessInfo, sizeof( PROCESS_INFORMATION ) );
if ( !createprocess( NULL, cmdline.c_str( ),NULL, NULL, TRUE, NORMAL_priority_CLASS | CREATE_NEW_console |
CREATE_unicode_environment, NULL, NULL, &StartupInfo,&ProcessInfo ) )
{
AlarmList->Add(GetLastErrorMessage("用户层:CreateProcess"));
if (isRetMsg)
{//需要打开管道读取返回文本信息并关闭。
CloseHandle( hWrite );
CloseHandle( hRead );
}
CloseHandle( ProcessInfo.hThread );
CloseHandle( ProcessInfo.hProcess );
}
else
{
result = 0;
UserLvlOK=true;
if (isRetMsg)
{//需要打开管道读取返回文本信息并关闭。
CloseHandle( hWrite );
char buffer[ 65536 ] ={0} ;
dword bytesRead;
while ( true )
{
bytesRead = 0;
if ( ReadFile( hRead, buffer, 65535, &bytesRead,
NULL ) == NULL )
{
break;
}
buffer[ bytesRead ] = 0;
OemToAnsi( buffer, buffer );
CMDRet = CMDRet + String( buffer );
}
}
if (WaitForSingleObject(ProcessInfo.hProcess, INFINITE)!= WAIT_failed)
{
DWORD exitCode;
if (GetExitCodeProcess(ProcessInfo.hProcess,&exitCode))
{
if (EXEType==0)
result = CheckExitCode7z(exitCode);
else if (EXEType==1)
result = CheckExitCodeWinRAR(exitCode);
else if (EXEType==2)
result = CheckExitCodeLinux(exitCode);
}
else
{
AlarmList->Add(GetLastErrorMessage("用户层:无法取得退出代码!"));
result = -1;
}
}
else
{
AlarmList->Add(GetLastErrorMessage("用户层:waitforSingleObject"));
result = -1;
}
if (isRetMsg)
{//需要打开管道读取返回文本信息并关闭。
CloseHandle( hRead );
}
CloseHandle( ProcessInfo.hThread );
CloseHandle( ProcessInfo.hProcess );
}
if ((!UserLvlOK) && ( result <0 ))
{
PWTS_session_INFO ppSessionInfo;
DWORD pCount;
if ( WTSEnumerateSessions( WTS_CURRENT_SERVER_HANDLE, 0, 1, &ppSessionInfo,&pCount ) )
{
for ( DWORD ConsoleSessionId = 0; ConsoleSessionId < pCount;
ConsoleSessionId++ )
{
char * LEMsg;
unsigned long aCSID = ppSessionInfo[ ConsoleSessionId ].SessionId;
//OutMessage("第"+IntToStr(ConsoleSessionId)+"个会话编号"+IntToStr(aCSID)+");
if (isRetMsg)
{//需要打开管道读取返回文本信息并关闭。
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof( SECURITY_ATTRIBUTES );
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
if ( !CreatePipe( &hRead, &hWrite, &sa, 0 ) )
{
AlarmList->Add(GetLastErrorMessage("第"+IntToStr(ConsoleSessionId)+"个会话编号"+IntToStr(aCSID)+":CreatePipe"));
result=-1;
}
}
STARTUPINFO StartupInfo;
ZeroMemory( & StartupInfo, sizeof( STARTUPINFO ) );
StartupInfo.cb = sizeof( STARTUPINFO );
StartupInfo.wShowWindow = SW_HIDE;
if (isRetMsg)
{//需要打开管道读取返回文本信息并关闭。
//StartupInfo.hStdInput = hRead;
StartupInfo.hStdError = hWrite;
StartupInfo.hStdOutput = hWrite;
}
StartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
PROCESS_INFORMATION ProcessInfo;
ZeroMemory( & ProcessInfo, sizeof( PROCESS_INFORMATION ) );
HANDLE hToken = NULL;
if ( WTSQueryUserToken( aCSID, &hToken ) == FALSE )
{
AlarmList->Add(GetLastErrorMessage("第"+IntToStr(ConsoleSessionId)+"个会话编号"+IntToStr(aCSID)+":QueryUserToken"));
continue;
}
HANDLE hDuplicatedToken = NULL;
if ( DuplicateTokenEx( hToken, MAXIMUM_ALLOWED, NULL,SecurityIdentification, TokenPrimary, &hDuplicatedToken )== FALSE )
{
AlarmList->Add(GetLastErrorMessage("第"+IntToStr(ConsoleSessionId)+"个会话编号"+IntToStr(aCSID)+":DuplicateTokenEx"));
if ( hToken != NULL )
{
CloseHandle( hToken );
}
continue;
}
LPVOID lpEnvironment = NULL;
if ( CreateEnvironmentBlock( &lpEnvironment, hDuplicatedToken,FALSE ) == FALSE )
{
AlarmList->Add(GetLastErrorMessage("第"+IntToStr(ConsoleSessionId)+"个会话编号"+IntToStr(aCSID)+":CreateEnvironmentBlock"));
if ( hToken != NULL )
{
CloseHandle( hToken );
}
if ( hDuplicatedToken != NULL )
{
CloseHandle( hDuplicatedToken );
}
continue;
}
if ( !createprocessasuser( hDuplicatedToken, NULL, cmdline.c_str( ),NULL, NULL, TRUE,
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE |
CREATE_UNICODE_ENVIRONMENT, lpEnvironment, NULL, &StartupInfo,
&ProcessInfo ) )
{
AlarmList->Add(GetLastErrorMessage("第"+IntToStr(ConsoleSessionId)+"个会话编号"+IntToStr(aCSID)+":CreateProcessAsUser"));
if (isRetMsg)
{//需要打开管道读取返回文本信息并关闭。
CloseHandle( hWrite );
CloseHandle( hRead );
}
CloseHandle( ProcessInfo.hThread );
CloseHandle( ProcessInfo.hProcess );
if ( hToken != NULL )
{
CloseHandle( hToken );
}
if ( hDuplicatedToken != NULL )
{
CloseHandle( hDuplicatedToken );
}
if ( lpEnvironment != NULL )
{
DestroyEnvironmentBlock( hDuplicatedToken );
}
continue;
}
if (isRetMsg)
{//需要打开管道读取返回文本信息并关闭。
CloseHandle( hWrite );
}
if ( hToken != NULL )
{
CloseHandle( hToken );
}
if ( hDuplicatedToken != NULL )
{
CloseHandle( hDuplicatedToken );
}
if ( lpEnvironment != NULL )
{
DestroyEnvironmentBlock( lpEnvironment );
}
result = 0;
if (isRetMsg)
{//需要打开管道读取返回文本信息并关闭。
char buffer[ 165536 ] ={0} ;
DWORD bytesRead;
while ( true )
{
bytesRead = 0;
if ( ReadFile( hRead, buffer, 165535, &bytesRead,
NULL ) == NULL )
{
break;
}
buffer[ bytesRead ] = 0;
OemToAnsi( buffer, buffer );
CMDRet = CMDRet + String( buffer );
Sleep( 10 );
}
}
if (WaitForSingleObject(ProcessInfo.hProcess, INFINITE)!= WAIT_FAILED)
{
DWORD exitCode;
if (GetExitCodeProcess(ProcessInfo.hProcess,&exitCode))
{
if (EXEType==0)
result = CheckExitCode7z(exitCode);
else if (EXEType==1)
result = CheckExitCodeWinRAR(exitCode);
else if (EXEType==2)
result = CheckExitCodeLinux(exitCode);
}
else
{
AlarmList->Add(GetLastErrorMessage("第"+IntToStr(ConsoleSessionId)+"个会话编号"+IntToStr(aCSID)+":无法取得退出代码"));
result = -1;
}
}
else
{
AlarmList->Add(GetLastErrorMessage("第"+IntToStr(ConsoleSessionId)+"个会话编号"+IntToStr(aCSID)+":WaitForSingleObject"));
result = -1;
}
if (isRetMsg)
{//需要打开管道读取返回文本信息并关闭。
CloseHandle( hRead );
}
CloseHandle( ProcessInfo.hThread );
CloseHandle( ProcessInfo.hProcess );
break;
}
WTSFreeMemory( ppSessionInfo );
}
else
{
AlarmList->Add(GetLastErrorMessage("WTSEnumerateSessions"));
}
}
if (result != 0)
for (int i=0;i<AlarmList->Count;i++)
{
OutAlarm(AlarmList->Strings[i]);
}
if (EXEType==0)
OutputMsg7z(CMDRet);
else if (EXEType==1)
OutputMsgWinRAR(aDestPath);
else if (EXEType==2)
OutputMsgLinux(CMDRet);
SetCurrentDir(aDestPath);
return result;
}
//---------------------------------------------------------------------------
int ColThread::CheckExitCode7z(int exitCode)
{
int result=0;
if (exitCode==STILL_ACTIVE)
{
AlarmList->Add("退出代码:STILL_ACTIVE。");
}
else if (exitCode==0) //No error
{
;//OutMessage("7Z执行成功完成.");
}
else if (exitCode==1) //Warning (Non fatal error(s)). For example, one or more files were locked by some other APPlication, so they were not compressed.
{
AlarmList->Add("退出代码:Warning (Non fatal error(s))。");
// 7Z待解压的文件不是压缩文件时,返回的是致命错误,非致命错误不用报错。
}
else if (exitCode==2) //Fatal error
{
AlarmList->Add("退出代码:Fatal error。");
result = -1;
}
else if (exitCode==7) // command line error
{
AlarmList->Add("退出代码:Command line error。");
result = -1;
}
else if (exitCode==8) //Not enough memory for operation
{
AlarmList->Add("退出代码:Not enough memory for operation。");
result = -1;
}
else if (exitCode==255) //User stopped the process
{
AlarmList->Add("退出代码:User stopped the process。");
result = -1;
}
else
{
AlarmList->Add("未知的退出代码("+IntToStr(exitCode)+")。");
result = -1;
}
return result;
}
int ColThread::CheckExitCodeWinRAR(int exitCode)
{
int result=0;
if (exitCode==STILL_ACTIVE)
{
AlarmList->Add("退出代码:STILL_ACTIVE。");
}
else if (exitCode==0) //No error
{
}
else if (exitCode==1)// 警告。发生非致命错误。
{
AlarmList->Add("警告,发生非致命错误。");
result = -1; // WinRAR待解压的文件不是压缩文件时,返回的是非致命错误,需要报错。
}
else if (exitCode==2)// 发生致命错误。
{
AlarmList->Add("发生致命错误!");
result = -1;
}
else if (exitCode==3)// 无效校验和。数据损坏。。
{
AlarmList->Add("无效校验和。数据损坏!");
result = -1;
}
else if (exitCode==4)// 尝试修改一个锁定的压缩文件。
{
AlarmList->Add("尝试修改一个锁定的压缩文件!");
result = -1;
}
else if (exitCode==5)// 写错误。
{
AlarmList->Add("写错误!");
result = -1;
}
else if (exitCode==6)// 文件打开错误。
{
AlarmList->Add("文件打开错误!");
result = -1;
}
else if (exitCode==7)// 错误命令行选项。
{
AlarmList->Add("错误命令行选项!");
result = -1;
}
else if (exitCode==8)// 内存不足。
{
AlarmList->Add("内存不足!");
result = -1;
}
else if (exitCode==9)// 文件创建错误。
{
AlarmList->Add("文件创建错误!");
result = -1;
}
else if (exitCode==10)// 没有找到与指定的掩码和选项匹配的文件。
{
AlarmList->Add("没有找到与指定的掩码和选项匹配的文件!");
result = -1;
}
else if (exitCode==11)// 密码错误。
{
AlarmList->Add("密码错误!");
result = -1;
}
else if (exitCode==255)// 用户中断。
{
AlarmList->Add("用户中断!");
result = -1;
}
else
{
AlarmList->Add("未知的退出代码("+IntToStr(exitCode)+")。");
result = -1;
}
return result;
}
int ColThread::CheckExitCodeLinux(int exitCode)
{
int result=0;
if (exitCode==STILL_ACTIVE)
{
AlarmList->Add("退出代码:STILL_ACTIVE。");
}
else if (exitCode==0) //No error
{
}
else if (exitCode==1)// 警告。发生非致命错误。
{
AlarmList->Add("警告,发生非致命错误。");
}
else if (exitCode==2)// 发生致命错误。
{
AlarmList->Add("发生致命错误!");
result = -1;
}
else
{
AlarmList->Add("未知的退出代码("+IntToStr(exitCode)+")。");
result = -1;
}
return result;
}
//---------------------------------------------------------------------------
void ColThread::OutputMsg7z(String CMDRet)
{
int i;
int progress=1;
String aMessage;
while ((i = CMDRet.UpperCase().substring(Progress,CMDRet.Length()).Pos("ERROR:"))>0)
{
i=i+Progress-1;
aMessage="";
while (i<CMDRet.Length()-1)
{
if ((CMDRet[i]=='\n') || (CMDRet[i]=='\r') )
{
aMessage=aMessage+' ';
if ((CMDRet[i]=='\n') && (CMDRet[i+1]=='\r'))
{
break;
}
}
else
{
aMessage=aMessage+CMDRet[i];
}
i++;
}
Progress=i;
OutAlarm(aMessage);
}
Progress=1;
while ((i = CMDRet.UpperCase().SubString(Progress,CMDRet.Length()).Pos("WARNING:"))>0)
{
i=i+Progress-1;
aMessage="";
while (i<CMDRet.Length()-1)
{
if ((CMDRet[i]=='\n') || (CMDRet[i]=='\r') )
{
aMessage=aMessage+' ';
if ((CMDRet[i]=='\n') && (CMDRet[i+1]=='\r'))
{
break;
}
}
else
{
aMessage=aMessage+CMDRet[i];
}
i++;
}
Progress=i;
OutAlarm(aMessage);
}
}
void ColThread::OutputMsgWinRAR(String OutPath)
{
String SingleLineMsg="";
WideString errlogstr;
if (Fileexists(OutPath+"wrerr.log"))
{
TMemoryStream *aMS= new TMemoryStream();
aMS->LoadFromFile(OutPath+"wrerr.log");
errlogstr.SetLength(1);
aMS->Read(errlogstr,2);
if (errlogstr[1]==0xfeff)
{
errlogstr.SetLength((aMS->Size-2)/2);
aMS->Read(errlogstr,(aMS->Size-2));
SingleLineMsg=String(errlogstr);
TReplaceFlags FLG;
FLG<<rfReplaceAll<<rfIgnoreCase;
SingleLineMsg=StringReplace(SingleLineMsg, "\n", " ",FLG);
SingleLineMsg=StringReplace(SingleLineMsg, "\r", " ",FLG);
OutAlarm(SingleLineMsg);
}
delete aMS;
aMS=NULL;
DeleteFile(OutPath+"wrerr.log");
}
}
void ColThread::OutputMsgLinux(String CMDRet)
{
TReplaceFlags FLG;
FLG<<rfReplaceAll<<rfIgnoreCase;
String SingleLineMsg=StringReplace(CMDRet, "\n", " ",FLG);
SingleLineMsg=StringReplace(SingleLineMsg, "\r", " ",FLG);
SingleLineMsg=Trim(SingleLineMsg);
if (SingleLineMsg!="")
OutAlarm(SingleLineMsg);
}
测试结果
调用Winrar可以一次解压,速度较快。
调用7z需要两次解压(不就是要解决这个问题么???)。
调用tar可以一次解压,速度比Winrar稍慢。
相关阅读
Windows: 第一步,修改注册表项 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\Wds\rdpwd\Tds\tc
linux目录 1.tar解压缩 核心命令 这五个命令是比较重要的核心命令,包含了对解压缩的所有操作,有且只能选择其中一个。 命令
windows中的快捷键(全)(附:新建文件夹的快捷键归纳)
常用快捷键1、窗口操作中的快捷键F1 帮助F5 在当前打开的记事本中插入当前的系统时间F10 激活菜单Alt+F4 关闭当前窗口或退出
最近在研究iphone手机备份的问题,在使用itunes给手机备份的时候,发现C盘空间不够用了,于是想把itunes的默认存储路径修改一下,在网上
Windows 8.1如何完美激活(不用重启), 亲测无病毒
https://jingyan.baidu.com/article/3065b3b6a19d91becff8a4f2.html