关于Windows环境下处理.tar.gz文件的问题

现象

.tar.gz文件是linux下标准的打包+压缩格式。
在Windows下处理时,发现一个小问题。

  • 情况A,如果是用Winrar解压,可以直接从.tar.gz文件解压出最终结果文件。(没问题)
  • 情况B,如果是7z等其它工具,程序内部,解压则是.tar.gz —> .tar —>最终结果文件。

比如一个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)…

代码

下述代码包括可以选择调用

  1. Winrar(如果客户购买了)
  2. 7z
  3. 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稍慢。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值