RT:
前提:任意大小不超过4G的文件。
要求:对文件内容进行二进制排序,以升序为例
实现方法:
1.以字符为单位遍历源文件(source file)
2.用unsigned long arr[256] 中的每一位保存每个字符出现的个数(如读取到source中的一个字符的十六进制为0x01,则arr[0x01]++),最坏的情况4G文件保存的全部是一个十六进制值.unsigned long 刚好可以满足,这就是为什么定义成unsigned long 数组.
3.从arr[0x00]开始遍历arr,分别打印字符到目标文件(target file)中(如arr[0x05] 的值为5则向target file 写入5个0x05);
4.降序则从arr[255]开始反向遍历输出即可.
以下为具体实现:
filesort.h
#ifndef _FILE_SORT_H
#define _FILE_SORT_H
#define MAX_ARR_SIZE 256
#define BUFFER_SIZE 1024
int file_sort(const char *, const char *);
#endif /*_FILE_SORT_H*/
filesort.c
#include #include #include #include #include "filesort.h"
/**
*函数说明:通过接受用户输入的源文件名以及目标文件名,
* 按文件内容的二进制升序排序
*参数说明:argc 输入的参数个数
* argv 输入的参数
*/
int main(int argc, char *argv[])
{
int ret = 0;
if (argc < 3)
{
printf("input args error!\n");
return 1;
}
if (0 == strcmp(argv[1], argv[2]))
{
printf("source file name must not be equals target file name!\n");
return 1;
}
ret = file_sort(argv[1], argv[2]);
/*ret != 0,sort fail*/
if (ret)
{
printf("sort fail!\n");
return 1;
}
return 0;
}
/**
*函数功能:将文件内容按二进制升序排序
*参数说明:sf 源文件名
* tf 目标文件名
*/
int file_sort(const char *sf, const char *tf)
{
FILE *prf = NULL;
FILE *pwf = NULL;
int read_bytes = 0;
int write_bytes = 0;
int idx = 0;
int flag = 0;
unsigned long cnt = 0;
unsigned char buffer[BUFFER_SIZE];
unsigned long arr[MAX_ARR_SIZE]={0};
assert(NULL != sf);
assert(NULL != tf);
do
{
prf = fopen(sf, "rb");
if (NULL == prf)
{
printf("cannot open the file:%s\n", sf);
flag = 1; /*flag sort fail*/
break;
}
pwf = fopen(tf, "wb");
if (NULL == pwf)
{
printf("cannot create the file:%s\n", tf);
flag = 1; /*flag sort fail*/
break;
}
/*read file and sort chars*/
while ((read_bytes = fread(buffer, sizeof(unsigned char), BUFFER_SIZE, prf)))
{
if ((-1 == read_bytes) && (errno != EINTR))
{
break;
}
for (idx = 0; idx < read_bytes; idx++)
{
arr[buffer[idx]]++;
}/* end for */
}/* end while */
/* write target file with sorted chars*/
for (idx = 0; idx < MAX_ARR_SIZE; idx++)
{
for (cnt = 0; cnt < arr[idx]; cnt++)
{
buffer[write_bytes++] = idx;
if ((write_bytes % BUFFER_SIZE) == 0)
{
fwrite(buffer, sizeof(unsigned char), BUFFER_SIZE, pwf);
write_bytes = 0;
}
}
}
if (write_bytes > 0)
{
fwrite(buffer, sizeof(unsigned char), write_bytes, pwf);
}
flag = 0; /*flag sort ok*/
} while(0);
/*close source file and target file stream*/
fclose(prf);
fclose(pwf);
return flag;
}
Makefile文件:
CC = cc
CFLAGS = -g
SRC = filesort.c
INC = -I../inc
LIBS =
OBJ = $(SRC:.c=.o)
TARGET = ./fs
all:$(TARGET)
.c.o:
$(CC) $(CFLAGS) $(INC) -c $(@D)/$(
编译生成可执行文件:
ricesea@ricesea-laptop:~/cs/src$ make
执行(注:source 是在当前文件夹下存在的一个文件,也可以指定其他的文件, date命令打印出开始执行和执行之后的时间,相减可以得出排序所用的时间):
ricesea@ricesea-laptop:~/cs/src$ date&&filesort source target&&date
演示一下吧:
在当前文件夹下有source文件:
在文件中有如下内容:
十六进制查看:
执行一下:date&&./fs source target&&date
多生成了一个指定的target文件,查看一下target内容是否符合:
十六进制:
ok 已经排好序了,但是两次date输出的时间都一样,因为date只能显示到秒级别,而刚刚我们排序的文件比较小
花的时间很少,所以没有变化,现在打算对一个稍大一点的文件排序,看看要花多少时间!
source_temp:大概310多MB
跑一下:date&&./fs source_temp target_temp&&date
排序总用时大概:3(s).
再看看cp 命令对其copy需要多少时间(为了区别,cp的目标文件为target_cp):
使用cp 命令总用时大概:2(s).
再看看文件列表:
P.S.:本人使用linux版本:Linux version 2.6.32-38-generic (buildd@zirconium) (gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5) )
CPU信息:Intel(R) Core(TM) i5-2410M CPU @ 2.30GHz
内存:2G
代码包下载: 对文件内容排序