[C/C++] 파일 패킹
2022. 1. 6. 16:00ㆍC++
파일들을 하나의 파일로 묶고 푸는 예제.
패킹 파일은,
패킹 파일에 대한 헤더, 패킹된 파일들에 대한 헤더, 실제 패킹된 파일들의 데이터
이렇게 세 구간으로 구분된다.
패킹 파일에 대한 헤더는, 이 파일을 상징하는 iType과 묶인 파일들의 수를 저장한다.
패킹된 파일들에 대한 헤더는 각 패킹된 파일들의 파일 사이즈, 파일의 이름, 실제 데이터 시작 위치(offset)를 저장한다.
이 때, offset을 저장하는 이유는
만약에 패킹 파일 내에서 변경(삭제 / 추가)이 일어났을 때, 중간에 데이터가 비는 부분이 발생할 수 있다.
예를 들어서, 중간 부분에 패킹된 100바이트 용량을 가진 파일이 삭제되고,
이 부분에 90바이트의 용량을 가진 파일이 추가된다면 사이즈로만 뒤의 파일들을 찾을 수 없다.
#include <iostream>
#define FILENAMELENGTH 128
#define PACKTYPE 0x99886655
//----------------------------------
// 패킹 파일 가장 앞 헤더
//----------------------------------
struct st_PACK_HEADER_
{
unsigned int iType; // 0x99886655 이 들어감.
int iFileNum;
};
//----------------------------------
// 내부 파일 정보
//----------------------------------
struct st_PACK_FILEINFO_
{
int iFileSize;
char szFileName[FILENAMELENGTH];
int fileOffset;
};
int main()
{
int i;
int isPack;
int packFileCount;
char* fileNames;
char packFileName[128];
FILE* fp;
FILE* fp2;
//패킹 or 언패킹 선택
printf("패킹 : 1, 언패킹 : 0 입력하세요 : ");
scanf_s("%d", &isPack);
//패킹
if (isPack == 1)
{
//패킹할 파일 개수 입력받기
printf("패킹할 파일의 개수를 입력하세요 : ");
scanf_s("%d", &packFileCount);
//각각의 파일 이름 입력 받기
fileNames = (char*)malloc(packFileCount * FILENAMELENGTH);
//예외처리
if (fileNames == nullptr) exit(1);
//inputstream 비우기
rewind(stdin);
for (i = 0; i < packFileCount; i++)
{
printf("%d 번째 파일 이름 입력: ", i + 1);
gets_s(fileNames + i * FILENAMELENGTH, FILENAMELENGTH);
}
//패킹 파일 이름 입력받기
printf("패킹 패일 이름 입력 : ");
gets_s(packFileName, FILENAMELENGTH);
//패킹하기
//패킹 파일 생성
fopen_s(&fp, packFileName, "wb");
if (fp == nullptr) exit(1);
//구조체 정보 입력
st_PACK_HEADER_ fileHeader;
fileHeader.iType = PACKTYPE;
fileHeader.iFileNum = packFileCount;
st_PACK_FILEINFO_* infoHeaders;
infoHeaders = (st_PACK_FILEINFO_*)malloc(sizeof(st_PACK_FILEINFO_) * packFileCount);
if (infoHeaders == nullptr) exit(1);
char** filesPtr = (char**)malloc(packFileCount);
if (filesPtr == nullptr) exit(1);
char* fileContent;
int fileSize;
int fileOffset = sizeof(st_PACK_HEADER_) + packFileCount * sizeof(st_PACK_FILEINFO_);
//파일 읽어오고 저장 반복
for (i = 0; i < packFileCount; i++)
{
fopen_s(&fp2, fileNames + i * FILENAMELENGTH, "rb");
if (fp2 == nullptr) exit(1);
//파일 크기 찾기
fseek(fp2, 0, SEEK_END);
fileSize = ftell(fp2);
fseek(fp2, 0, SEEK_SET);
//해당 파일 내용 할당
fileContent = (char*)malloc(fileSize);
//예외처리
if (fileContent == nullptr) exit(1);
//읽기
fread_s(fileContent, fileSize, 1, fileSize, fp2);
//현재 파일 내용의 주소값 저장
filesPtr[i] = fileContent;
//현재 파일 헤더 구조체 저장
infoHeaders[i].iFileSize = fileSize;
infoHeaders[i].fileOffset = fileOffset;
//다음 파일을 위해 오프셋 업데이트
fileOffset += fileSize;
strcpy_s(infoHeaders[i].szFileName, fileNames + i * FILENAMELENGTH);
//파일 닫기
fclose(fp2);
}
//패킹
fwrite(&fileHeader, 1, sizeof(fileHeader), fp);
fwrite(infoHeaders, 1, sizeof(st_PACK_FILEINFO_) * packFileCount, fp);
for (i = 0; i < packFileCount; i++)
{
fwrite(filesPtr[i], 1, infoHeaders[i].iFileSize, fp);
}
//할당 해제
for (i = 0; i < packFileCount; i++)
{
free(filesPtr[i]);
}
free(infoHeaders);
free(filesPtr);
free(fileNames);
//파일 닫기
fclose(fp);
}
//언패킹
else
{
st_PACK_HEADER_ fileHeader;
st_PACK_FILEINFO_ fileInfo;
char* content;
//스트림 비우기
rewind(stdin);
//패킹파일 입력받기
printf("언패킹할 파일 이름 입력 : ");
gets_s(packFileName, FILENAMELENGTH);
//파일 열기
fopen_s(&fp, packFileName, "rb");
if (fp == nullptr) exit(1);
//해당 파일 헤더 분석
fread_s(&fileHeader, sizeof(fileHeader), 1, sizeof(fileHeader), fp);
//타입확인 -> 아니면 오류
if (fileHeader.iType != PACKTYPE)
{
exit(1);
}
//파일 개수 확인
packFileCount = fileHeader.iFileNum;
//각 파일 반복해서 뽑아내기
for (i = 0; i < packFileCount; i++)
{
//해당 파일 헤더 받기
fseek(fp, sizeof(fileHeader) + i * sizeof(fileInfo), SEEK_SET);
fread_s(&fileInfo, sizeof(fileInfo), 1, sizeof(fileInfo), fp);
//파일의 오프셋으로 점프
fseek(fp, fileInfo.fileOffset, SEEK_SET);
//내용 뽑아내고 파일 생성
//할당
content = (char*)malloc(fileInfo.iFileSize);
if (content == nullptr) exit(1);
//읽기
fread_s(content, fileInfo.iFileSize, 1, fileInfo.iFileSize, fp);
//패킹 파일 분리
//파일 생성
fopen_s(&fp2, fileInfo.szFileName, "wb");
if (fp2 == nullptr) exit(1);
//파일에 쓰기
fwrite(content, 1, fileInfo.iFileSize, fp2);
//종료
free(content);
fclose(fp2);
}
}
//종료
return 0;
}
'C++' 카테고리의 다른 글
C++ 정리 (0) | 2022.01.06 |
---|---|
비트맵(.bmp) 파일 구조 (0) | 2022.01.06 |
[C/C++] 파일 입출력 (0) | 2022.01.06 |
C언어 문자열 처리 (0) | 2022.01.06 |
C/C++ 시간을 측정하기 (0) | 2022.01.06 |