最终,我只是想将二进制文件剪切成大小不超过X的片段。不用别的了。如果输入文件是21MB,我想要3个7MB我可以加入猫或什么不。我在下面的简单示例中工作,我使用7MB块大小的缓冲区。我是否必须使用它才能获得7MB的文件块?如果块大小是2GB,那显然不是我想放在内存中的东西。所以我需要创建一个缓冲区。
我确实在这里和其他网站上读了几篇关于这个的帖子,但是它们似乎都使用了malloc或数组创建的某种缓冲区,并且查找非缓冲方式让我领先于我对套接字和与TCP / IP相关的主题。
我注定了很多if / while语句吗?
P.S。我在哪里可以找到C中I / O流的书籍?我可以找到很多C ++,但不是C。
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);
答案 0 :(得分:1)
setvbuf( ifp, NULL, _IOFBF, I_BUFFER); // Are these on
setvbuf( ofp, NULL, _IOFBF, O_BUFFER); // by default?
这些文件缓冲区设置为“完全缓冲”,这意味着只有当缓冲区(由I_BUFFER和O_BUFFER定义)已满时才会写入数据。
我还建议您一次不需要大量阅读。 10-100KB足以将操作系统中的任何开销减少到几乎没有,并且执行此操作几次的循环将是如此小的比例无关紧要。如果你读取较小的部分,然后写出一小部分,你甚至可能会有一些重叠,如果你一次读取7MB,这将需要足够长的时间,以前的7MB的写入可能已完全完成已阅读7MB。
www.cplusplus.com涵盖了所有C标准库(尽管名称,它涵盖了C函数以及C ++函数)。
答案 1 :(得分:1)
这是我最初在1991年写的一个程序bsplit
。它将文件分成任意大小的块;默认大小以千字节为单位(嗯,kibibytes - 1024字节)。
/*
@(#)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);
}
标题stderr.h
声明了一系列错误报告例程;我在大多数程序中都使用它。标题filter.h
声明函数filter_stdout()
,它遍历参数列表,打开文件以便读取和调用函数 - 在本例中为bsplit()
- 依次处理每个文件。它自动处理'无参数意味着读取标准输入'等。 (联系我以获取代码 - 请参阅我的个人资料。)
请注意,乘数c
表示'字符',b
表示512字节的块,k
,m
和g
表示KiB, MiB和GiB分别。
答案 2 :(得分:0)
你根本不需要担心缓冲。标准C库开发人员已经为您完成了这项工作。即使您使用fgetc()
逐字逐句阅读并使用fputc()
进行书写,也不会失去太多的表现。这些通常是访问缓冲的stdio结构的宏。
我相信我不必告诉你如何编写一个按字符读写的循环,并在所需的字节数后切换到一个新文件。
再次明确说明:优化的第一条规则:不要。第二个:在你做之前的措施。