稀疏文件文件这个东东,最开始知道是在学Oracle temp表空间。因为 Oracle 临时表空间的数据文件ls和du出来,大小不一致,后来才知道,
这东东是稀疏文件的特性。 这玩意主要是先跟系统把整个文件大小空间申请下来,然后再在需要时把数据向里面填。 好处是一次性分配连续空间,
避免了硬盘碎片。 坏处是,后续文件扩展有可能没有相应的空间, 结果向临时表空间文件放数据,就有可能会发现硬盘空间不够了。 所以有些DBA为了
防止出现这种问题,创建出Oracle的 临时表空间数据文件后,用命令将其转为非稀疏文件。
因为最近整批量生成测试文件东东,又整理了下这个东东。
(一) 命令行方式生成方式及与普通文件的相互转换
(二) 压缩时的小问题
(三) Linux下代码生成
(四) Windows下代码生成
(一) 命令行方式生成及与普通文件的相互转换
Windows下没找到直接生成稀疏文件的命令,UNIX/Linux没找到直接生成非稀疏文件的命令,郁闷。
UNIX/Linux用dd命令就行了。
dd if=/dev/zero of=xcl.sparsefile bs=1M seek=1000 count=0
//除了dd,在Solaris上,还可以用mkfile命令来创建
mkfile -n 10m /u01/xcl.sparsefile
//查看文件内容
od -t a /u01/xcl.sparsefile
//查看文件实际大小
du -k /u01/xcl.sparsefile
// 将稀疏文件转为非稀疏
cp --sparse=never /u01/app/oracle/oradata/xcldb/temp_xcl.dbf
//将普通文件转为稀疏文件
cp --sparse=always /u01/xcl.nosparsefile /u01/xcl.sparsefile
(二) 压缩时的小问题
稀疏文件压缩时,一定要记得在tar中加S参数,不然解压出来就不是稀疏文件了。
tar zcSf temp_xcl.tar.gz /u01/app/oracle/oradata/xcldb/temp_xcl.dbf
(三) Linux下代码生成
主要是有fsetpos来移到到指定大小位置,再用fwrite来占位。 也可以用lseek来实现。
本来当时在Linux下弄完这个代码,想Windows下应当也一样,没想到效果不同。
再就是fpost_t 的使用,区别比较大,要注意。
/*************************************************
Author: xiongchuanliang
Description: 非Windows下生成指定大小的稀疏文件
**************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define PRINT_ERROR printf("error : %d:%s",errno,strerror(errno))
int testSparseFile(const char * fname)
{
FILE *fp = NULL;
fpos_t pos ;
char buf[255] ={0};
if( (fp = fopen(fname,"w+")) == NULL)
{
printf("err: fopen() \n");
PRINT_ERROR;
return -1;
}
// Linux 设置fpos_t 用这个结构体
pos.__pos = 0x100000; //1024 == 1mb
// Windows 在vc下fpos_t被定义为long型,则是直接赋值就可以了。
// 但生成出来的文件是非稀疏的。
// pos = 0x100000 ;
if( fsetpos( fp, &pos ) != 0 )
{
printf("err: fsetpos() \n");
PRINT_ERROR;
return -1;
}
if( (fwrite("\0",1,1,fp)) != 1)
{
printf("err: fwrite() \n");
PRINT_ERROR;
return -1;
}
fclose( fp );
return 0;
}
int main()
{
const char * fname ="/u01/xcl.sparsefile";
//const char * fname ="C:\\xcl\\demo5.nosparsefile";
char cmdbuf[50] = {0};
sprintf(cmdbuf,"ls -l %s ; du %s ;",fname,fname);
testSparseFile(fname);
system(cmdbuf);
return 0;
}
( 四) Windows下代码生成
Windows下生成稀疏文件的关键是 DeviceIoControl 函数。但在XP下使用麻烦不断。
要定义_WIN32_WINNT大于等于0x0500才能使用FSCTL_SET_SPARSE.
可参考:
http://msdn.microsoft.com/zh-cn/subscriptions/aa364596
/*************************************************
Author: xiongchuanliang
Description: Windows下生成指定大小的文件,非稀疏文件
**************************************************/
#include <stdlib.h>
#include <stdio.h>
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif
#include <Windows.h>
#include <Winioctl.h>
#include <direct.h> // _mkdir
#include <io.h>
void PrintError(DWORD dwErr) {
char szMsg[256];
DWORD dwFlags = FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK |
FORMAT_MESSAGE_FROM_SYSTEM;
if (!::FormatMessageA(dwFlags, NULL, dwErr, 0, szMsg, sizeof(szMsg), NULL)) strcpy(szMsg, "Unknown error.");
printf(szMsg);
printf("\n");
}
int testfile()
{
HANDLE hFile ;
DWORD dwWriteaddr = 0;
DWORD dwRet =0,dwFPos = 0;
BOOL bRet = FALSE;
hFile = CreateFileA("C:\\xcl\\demo4.txt",GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
0,
NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
printf("创建文件失败!\n");
PrintError(GetLastError());
return 1;
}
//告诉系统该文件是稀疏文件,将文件中那些0字节空间给压缩掉
bRet = DeviceIoControl(hFile,
FSCTL_SET_SPARSE,
NULL,
0,
NULL,
0,
&dwRet,
NULL);
if(!bRet)
{
printf("DeviceIoControl发生错误.\n");
PrintError(GetLastError());
return 1;
}
//生成指定大小的文件
// 0x100000 = 1048576 = 1 MB
dwFPos = SetFilePointer(hFile,0x100000,NULL,FILE_BEGIN);
if (dwFPos == INVALID_SET_FILE_POINTER)
{
printf("SetFilePointer发生错误.\n");
PrintError(GetLastError());
return 1;
}
bRet = WriteFile(hFile,"XCL\0",4,&dwWriteaddr,NULL);
if (!bRet)
{
printf("WriteFile发生错误.\n");
PrintError(GetLastError());
return 1;
}
//除了在文件最末尾会有"XCL"这三个字符外,其它部份将会被填上0,实实在在的占用系统空间.
dwFPos = SetEndOfFile(hFile);
if (dwFPos == INVALID_SET_FILE_POINTER)
{
printf("SetEndOfFile发生错误.\n");
PrintError(GetLastError());
return 1;
}
//GetFileInformationByHandle 可查看文件是否为稀疏文件(sparse-files)
BY_HANDLE_FILE_INFORMATION stFileInfo;
GetFileInformationByHandle(hFile, &stFileInfo);
if(stFileInfo.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE)
{
//Sparse file
printf("稀疏文件 \n");
}else{
//Not sparse file
printf("非稀疏文件 \n");
}
CloseHandle(hFile);
return 0;
}
int main(void)
{
testfile();
system("pause");
return 0;
}