0

最終的には、バイナリファイルをX以下のサイズに分割することを検討しています。それで他に何もしないでください。入力ファイルが21MBの場合、猫と結合できる7MBを3つ必要とします。以下の簡単な例では、7MBのチャンクサイズのバッファーを使用しています。7MBのファイルチャンクを取得するには、それを使用する必要がありますか?チャンクサイズが2GBと言った場合、それは明らかに私がメモリに入れたいものではありません。したがって、バッファを作成する必要がありますか。

私はこれについてここや他のサイトでいくつかの投稿を読みましたが、それらはすべて、mallocまたは配列によって作成されたある種のバッファーを使用しているようです。関連トピック。

私はたくさんのif/whileステートメントに運命づけられていますか?

PSCのI/Oストリームに関する本はどこにありますか?C ++のLOTは見つかりますが、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);
4

3 に答える 3

1
setvbuf( ifp, NULL, _IOFBF, I_BUFFER); // Are these on
setvbuf( ofp, NULL, _IOFBF, O_BUFFER); // by default?

これらは、ファイルバッファを「完全にバッファリング」するように設定します。つまり、データは、バッファ(I_BUFFERおよびO_BUFFERで定義)がいっぱいになったときにのみ書き込まれます。

また、一度に大量に読む必要はないことをお勧めします。10〜100 KBは、OSのオーバーヘッドをほぼゼロに減らすのに十分であり、これを数回実行するループは、問題にならないほど小さな割合になります。小さい部分を読み取ってから小さい部分を書き出すと、少し重複することもあります。一度に7MBを読み取ると、以前の7MBの書き込みがおそらく完全に終了するまでに十分な時間がかかります。 7MBが読み込まれました。

すべてのC標準ライブラリはwww.cplusplus.comでカバーされています(名前にもかかわらず、C++関数だけでなくC関数もカバーしています)。

于 2013-01-01T00:15:05.377 に答える
1

これが私が1991年に最初に書いたプログラムbsplitです。それはファイルを任意のサイズのチャンクに分割します。デフォルトのサイズはキロバイトで指定されます(キビバイト— 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を意味することに注意してください。


サポートコードは、GitHubのSOQ (Stack Overflow Questions)リポジトリで、ファイルfilter.c、、、およびsrc/libsoqサブディレクトリで利用できるようになりました。スタンザを置き換えるヘッダーもあります—そしてPOSIX.1 2008(2018)サポートを要求するのではなく使用します。filter.hfilterio.cstderr.cstderr.hposixver.h__STDC_VERSION__#define _XOPEN_SOURCE 700600

于 2013-01-01T00:27:42.963 に答える
0

バッファリングについてまったく心配する必要はありません。標準Cライブラリの開発者は、これをすでに行っています。を使用して文字ごとに読み取り、を使用しfgetc()て書き込みを行っても、パフォーマンスが大幅に低下することはありませんfputc()。これらは通常、バッファリングされたstdio構造にアクセスするためのマクロです。

文字ごとに読み書きし、必要なバイト数の後に新しいファイルに切り替えるループの書き方を説明する必要はないと思います。

もう一度明示的にするには:最適化の最初のルール:しないでください。2番目:実行する前に測定します。

于 2013-01-01T00:26:54.440 に答える