最近项目需要解压缩rar文件,我们都知道rar是闭源收费软件,如果直接采用命令行可能会有限制,或者盗版问题,使用正版的winrar命令行解压rar文件是否有限制,这个我没来得及测试,但是从交互体验上来说,命令行对于很多情况的处理也不太友好,比如是否出错,比如异常处理,甚至某些高级功能,比如自定义解压缩的文件名等等,这些在命令行中不太好实现甚至无法实现。
网上很多关于c++解压rar的代码都是基于命令行的,这不是我想要的。
我想找能够解压rar的库或者dll,经过一番寻找,发现rarlab官网已经提供了UnRAR64,可以直接下载运行,这里提供一下下载地址:https://www.rarlab.com/rar/unrardll-624.exe
https://www.rarlab.com/rar/unrardll-624.exe
其他版本在这个页面:WinRAR archiver, a powerful tool to process RAR and ZIP files
https://www.rarlab.com/rar_add.htm
使用官方的例子,即可实现winrar的解压缩,不过为了方便使用,我拓展了一下官方的代码,可以实现列出文件和解压缩rar文件到指定的目录,修改比较简单,这里直接上代码:
- #pragma once
-
-
- #include
- #include
- #include
- #include
- #include
-
- #include "unrar.h"
-
- enum { EXTRACT, TEST, PRINT, LIST };
-
- int CommandLine(int Argc, char *Argv[]);
-
- void ExtractArchive(char *ArcName,int Mode);
- void ExtractArchive(char *ArcName, char* DstDir);
- void ListArchive(char *ArcName);
- size_t ListArchive(char *ArcName, std::vector
& vFiles) ; - void ShowComment(wchar_t *CmtBuf);
- void OutHelp(void);
-
- enum ERR_TYPE {ERR_OPEN, ERR_READ, ERR_PROCESS};
- void OutError(int Error,char *ArcName,int ErrType);
-
- void ShowArcInfo(unsigned int Flags,char *ArcName);
- void PrintTime(const char *Label,unsigned int Low,unsigned int High);
- void OutProcessFileError(int Error);
- int CALLBACK CallbackProc(UINT msg,LPARAM UserData,LPARAM P1,LPARAM P2);
实现文件:
- #define STRICT
-
- #include "UnRDLL.h"
-
- int CommandLine(int Argc, char *Argv[])
- {
- setlocale(LC_ALL, NULL);
-
- if (Argc!=3)
- {
- OutHelp();
- return(0);
- }
-
- switch(toupper(Argv[1][0]))
- {
- case 'X':
- ExtractArchive(Argv[2],EXTRACT);
- break;
- case 'T':
- ExtractArchive(Argv[2],TEST);
- break;
- case 'P':
- ExtractArchive(Argv[2],PRINT);
- break;
- case 'L':
- ListArchive(Argv[2]);
- break;
- default:
- OutHelp();
- return(0);
- }
-
- return(0);
- }
-
-
- void ExtractArchive(char *ArcName,int Mode)
- {
- HANDLE hArcData;
- int RHCode,PFCode;
- wchar_t CmtBuf[16384];
- struct RARHeaderData HeaderData;
- struct RAROpenArchiveDataEx OpenArchiveData;
-
- memset(&HeaderData,0,sizeof(HeaderData));
- memset(&OpenArchiveData,0,sizeof(OpenArchiveData));
-
- OpenArchiveData.ArcName=ArcName;
- OpenArchiveData.CmtBufW=CmtBuf;
- OpenArchiveData.CmtBufSize=sizeof(CmtBuf)/sizeof(CmtBuf[0]);
- OpenArchiveData.OpenMode=RAR_OM_EXTRACT;
- OpenArchiveData.Callback=CallbackProc;
- OpenArchiveData.UserData=Mode;
- hArcData=RAROpenArchiveEx(&OpenArchiveData);
-
- if (OpenArchiveData.OpenResult!=0)
- {
- OutError(OpenArchiveData.OpenResult,ArcName,ERR_OPEN);
- return;
- }
-
- ShowArcInfo(OpenArchiveData.Flags,ArcName);
-
- if (OpenArchiveData.CmtState==1)
- ShowComment(CmtBuf);
-
- while ((RHCode=RARReadHeader(hArcData,&HeaderData))==0)
- {
- switch(Mode)
- {
- case EXTRACT:
- printf("\nExtracting %-45s",HeaderData.FileName);
- break;
- case TEST:
- printf("\nTesting %-45s",HeaderData.FileName);
- break;
- case PRINT:
- printf("\nPrinting %-45s\n",HeaderData.FileName);
- break;
- }
- PFCode=RARProcessFile(hArcData,(Mode==EXTRACT) ? RAR_EXTRACT:RAR_TEST,
- NULL,NULL);
- if (PFCode==0)
- printf(" OK");
- else
- {
- OutError(PFCode,ArcName,ERR_PROCESS);
- break;
- }
- }
-
- OutError(RHCode,ArcName,ERR_READ);
-
- RARCloseArchive(hArcData);
- }
-
-
- void ExtractArchive(char *ArcName, char* DstDir)
- {
- HANDLE hArcData;
- int RHCode,PFCode;
- wchar_t CmtBuf[16384];
- struct RARHeaderData HeaderData;
- struct RAROpenArchiveDataEx OpenArchiveData;
-
- memset(&HeaderData,0,sizeof(HeaderData));
- memset(&OpenArchiveData,0,sizeof(OpenArchiveData));
-
- OpenArchiveData.ArcName=ArcName;
- OpenArchiveData.CmtBufW=CmtBuf;
- OpenArchiveData.CmtBufSize=sizeof(CmtBuf)/sizeof(CmtBuf[0]);
- OpenArchiveData.OpenMode=RAR_OM_EXTRACT;
- OpenArchiveData.Callback=CallbackProc;
- OpenArchiveData.UserData= EXTRACT;
- hArcData=RAROpenArchiveEx(&OpenArchiveData);
-
- if (OpenArchiveData.OpenResult!=0)
- {
- OutError(OpenArchiveData.OpenResult,ArcName,ERR_OPEN);
- return;
- }
-
- ShowArcInfo(OpenArchiveData.Flags,ArcName);
-
- if (OpenArchiveData.CmtState==1)
- ShowComment(CmtBuf);
-
- while ((RHCode=RARReadHeader(hArcData,&HeaderData))==0)
- {
- printf("\nExtracting %-45s",HeaderData.FileName);
- PFCode=RARProcessFile(hArcData,RAR_EXTRACT,DstDir,NULL);
- if (PFCode==0)
- printf(" OK");
- else
- {
- OutError(PFCode,ArcName,ERR_PROCESS);
- break;
- }
- }
-
- OutError(RHCode,ArcName,ERR_READ);
-
- RARCloseArchive(hArcData);
- }
-
- size_t ListArchive(char *ArcName, std::vector
& vFiles) - {
- HANDLE hArcData;
- int RHCode,PFCode;
- wchar_t CmtBuf[16384];
- struct RARHeaderDataEx HeaderData;
- struct RAROpenArchiveDataEx OpenArchiveData;
- wchar_t RedirName[1024];
-
- memset(&HeaderData,0,sizeof(HeaderData));
- memset(&OpenArchiveData,0,sizeof(OpenArchiveData));
- OpenArchiveData.ArcName=ArcName;
- OpenArchiveData.CmtBufW=CmtBuf;
- OpenArchiveData.CmtBufSize=sizeof(CmtBuf)/sizeof(CmtBuf[0]);
- OpenArchiveData.OpenMode=RAR_OM_LIST;
- OpenArchiveData.Callback=CallbackProc;
- OpenArchiveData.UserData=LIST;
- hArcData=RAROpenArchiveEx(&OpenArchiveData);
-
- if (OpenArchiveData.OpenResult!=0)
- {
- OutError(OpenArchiveData.OpenResult,ArcName,ERR_OPEN);
- return 0;
- }
-
- ShowArcInfo(OpenArchiveData.Flags,ArcName);
-
- if (OpenArchiveData.CmtState==1)
- ShowComment(CmtBuf);
-
- HeaderData.RedirName=RedirName;
- HeaderData.RedirNameSize=sizeof(RedirName)/sizeof(RedirName[0]);
- while ((RHCode=RARReadHeaderEx(hArcData,&HeaderData))==0)
- {
- __int64 UnpSize=HeaderData.UnpSize+(((__int64)HeaderData.UnpSizeHigh)<<32);
- __int64 PackSize=HeaderData.PackSize+(((__int64)HeaderData.PackSizeHigh)<<32);
- printf("\nName: %s",HeaderData.FileName);
-
- vFiles.push_back(HeaderData.FileName);
-
- printf("\nSize: %lld ",UnpSize);
- printf("\nPacked: %lld ",PackSize);
-
- PrintTime("mtime",HeaderData.MtimeLow,HeaderData.MtimeHigh);
- PrintTime("ctime",HeaderData.CtimeLow,HeaderData.CtimeHigh);
- PrintTime("atime",HeaderData.AtimeLow,HeaderData.AtimeHigh);
-
- if (HeaderData.RedirType!=0)
- printf("\n\tlink type %d, target %ls",HeaderData.RedirType,HeaderData.RedirName);
- if ((PFCode=RARProcessFile(hArcData,RAR_SKIP,NULL,NULL))!=0)
- {
- OutError(PFCode,ArcName,ERR_PROCESS);
- break;
- }
- printf("\n");
- }
-
- OutError(RHCode,ArcName,ERR_READ);
-
- RARCloseArchive(hArcData);
-
- return vFiles.size();
- }
-
- void ListArchive(char *ArcName)
- {
- HANDLE hArcData;
- int RHCode,PFCode;
- wchar_t CmtBuf[16384];
- struct RARHeaderDataEx HeaderData;
- struct RAROpenArchiveDataEx OpenArchiveData;
- wchar_t RedirName[1024];
-
- memset(&HeaderData,0,sizeof(HeaderData));
- memset(&OpenArchiveData,0,sizeof(OpenArchiveData));
- OpenArchiveData.ArcName=ArcName;
- OpenArchiveData.CmtBufW=CmtBuf;
- OpenArchiveData.CmtBufSize=sizeof(CmtBuf)/sizeof(CmtBuf[0]);
- OpenArchiveData.OpenMode=RAR_OM_LIST;
- OpenArchiveData.Callback=CallbackProc;
- OpenArchiveData.UserData=LIST;
- hArcData=RAROpenArchiveEx(&OpenArchiveData);
-
- if (OpenArchiveData.OpenResult!=0)
- {
- OutError(OpenArchiveData.OpenResult,ArcName,ERR_OPEN);
- return;
- }
-
- ShowArcInfo(OpenArchiveData.Flags,ArcName);
-
- if (OpenArchiveData.CmtState==1)
- ShowComment(CmtBuf);
-
- HeaderData.RedirName=RedirName;
- HeaderData.RedirNameSize=sizeof(RedirName)/sizeof(RedirName[0]);
- while ((RHCode=RARReadHeaderEx(hArcData,&HeaderData))==0)
- {
- __int64 UnpSize=HeaderData.UnpSize+(((__int64)HeaderData.UnpSizeHigh)<<32);
- __int64 PackSize=HeaderData.PackSize+(((__int64)HeaderData.PackSizeHigh)<<32);
- printf("\nName: %s",HeaderData.FileName);
- printf("\nSize: %lld ",UnpSize);
- printf("\nPacked: %lld ",PackSize);
-
- PrintTime("mtime",HeaderData.MtimeLow,HeaderData.MtimeHigh);
- PrintTime("ctime",HeaderData.CtimeLow,HeaderData.CtimeHigh);
- PrintTime("atime",HeaderData.AtimeLow,HeaderData.AtimeHigh);
-
- if (HeaderData.RedirType!=0)
- printf("\n\tlink type %d, target %ls",HeaderData.RedirType,HeaderData.RedirName);
- if ((PFCode=RARProcessFile(hArcData,RAR_SKIP,NULL,NULL))!=0)
- {
- OutError(PFCode,ArcName,ERR_PROCESS);
- break;
- }
- printf("\n");
- }
-
- OutError(RHCode,ArcName,ERR_READ);
-
- RARCloseArchive(hArcData);
- }
-
-
- void ShowComment(wchar_t *CmtBuf)
- {
- printf("\nComment:\n%ls\n",CmtBuf);
- }
-
-
- void OutHelp(void)
- {
- printf("\nUNRDLL. This is a simple example of UNRAR.DLL usage\n");
- printf("\nSyntax:\n");
- printf("\nUNRDLL X
extract archive contents" ); - printf("\nUNRDLL T
test archive contents" ); - printf("\nUNRDLL P
print archive contents to stdout" ); - printf("\nUNRDLL L
view archive contents\n" ); - }
-
-
- void OutError(int Error,char *ArcName,int ErrType)
- {
- switch(Error)
- {
- case ERAR_NO_MEMORY:
- printf("\nNot enough memory");
- break;
- case ERAR_BAD_DATA:
- printf("\n%s: archive header or data are damaged",ArcName);
- break;
- case ERAR_BAD_ARCHIVE:
- printf("\n%s is not RAR archive",ArcName);
- break;
- case ERAR_UNKNOWN_FORMAT:
- printf("Unknown archive format");
- break;
- case ERAR_EOPEN:
- if (ErrType==ERR_PROCESS) // Returned by RARProcessFile.
- printf("Volume open error");
- else
- printf("\nCannot open %s",ArcName);
- break;
- case ERAR_ECREATE:
- printf("File create error");
- break;
- case ERAR_ECLOSE:
- printf("File close error");
- break;
- case ERAR_EREAD:
- printf("Read error");
- break;
- case ERAR_EWRITE:
- printf("Write error");
- break;
- case ERAR_SMALL_BUF:
- printf("Buffer for archive comment is too small, comment truncated");
- break;
- case ERAR_UNKNOWN:
- printf("Unknown error");
- break;
- case ERAR_MISSING_PASSWORD:
- printf("Password for encrypted file or header is not specified");
- break;
- case ERAR_EREFERENCE:
- printf("Cannot open file source for reference record");
- break;
- case ERAR_BAD_PASSWORD:
- printf("Wrong password is specified");
- break;
- }
- }
-
-
- void ShowArcInfo(unsigned int Flags,char *ArcName)
- {
- printf("\nArchive %s\n",ArcName);
- printf("\nVolume:\t\t%s",(Flags & 1) ? "yes":"no");
- printf("\nComment:\t%s",(Flags & 2) ? "yes":"no");
- printf("\nLocked:\t\t%s",(Flags & 4) ? "yes":"no");
- printf("\nSolid:\t\t%s",(Flags & 8) ? "yes":"no");
- printf("\nNew naming:\t%s",(Flags & 16) ? "yes":"no");
- printf("\nRecovery:\t%s",(Flags & 64) ? "yes":"no");
- printf("\nEncr.headers:\t%s",(Flags & 128) ? "yes":"no");
- printf("\nFirst volume:\t%s",(Flags & 256) ? "yes":"no or older than 3.0");
- printf("\n---------------------------\n");
- }
-
-
- void PrintTime(const char *Label,unsigned int Low,unsigned int High)
- {
- if (Low!=0 || High!=0)
- {
- FILETIME ft;
- ft.dwLowDateTime=Low;
- ft.dwHighDateTime=High;
- SYSTEMTIME ust,st;
- FileTimeToSystemTime(&ft,&ust);
- SystemTimeToTzSpecificLocalTime(NULL,&ust,&st);
- printf("\n%s: %u-%02u-%02u %02u:%02u:%02u,%03u",Label,st.wYear,st.wMonth,
- st.wDay,st.wHour,st.wMinute,st.wSecond,st.wMilliseconds);
- }
- }
-
-
- int CALLBACK CallbackProc(UINT msg,LPARAM UserData,LPARAM P1,LPARAM P2)
- {
- switch(msg)
- {
- case UCM_CHANGEVOLUMEW:
- if (P2==RAR_VOL_ASK)
- {
- printf("\n\nVolume %S is required\nPossible options:\n",(wchar_t *)P1);
- printf("\nEnter - try again");
- printf("\n'R' - specify a new volume name");
- printf("\n'Q' - quit");
- printf("\nEnter your choice: ");
- switch(toupper(getchar()))
- {
- case 'Q':
- return(-1);
- case 'R':
- {
- wchar_t *eol;
- printf("\nEnter new name: ");
- fflush(stdin);
-
- // fgetws may fail to read non-English characters from stdin
- // in some compilers. In this case use something more
- // appropriate for Unicode input.
- fgetws((wchar_t *)P1,MAX_PATH,stdin);
-
- eol=wcspbrk((wchar_t *)P1,L"\r\n");
- if (eol!=NULL)
- *eol=0;
- }
- return(1);
- default:
- return(1);
- }
- }
- if (P2==RAR_VOL_NOTIFY)
- printf("\n ... volume %S\n",(wchar_t *)P1);
- return(1);
- case UCM_PROCESSDATA:
- if (UserData==PRINT)
- {
- fflush(stdout);
- fwrite((char *)P1,1,P2,stdout);
- fflush(stdout);
- }
- return(1);
- case UCM_NEEDPASSWORDW:
- {
- wchar_t *eol;
- printf("\nPassword required: ");
-
- // fgetws may fail to read non-English characters from stdin
- // in some compilers. In this case use something more appropriate
- // for Unicode input.
- fgetws((wchar_t *)P1,(int)P2,stdin);
-
- eol=wcspbrk((wchar_t *)P1,L"\r\n");
- if (eol!=NULL)
- *eol=0;
- }
- return(1);
- }
- return(0);
- }