C - Попытка вернуться к предыдущей строке в файле - PullRequest
0 голосов
/ 06 октября 2011

Мне нужно прочитать текстовый файл, который может начинаться с необязательных комментариев. На практике мне нужно пропустить любую строку в начале файла, которая не начинается с «@» или «>». В моем тестовом случае файл выглядит так:

# Sun Jul 12 22:04:52 2009 /share/apps/corona/bin/filter_fasta.pl --output=/data/results/solid0065/primary.20090712170542775 
# Cwd: /state/partition1/home/pipeline
# Title: solid0065_20090629_FC1_Tomate_Heinz_4_5_Kb_Tomate_Heinz_4_5_Kb_01
>125_963_316_F3
T1230330231223011323010013


Так что я должен пропустить первые 3 строки (но в целом я должен пропустить n строк). Я должен повторить это с 2 или 4 файлами [которые находятся внутри ФАЙЛА ** inputFiles]. Я пробовал с этим циклом:

buffer = (char*) malloc (sizeof(char) * 5000);
if (buffer == NULL)
    notEnoughMemory();

for (i = 0; i < (cIn-1); i++){
    fgetpos(inputFiles[i], &position);
    fgets(buffer, 4999, inputFiles[i]);
    while ((buffer[0] != '@') && (buffer[0] != '>')){
        fgetpos(inputFiles[i], &position);
        fgets(buffer, 4999, inputFiles[i]);
    }
    fsetpos(inputFiles[i], &position);
}


Где cIn - это number_of_input_files + 1. При попытке отладки цикл корректно останавливается после прочтения четвертой строки. Но когда я использую setpos, он возвращается не к началу четвертой строки, как я ожидал, а к середине третьей. На самом деле, если точно после fsetpos () я печатаю буфер после этих операций:

fgets(buffer, 4999, inputFiles[i]);
fgets(buffer, 4999, inputFiles[i]);

Я получаю:

FC1_Tomate_Heinz_4_5_Kb_Tomate_Heinz_4_5_Kb_01
>125_963_316_F3

Есть идеи? Заранее спасибо

Ответы [ 3 ]

2 голосов
/ 06 октября 2011

Вместо fgetpos(); fsetpos(); вы можете использовать
fseek(inputFiles[i], -strlen(buffer), SEEK_CUR);

1 голос
/ 06 октября 2011

(ИМХО) Лучше всего прочитать весь файл в один большой буфер (также доступен вариант mmap, если он доступен), затем найти и исправить окончания строк и заголовки fasta. Это также уменьшит фрагментацию памяти. И это сильно упрощает «парсер».

РЕДАКТИРОВАТЬ: добавлен источник (он не идеален, но в прошлый раз, когда я проверял его, он работал ;-) Возможно, он неполон, я оторвал его от более крупной программы.

struct fastapart {
  char * name;
  char * data;
  unsigned size;
  struct roedel *friends;
  };
struct fastafile {
  size_t totsize;
  char *tot;
  unsigned count;
  struct fastapart *parts;
  int *alloc;
  };

struct fastafile * read_complete_fasta(char *name)
{
int rc,state;
struct fastafile * result;
size_t pos,len,cnt,idx;
struct strbuff *fwd=NULL,*rev = NULL;

result = malloc (sizeof *result);
if (!result) return NULL;
result->tot = read_complete_file(name , &result->totsize);
if (!result->tot) goto failfree;

result->count = 0;
result->parts = NULL;

for (pos=cnt=state=0; pos < result->totsize; ) {
switch (state) {
case 0: /* find first '>' */
  if (result->tot[pos] == '>') { pos++; state=2; continue; }
  pos += strcspn( result->tot+pos, "\n" );
case 1: /* not found: sync to newline */
  if (result->tot[pos] == '\n') { pos++; state=0; continue; }
  else pos++;
  continue;;
case 2: /* Got '>'; grab name */
  len = strcspn( result->tot+pos, " \t\n" );
  if (cnt >= result->count) {
    size_t siz;
    siz = result->count ? 2* result->count: 16;
    result->parts = realloc( result->parts
      , siz * sizeof *result->parts);
    for (  ; result->count < siz;result->count ++) {
      result->parts[cnt].name = NULL;
      result->parts[cnt].data = NULL;
      result->parts[cnt].friends = NULL;
      result->parts[cnt].size = 0;
      }
    }

  result->parts[cnt].name = result->tot+pos;
  result->parts[cnt].name[len] = 0;
  pos += 1+len;
  len = strspn( result->tot+pos, " \t\n" );
  pos += len;
  state++;
  continue;
case 3: /* grab data; for the moment, throw away reversed data */
  if (result->tot[pos] == '>') {
    if (fwd) {
      memcpy(result->parts[cnt].data, fwd->data, fwd->used ); result->parts[cnt].size = fwd->used;
      result->parts[cnt].data [ fwd->used ] = 0;
      fwd->used = 0; }
    if (rev) {
      /* memcpy(result->parts[cnt].data+result->parts[cnt].size, rev->data, rev->used );  */
      rev->used = 0;
      }
    if (result->parts[cnt].data) cnt++;
    pos++; state=2;
    continue;
    }
  len = strcspn( result->tot+pos, "\t\n" );
  if (!len) { /* empty line; what to do? skip it! */
    fprintf(stderr, "Empty\n" );
    pos++; state=1;
    continue; }
  if (!result->parts[cnt].data) {result->parts[cnt].data = result->tot+pos;  }
  fwd = strbuff_add(fwd, result->tot+pos, len);
  pos += len;
  if (result->tot[pos] == '\t' ) {
    pos += strspn(result->tot+pos, " \t" );
    len = strcspn( result->tot+pos, "\n" );
    rev =  strbuff_add(rev, result->tot+pos, len);
    pos += len;
    }
  pos += strspn(result->tot+pos, " \t\r\n" );
  }}
if (state == 3) {
  if (fwd) {
    memcpy(result->parts[cnt].data, fwd->data, fwd->used ); result->parts[cnt].size = fwd->used;
    result->parts[cnt].data [ fwd->used ] = 0;
    fwd->used = 0;
    }
  if (rev) {
    /* memcpy(result->parts[cnt].data+result->parts[cnt].size, rev->data, rev->used );  */
    rev->used = 0;
    }
  if (result->parts[cnt].data) cnt++;
  }
  /* final realloc */
result->parts = realloc( result->parts, cnt * sizeof *result->parts);
result->count  = cnt;
free (fwd);
free (rev);

result->alloc = malloc( result->count * sizeof result->alloc[0] );
if (result->alloc) {
  for (cnt = 0; cnt <  result->count; cnt++ ) result->alloc[cnt] = cnt;
  }
return result;

failfree:
free (fwd);
free (rev);
free (result);
return NULL;
}

char * read_complete_file(char *name, size_t *sizep)
{
int fd, rc;
size_t size, len;
char *result;

struct stat st;

fd = open(name, O_RDONLY);

if (fd == -1) goto fail;
rc = fstat(fd, &st);
if (rc == -1) goto closefail;
result = malloc (1+st.st_size );
if (!result ) goto closefail;
result[st.st_size] = 0;

for (size = 0; size < st.st_size;) {
  rc = read(fd, result, st.st_size - size);
  if (rc < 0) goto freeclosefail;
  size += rc;
  }

fprintf(stderr, "Read %lu bytes FROM %s\n"
  , (unsigned long) size, name);
close(fd);
*sizep = size;
return result;

freeclosefail:
  free(result);
closefail:
  close(fd);
fail:
  *sizep=0; return NULL;
}
0 голосов
/ 06 октября 2011

Вы можете просто пропустить обработку строк, которые вас не интересуют:

for (i = 0; i < (cIn-1); i++){

    while (fgets(buffer, 4999, inputFiles[i])){
       if(buffer[0] == '@' || buffer[0] == '>') {
          puts(buffer);
        }
        /* else do nothing*/
    }
}

Затем вы просто заменяете puts(buffer); кодом, который вам нужен для обработки допустимых строк. (хотя из вашего примера звучит так, что вы скорее хотите игнорировать только строки, начинающиеся с #,?)

...