C 文件分块和缓冲?
最终,我只是想把一个二进制文件切成大小不超过X的碎片。别再拿它做别的了。如果输入文件是21MB,我想要3个7MB的块,我可以用cat或其他什么东西加入。在下面的简单示例中,我使用7MB的块大小缓冲区。我必须使用它来获得7MB的文件块吗?如果区块大小是2GB,那么这显然不是我想要放在内存中的东西。所以我需要创建一个缓冲区 我确实在这里和其他网站上读了几篇关于这一点的文章,但它们似乎都使用了malloc或数组创建的某种缓冲区,查找非缓冲区的方式使我在套接字和TCP/IP相关主题方面走得太远了 我是否注定要做大量的if/while语句 顺便问一下,在哪里可以找到有关C中I/O流的书籍?我可以找到很多C++,但不是C.C 文件分块和缓冲?,c,C,最终,我只是想把一个二进制文件切成大小不超过X的碎片。别再拿它做别的了。如果输入文件是21MB,我想要3个7MB的块,我可以用cat或其他什么东西加入。在下面的简单示例中,我使用7MB的块大小缓冲区。我必须使用它来获得7MB的文件块吗?如果区块大小是2GB,那么这显然不是我想要放在内存中的东西。所以我需要创建一个缓冲区 我确实在这里和其他网站上读了几篇关于这一点的文章,但它们似乎都使用了malloc或数组创建的某种缓冲区,查找非缓冲区的方式使我在套接字和TCP/IP相关主题方面走得太远了 我是否
ifp = fopen(ifile, "rb"); // ifile is a 25MB sound file
ofp = fopen(ofile, "w"); // Omitted error checking.
setvbuf( ifp, NULL, _IOFBF, 1024); // Are these on
setvbuf( ofp, NULL, _IOFBF, 1024); // by default?
size_t CHUNK = 7000000; // 7MB Chunk sizes
size_t result = 0;
size_t *buffer = malloc(CHUNK);
if (buffer == NULL) {fputs ("Could not allocate memory",stderr); exit (1);}
// Read 1 btye at a time?
result = fread(buffer, 1, CHUNK, ifp);
if (result != CHUNK) {fputs ("ERROR: Buffer/read mismatch.",stderr); exit (1);}
fwrite(buffer, CHUNK, 1, ofp);
free(buffer);
这些设置将文件缓冲区设置为“完全缓冲”,这意味着只有在缓冲区(由I_缓冲区和O_缓冲区定义)已满时才写入数据
我还建议你不需要一次读大量的书。10-100KB将足以将操作系统中的任何开销减少到几乎为零,而几次这样做的循环将是如此小的比例,这无关紧要。如果读取较小的部分,然后写出较小的部分,甚至可能会有一点重叠,如果一次读取7MB,可能需要足够长的时间才能在读取7MB时完成之前的7MB写入
所有的C标准库都在www. cPLUSPLUS.Web(尽管有名称,它涵盖了C函数以及C++函数)。p> 您根本不需要担心缓冲。标准C库开发人员已经为您完成了这项工作。即使使用
fgetc()
逐字符读取,并使用fputc()
写入,也不会损失太多性能。这些通常是访问缓冲stdio结构的宏
我相信我不必告诉您如何编写一个按字符读写并在所需字节数后切换到新文件的循环
再次明确:优化的第一条规则:不要。第二:先测量再测量。这里有一个程序,
bsplit
,我最初是在1991年编写的。它将文件分割成任意大小的块;默认大小以千字节为单位指定(很好,-1024字节)
/*
@(#)文件:$RCSfile:bsplit.c,v$
@(#)版本:$修订版:1.11$
@(#)上次更改:$日期:2008/08/09 05:54:55$
@(#)用途:将文件拆分为块--二进制
@(#)作者:J Leffler
*/
#如果STDC版本=199901L
#定义_XOPEN_源600
#否则
#定义_XOPEN_源500
#endif/*\uuuu STDC\u版本\uuuu*/
#包括
#包括
#包括
#包括
#包括
#包括“stderr.h”
#包括“filter.h”
#定义MAXFILENAMELEN 256
#定义KB 1024
#定义兆字节(千字节*千字节)
#定义千兆字节(兆字节*千字节)
#定义零(x)((x)0)
#定义最小值(a,b)((a)<(b))?(a):(b))
char*prefix=“bsplit。”;
大小\u t块大小=64;
大小块=0;
大小\u t Skipblock=0;
字符缓冲区[64*KB];
长计数器=0;
静态int bsplit(文件*ifp,常量char*fn)
{
这次读取的大小\u t n;/*字节*/
大小\u t bsize;/*为当前块写入的大小*/
大小\u t tsize;/*为当前文件写入的大小*/
大小\u t rsize;/*读取量*/
文件*op;/*输出文件流*/
char文件[MAXFILENAMELEN];/*输出文件名*/
tsize=0;
bsize=0;
op=NIL(文件*);
rsize=MIN(缓冲区大小),块大小;
而((n=fread(buffer,sizeof(char),rsize,ifp))>0)
{
tsize+=n;
如果(tsize>SkipBlock)
{
如果(bsize==0)
{
sprintf(文件,“%s%03ld”,前缀,计数器++);
如果((op=fopen(文件,“w”)==NIL(文件*)
{
err_sysrem2(“无法打开文件”,文件);
返回(-1);
}
printf(“%s\n”,文件);
}
bsize+=n;
if(fwrite(缓冲区,sizeof(char),n,op)!=n)
{
err_sysrem2(“未能写入文件”,文件);
返回(-1);
}
如果(bsize>=块大小)
{
fclose(op);
bsize=0;
}
如果(nblocks>0&&tsize>=nblocks)
打破
}
}
返回0;
}
int main(int argc,字符**argv)
{
int-opt;
大小\u t乘数=千字节;
char*p;
字符c;
int rc;
opterr=0;
err_setarg0(argv[0]);
while((opt=getopt(argc,argv,“s:n:p:b:V”))!=-1)
{
开关(opt)
{
案例“p”:
前缀=optarg;
if(strlen(前缀)>MAXFILENAMELEN-sizeof(“000”))
err_error(“文件名前缀(%s)太长(最多%d)”,前缀,
(int)(MAXFILENAMELEN sizeof(“000”));
打破
案例s:
skipblocks=atoi(optarg);
打破
案例“n”:
nblocks=atoi(optarg);
打破
案例“b”:
区块大小=atoi(optarg);
p=optarg+strspn(optarg,“0123456789”);
如果(*p!='\0')
{
c=下限((无符号字符)*p);
如果(c=='c')
乘数=1;
else如果(c=='b')
乘数=千字节/2;
else如果(c='k')
乘数=千字节;
else如果(c='m')
乘法器=兆字节;
else如果(c='g')
乘数=千兆字节;
其他的
err_错误(“未知大小乘数后缀
setvbuf( ifp, NULL, _IOFBF, I_BUFFER); // Are these on
setvbuf( ofp, NULL, _IOFBF, O_BUFFER); // by default?
/*
@(#)File: $RCSfile: bsplit.c,v $
@(#)Version: $Revision: 1.11 $
@(#)Last changed: $Date: 2008/08/09 05:54:55 $
@(#)Purpose: Split file into blocks -- binary
@(#)Author: J Leffler
*/
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif /* __STDC_VERSION__ */
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "stderr.h"
#include "filter.h"
#define MAXFILENAMELEN 256
#define KILOBYTE 1024
#define MEGABYTE (KILOBYTE*KILOBYTE)
#define GIGABYTE (MEGABYTE*KILOBYTE)
#define NIL(x) ((x)0)
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
char *prefix = "bsplit.";
size_t blocksize = 64;
size_t nblocks = 0;
size_t skipblocks = 0;
char buffer[64*KILOBYTE];
long counter = 0;
static int bsplit(FILE *ifp, const char *fn)
{
size_t n; /* Bytes read this time */
size_t bsize; /* Size written for current block */
size_t tsize; /* Size written for current file */
size_t rsize; /* Amount to read */
FILE *op; /* Output file stream */
char file[MAXFILENAMELEN]; /* Output file name */
tsize = 0;
bsize = 0;
op = NIL(FILE *);
rsize = MIN(sizeof(buffer), blocksize);
while ((n = fread(buffer, sizeof(char), rsize, ifp)) > 0)
{
tsize += n;
if (tsize > skipblocks)
{
if (bsize == 0)
{
sprintf(file, "%s%03ld", prefix, counter++);
if ((op = fopen(file, "w")) == NIL(FILE *))
{
err_sysrem2("failed to open file", file);
return(-1);
}
printf("%s\n", file);
}
bsize += n;
if (fwrite(buffer, sizeof(char), n, op) != n)
{
err_sysrem2("failed to write to file", file);
return(-1);
}
if (bsize >= blocksize)
{
fclose(op);
bsize = 0;
}
if (nblocks > 0 && tsize >= nblocks)
break;
}
}
return 0;
}
int main(int argc, char **argv)
{
int opt;
size_t multiplier = KILOBYTE;
char *p;
char c;
int rc;
opterr = 0;
err_setarg0(argv[0]);
while ((opt = getopt(argc, argv, "s:n:p:b:V")) != -1)
{
switch (opt)
{
case 'p':
prefix = optarg;
if (strlen(prefix) > MAXFILENAMELEN - sizeof("000"))
err_error("file name prefix (%s) is too long (max %d)", prefix,
(int)(MAXFILENAMELEN-sizeof("000")));
break;
case 's':
skipblocks = atoi(optarg);
break;
case 'n':
nblocks = atoi(optarg);
break;
case 'b':
blocksize = atoi(optarg);
p = optarg + strspn(optarg, "0123456789");
if (*p != '\0')
{
c = tolower((unsigned char)*p);
if (c == 'c')
multiplier = 1;
else if (c == 'b')
multiplier = KILOBYTE/2;
else if (c == 'k')
multiplier = KILOBYTE;
else if (c == 'm')
multiplier = MEGABYTE;
else if (c == 'g')
multiplier = GIGABYTE;
else
err_error("unknown size multiplier suffix %s\n", p);
if (p[1] != '\0')
err_error("unknown size multiplier suffix %s\n", p);
}
break;
case 'V':
err_version("BSPLIT", &"@(#)$Revision: 1.11 $ ($Date: 2008/08/09 05:54:55 $)"[4]);
break;
default:
err_usage("[-b blocksize][-p prefix][-s skipblocks][-n blocks][file [...]]");
break;
}
}
/* Convert sizes to bytes */
blocksize *= multiplier;
skipblocks *= blocksize;
if (nblocks > 0)
nblocks = skipblocks + nblocks * blocksize;
rc = filter_stdout(argc, argv, optind, bsplit);
return(rc);
}