3

私が解決しようとしている問題は、コマンドライン「program input_file output_file」を持つサードパーティコードの入力を最適化することです。サードパーティのコードは、input_file を標準の fopen、fseek、fread などで処理します。複数の入力ファイルを使用できるようにして、提供された順序で連結されているかのように単一のファイルとして処理できるようにしたいと考えています。サードパーティのコードを持っていますが、できるだけ変更したくありません。現在、ファイルを連結してから、連結されたファイルを入力としてプログラムを呼び出しています。ファイルが大きくて時間がかかる可能性があるため、連結を排除しようとしています。プログラムが標準入力をファイルに書き込み、シークを許可するため、標準入力からの読み取りは私が望むことをしません。

私が取り組んでいる解決策は、連結された多くのファイル (? 区切り) として input_file コマンドライン引数を受け入れ、concat_stream.h をプログラム ソースの先頭に追加することです (stdio を含めた後)。concat_stream.h は、複数のストリームを 1 つのストリームとして透過的に処理するために、標準呼び出しをインターセプトし、ストリームとそれに付随するデータのグローバル配列を使用して連結されたストリームを実装します。例として、concat_stream.h の一部を次に示します。

    FILE * fopen_concat_streams (char * filename, char * mode )
    {
      if( strchr(filename, '?')!=NULL )/*do we want a concat_stream?*/
        return concat_streams_init(filename, mode);/*setup concat_stream, return first stream as id*/
      else
        return fopen(filename, mode);/*standard library implementation*/
    }

    long int ftell_concat_streams( FILE * stream )
    {
      unsigned int index=is_stream_concat(stream);/*work out if stream refers to a concat_stream or regular stream*/
      if(index!=CONCAT_STREAMS_MAX)/*is stream a concat_stream?*/
      {
        ...
        return answer;/*work out and return location in concat_stream*/
      }
      else
        return ftell(stream);/*standard library implementation*/
    }

    #define fopen(x, y) fopen_concat_streams(x, y)
    #define ftell(x) ftell_concat_streams(x)

私の質問は、私は正しい軌道に乗っているか、それを行う簡単な方法はありますか? これを整理するためのライブラリがある場合は、代わりにそれを使用します。これは一般的なことのようですが、これまでのところ何も見つかりませんでした。最初の問題を解決するためのまったく異なる方法も受け入れられます。

4

3 に答える 3

2

すべてのファイルのパスとサイズがわかっている場合は、これでうまくいく可能性があります。達成しようとしているのは、すべての個々のパーツで構成される仮想ファイルを作成することです。

各ファイルのファイル ハンドルとオフセット (仮想ファイル内) を含むデータ構造を作成する必要があります。次に、この構造体で実際のファイル ハンドルを検索し、正しいオフセットを計算できます。

注意すべき問題:

  • fread()1 回の呼び出しでファイルの末尾を読み取った場合

その他のオプション:

  • が必要ない場合は、エイリアスとして理解し、ファイルを連結するために使用するfseek()ようにコードを教えることができます。-stdincatcat file1 file2 file3 | program - output

  • FUSE APIを使用してファイル システムを作成します。それはあなたの場合ほど怖くはありません。これにより、元のコードを変更せずに保つことができます。代わりに、FUSE を使用して、ファイルを 1 つの巨大なファイルのように見せます。

于 2012-10-29T15:04:57.630 に答える
1

bash「プロセス置換」を通じて4.xが達成することを達成したいようです:

the_program <(cat file1 file2 file3) output

つまり、入力ファイルを、プログラムが開いて読み取ることができるcat1 つの名前付きストリーム (おそらく などの名前) として送信します。/dev/fd/64これにより、プログラムへのすべての変更が回避されます。

これは要件を満たしていますか (効果を達成するために C コードを必要とすること以外)? 考えられる問題の 1 つは、プログラムがシーク可能なファイルを必要とする場合です。開いているファイル ストリームをシークできるかどうかは明らかではありません。

于 2012-10-29T16:34:38.523 に答える
0

これは、基本を実装するカットダウンインターセプトソリューションです。限られたテスト、限られたエラーチェック、フェザーとほぼ同じくらい堅牢です。すべての関数が完全であるわけではなく、多くが欠落しています(コードでfseeki64を使用している場合は、ここで実装するなど)。これは私が避けている解決策です(提案されているように融合を試みます)が、他の誰かがこの方法でそれをやりたいのであれば、これが出発点かもしれません。

主要

#include <stdio>
#include "concat_streams.h"
int main(int argc, char*argv[])
{
  char buf[16];
  concat_streams_global_init('?');
  FILE* file = fopen( "file1?file2?file3?file4", "rb" );
  ...
  fseek( file, 12, SEEK_SET);
  ...
  fread(buf, 1, 16, file);
  ...
  fclose(file);
}

concat_streams.h

#define CONCAT_STREAMS_MAX 10 /*max number of concat streams*/
FILE*** concat_streams=NULL;
size_t** concat_streams_boundaries=NULL;
size_t* concat_streams_count=NULL;
size_t* concat_streams_selector=NULL;
size_t* concat_streams_tot_size=NULL;
char concat_streams_delim='?';

/*return index of stream if it is concat, CONCAT_STREAMS_MAX otherwise*/
int is_stream_concat(FILE* stream)
{
  unsigned int index=0;
  while(index<CONCAT_STREAMS_MAX)
  {
    if(concat_streams[index]!=NULL)
    {
      if(concat_streams[index][0]==stream)
        break;
    }
    ++index;
  }
  return index;
}

/*Initialise concat_stream store*/
void concat_streams_global_init(char delim_use)
{
  concat_streams_delim=delim_use;

  concat_streams=(FILE***) malloc(sizeof(FILE**)*CONCAT_STREAMS_MAX);
  concat_streams_boundaries=(size_t**) malloc(sizeof(size_t*)*CONCAT_STREAMS_MAX);
  concat_streams_count=(size_t*) malloc(sizeof(size_t)*CONCAT_STREAMS_MAX);
  concat_streams_selector=(size_t*) malloc(sizeof(size_t)*CONCAT_STREAMS_MAX);
  concat_streams_tot_size=(size_t*) malloc(sizeof(size_t)*CONCAT_STREAMS_MAX);

  memset(concat_streams, 0, sizeof(FILE**)*CONCAT_STREAMS_MAX );
  memset(concat_streams_boundaries, 0, sizeof(size_t*)*CONCAT_STREAMS_MAX);
  memset(concat_streams_count, 0, sizeof(size_t)*CONCAT_STREAMS_MAX );
  memset(concat_streams_selector, 0, sizeof(size_t)*CONCAT_STREAMS_MAX );
  memset(concat_streams_tot_size, 0, sizeof(size_t)*CONCAT_STREAMS_MAX );
}

/*The meat of fopen*/
FILE* concat_streams_init(char* files_question_delim, char * mode)
{
  unsigned int concat_streams_next_set=0;
  while(concat_streams_next_set<CONCAT_STREAMS_MAX)
  {
    if(concat_streams[concat_streams_next_set]==NULL)
      break;
    ++concat_streams_next_set;
  }
  if(concat_streams_next_set==CONCAT_STREAMS_MAX)
    return NULL;
  char*files_question_delim_cpy=NULL;
  unsigned int i=0;
  while(files_question_delim[i]!=0)
  {
    if(files_question_delim[i]=='?')
      ++concat_streams_count[concat_streams_next_set];
    ++i;
  }
  ++concat_streams_count[concat_streams_next_set];

  files_question_delim_cpy=(char*)malloc(i);
  memcpy(files_question_delim_cpy, files_question_delim, i);

  concat_streams[concat_streams_next_set]=(FILE**)malloc(sizeof(FILE*)*concat_streams_count[concat_streams_next_set]);
  concat_streams_boundaries[concat_streams_next_set]=(size_t*)malloc(sizeof(size_t)*(concat_streams_count[concat_streams_next_set]+1));
  concat_streams_boundaries[concat_streams_next_set][0]=0;


  char* next_file;
  next_file=strtok(files_question_delim_cpy, "?");
  while(next_file!=NULL)
  {
    concat_streams[concat_streams_next_set][concat_streams_selector[concat_streams_next_set]]=fopen(next_file, "rb");
    if(concat_streams[concat_streams_next_set][concat_streams_selector[concat_streams_next_set]]==NULL)
    {
      fclose_concat_streams(concat_streams[concat_streams_next_set][0]);
      return NULL;/*fopen failed*/
    }
    fseek(concat_streams[concat_streams_next_set][concat_streams_selector[concat_streams_next_set]], 0, SEEK_END);
    concat_streams_boundaries[concat_streams_next_set][1+concat_streams_selector[concat_streams_next_set]] = concat_streams_boundaries[concat_streams_next_set][concat_streams_selector[concat_streams_next_set]] + ftell(concat_streams[concat_streams_next_set][concat_streams_selector[concat_streams_next_set]]);
    concat_streams_tot_size[concat_streams_next_set]+=ftell(concat_streams[concat_streams_next_set][concat_streams_selector[concat_streams_next_set]]);
    rewind(concat_streams[concat_streams_next_set][concat_streams_selector[concat_streams_next_set]]);
    ++concat_streams_selector[concat_streams_next_set];
    next_file=strtok(NULL, "?");
  }
  concat_streams_selector[concat_streams_next_set]=0;

  free(files_question_delim_cpy);
  return concat_streams[concat_streams_next_set][0];
}

FILE * fopen_concat_streams (char * filename, char * mode )
{
  if( strchr(filename, '?')!=NULL )
    return concat_streams_init(filename, mode);
  else
    return fopen(filename, mode);
}

/*only implemented origin==SEEK_SET*/
int fseek_concat_streams( FILE * stream, long int offset, int origin )
{
  unsigned int i=0;
  unsigned int index=is_stream_concat(stream);
  if(index!=CONCAT_STREAMS_MAX)
  {
    switch(origin)
    {
      case SEEK_SET:
        while(i<concat_streams_count[index])
        {
          if(offset>=concat_streams_boundaries[index][i] && offset<concat_streams_boundaries[index][i+1])
            break;
          ++i;
        }
        if(i==concat_streams_count[index])
          return 1;/*out of range*/
        concat_streams_selector[index]=i;
        return fseek(concat_streams[index][concat_streams_selector[index]], offset-concat_streams_boundaries[index][concat_streams_selector[index]], SEEK_SET);
      default:
          puts("error, Only SEEK_SET supported when using cat streams");
        return 1;/*not implemented*/
    }
  }
  else
    return fseek(stream, offset, origin);/*just a normal file*/
}

long int ftell_concat_streams( FILE * stream )
{
  unsigned int index=is_stream_concat(stream);
  if(index!=CONCAT_STREAMS_MAX)
  {
    /*Found*/
    return concat_streams_boundaries[index][concat_streams_selector[index]] + ftell(concat_streams[index][concat_streams_selector[index]]);
  }
  else
    return ftell(stream);
}

int feof_concat_streams( FILE * stream )
{
  unsigned int index=is_stream_concat(stream);
  if(index!=CONCAT_STREAMS_MAX)
  {
    if(concat_streams_selector[index]==concat_streams_count[index])
      return 1;/*EOF*/
    else
      return 0;
  }
  else
    return feof(stream);
}

size_t fread_concat_streams (void * ptr, size_t size, size_t count, FILE * stream )
{
  size_t mult=size*count;
  size_t num_to_go=mult;
  char* buffer=NULL;
  unsigned int index=is_stream_concat(stream);
  unsigned int num_read;
  char* out_ptr=(char*)ptr;

  if(index!=CONCAT_STREAMS_MAX)
  {
    if(concat_streams_selector[index]==concat_streams_count[index])
      return 0;/*at eof*/

    buffer=(char*)malloc(2048*4096);
    while(num_to_go!=0)
    {
      num_read=fread(buffer, 1, num_to_go>=2048*4096?2048*4096:num_to_go, concat_streams[index][concat_streams_selector[index]]);
      if( num_read != (num_to_go>=2048*4096?2048*4096:num_to_go) )
      {
        if( feof(concat_streams[index][concat_streams_selector[index]])==0 )
        {
          puts("EOF not set, read error");
          memcpy(out_ptr, buffer, num_read);
          out_ptr+=num_read;
          num_to_go-=num_read;
          free(buffer);
          return mult-num_to_go;
        }
        else
        {
          rewind(concat_streams[index][concat_streams_selector[index]]);
          ++concat_streams_selector[index];
          if(concat_streams_selector[index]==concat_streams_count[index])
          {
            memcpy(out_ptr, buffer, num_read);
            out_ptr+=num_read;
            num_to_go-=num_read;
            free(buffer);
            return mult-num_to_go;
          }
          else
            rewind(concat_streams[index][concat_streams_selector[index]]);
        }
      }
      memcpy(out_ptr, buffer, num_read);
      out_ptr+=num_read;
      num_to_go-=num_read;
    }
    free(buffer);  
    return mult;
  }
  else
    return fread(ptr, size, count, stream);
}

size_t fwrite_concat_streams ( const void * ptr, size_t size, size_t count, FILE * stream )
{
  unsigned int index=is_stream_concat(stream);
  if(index!=CONCAT_STREAMS_MAX)
  {
    puts("error, writing to cat_streams not supported");
    return 0;
  }
  else
    return fwrite(ptr, size, count, stream);
}

int fclose_concat_streams ( FILE * stream )
{
  unsigned int i=0;
  unsigned int index=is_stream_concat(stream);
  if(index!=CONCAT_STREAMS_MAX)
  {
    while(i<concat_streams_count[index])
    {
      fclose(concat_streams[index][i]);
      ++i;
    }
    free(concat_streams[index]);
    concat_streams[index]=NULL;
    free(concat_streams_boundaries[index]);
    concat_streams_boundaries[index]=NULL;
    concat_streams_count[index]=0;
    concat_streams_selector[index]=0;
    concat_streams_tot_size[index]=0;
  }
  else
    return fclose(stream);
}

#define fseek(x, y, z) fseek_concat_streams(x, y, z)
#define fread(w, x, y, z) fread_concat_streams(w, x, y, z)
#define fwrite(w, x, y, z) fwrite_concat_streams(w, x, y, z)
#define fopen(x, y) fopen_concat_streams(x, y)
#define ftell(x) ftell_concat_streams(x)
#define feof(x) feof_concat_streams(x)
#define fclose(x) fclose_concat_streams(x)
于 2012-10-30T10:02:25.093 に答える