2009-11-25 6 views
5

'daki bir dizi satıra okuma CI'nın kullanılması, bir metin dosyasının içeriğinde, tümünün söylenmesi ve nth dizesini gösteren bir dizenin dizisini okuyacak şekilde okumak ister. metin dosyasının satırı. Dosyanın satırları keyfi uzun olabilir.Metin dosyasını C

Bunu gerçekleştirmenin zarif bir yolu nedir? Bir metin dosyasını doğrudan uygun bir boyutta bir arabelleğe okumak için bazı düzgün hileler biliyorum, ancak onu satırlara ayırmak onu daha da zorlaştırıyor (en azından anlatabildiğim kadarıyla).

Çok teşekkürler!

cevap

6

Çizgileri parçalara ayırmak, metni ayrıştırmak ve tüm EOL'leri (EOL ile kastediyorum \ n ve \ r) karakterlerini 0 ile değiştirmek anlamına gelir. Bu şekilde, arabelleğinizi yeniden kullanabilirsiniz ve yalnızca her birinin başlangıcını depolayabilirsiniz. Ayrı bir char * dizisine giriş yapın (hepsi sadece 2 geçiş yaparak).

Bu sayede, büyük olasılıkla performansı artıran dosya boyutu + 2 ayrıştırması için bir tane okuyabilirsiniz.

+0

kullanabilirsiniz. Çizgileri saymalı (doğru boyut dizisini ayırabilmeniz için), \ n ile 0 değiştirin ve ardından her satırın başlangıcını dizideki doğru noktaya atayın. Elbette bunu iki geçişte yapabilirsiniz. –

+0

Çok güzel bir fikir. Ben ona bir girdap vereceğim. –

+0

+1 İlk kopyayı dosyadan arabelleğe saymıyorsanız, 'realloc()' ve 'strtok()' ile tek bir geçiş yapabilirsiniz. – pmg

0

C için (C++'nin aksine) büyük olasılıkla fgets() kullanıyor olabilirsiniz. Ancak, rasgele uzunluk satırlarınız nedeniyle sorun yaşayabilirsiniz.

0

Belki de Bağlantılı Liste bunu yapmanın en iyi yolu olabilir mi? Derleyici, bunu yapmak için ne kadar büyük bir fikrinin olmadığı bir diziye sahip olmayı sevmeyecektir. Bağlantılı bir Liste ile gerçekten büyük bir metin dosyanız olabilir ve diziye yeterli bellek ayırma konusunda endişelenmeyin.

Ne yazık ki, bağlantılı listeler nasıl yapılacağını öğrenmedim, ama belki başka biri size yardımcı olabilir. Tüm dosyayı belleğe okumak için iyi bir yönteminiz varsa, neredeyse oradasınız demektir.

+0

Keyfi boyutu, bağlantılı listelerin çekici bir özelliğidir, ancak bunu elde etmek için rasgele erişime izin vermezsiniz. Örneğin, ilk önce 0-4 satırlarını almadan hat numarası alamazsınız. Fakat bir ara yapı olarak bağlantılı bir liste oluşturmak iyi bir fikirdir, daha sonra diziyi kolayca kurabilirsiniz. –

+0

Maalesef bu listede bağlantısız kaldığım bazı ayrıntılar nedeniyle bağlantılı bir liste çok uygun değil (kısaca rastgele erişime ihtiyacım var). Tabii ki, her şeyi bağlantılı bir listeye okuyabilirim, sonra içeriği bir diziye kopyalayabilirim, ama daha zarif bir yaklaşım olmasını umuyordum. –

0

Bunu yaptıktan sonra dosyayı iki kez tarayabilirsiniz. Satırları saymak için bir kez, ve bir kez satır işaretçileri ayarlamak ve '\ n' ve (ve belki de '\ r', dosya Windows ikili modda okunduğunda '\ r' ile değiştirin). Taramalar arasında bir kaç işaretçi ayırırsınız, şimdi kaç tane ihtiyacın olduğunu bilirsiniz.

1

Dosyadaki satır sayısını (döngü öğeleri) okumak ve ardından ilk boyut + 1 satır sayısı olan 2 boyutlu bir dizi oluşturmak mümkündür. Ardından, dosyayı diziye yeniden okuyun.

Öğelerin uzunluğunu tanımlamanız gerekir, ancak. Veya en uzun satır boyutu için bir sayı yapın.

örnek kod: bu bütün dosyanın üzerine birden fazla geçiş gerektirebilir olsa

inFile = fopen(FILENAME, "r"); 
lineCount = 0; 
while(inputError != EOF) { 
    inputError = fscanf(inFile, "%s\n", word); 
    lineCount++; 
} 
fclose(inFile); 
    // Above iterates lineCount++ after the EOF to allow for an array 
    // that matches the line numbers 

char names[lineCount][MAX_LINE]; 

fopen(FILENAME, "r"); 
for(i = 1; i < lineCount; i++) 
    fscanf(inFile, "%s", names[i]); 
fclose(inFile); 
0

Eğer Bu kesinlikle en iyi yolu bu şekilde

#include <stdlib.h> /* exit, malloc, realloc, free */ 
#include <stdio.h> /* fopen, fgetc, fputs, fwrite */ 

struct line_reader { 
    /* All members are private. */ 
    FILE *f; 
    char *buf; 
    size_t siz; 
}; 

/* 
* Initializes a line reader _lr_ for the stream _f_. 
*/ 
void 
lr_init(struct line_reader *lr, FILE *f) 
{ 
    lr->f = f; 
    lr->buf = NULL; 
    lr->siz = 0; 
} 

/* 
* Reads the next line. If successful, returns a pointer to the line, 
* and sets *len to the number of characters, at least 1. The result is 
* _not_ a C string; it has no terminating '\0'. The returned pointer 
* remains valid until the next call to next_line() or lr_free() with 
* the same _lr_. 
* 
* next_line() returns NULL at end of file, or if there is an error (on 
* the stream, or with memory allocation). 
*/ 
char * 
next_line(struct line_reader *lr, size_t *len) 
{ 
    size_t newsiz; 
    int c; 
    char *newbuf; 

    *len = 0;   /* Start with empty line. */ 
    for (;;) { 
     c = fgetc(lr->f); /* Read next character. */ 
     if (ferror(lr->f)) 
      return NULL; 

     if (c == EOF) { 
      /* 
      * End of file is also end of last line, 
     ` * unless this last line would be empty. 
      */ 
      if (*len == 0) 
       return NULL; 
      else 
       return lr->buf; 
     } else { 
      /* Append c to the buffer. */ 
      if (*len == lr->siz) { 
       /* Need a bigger buffer! */ 
       newsiz = lr->siz + 4096; 
       newbuf = realloc(lr->buf, newsiz); 
       if (newbuf == NULL) 
        return NULL; 
       lr->buf = newbuf; 
       lr->siz = newsiz; 
      } 
      lr->buf[(*len)++] = c; 

      /* '\n' is end of line. */ 
      if (c == '\n') 
       return lr->buf; 
     } 
    } 
} 

/* 
* Frees internal memory used by _lr_. 
*/ 
void 
lr_free(struct line_reader *lr) 
{ 
    free(lr->buf); 
    lr->buf = NULL; 
    lr->siz = 0; 
} 

/* 
* Read a file line by line. 
* http://rosettacode.org/wiki/Read_a_file_line_by_line 
*/ 
int 
main() 
{ 
    struct line_reader lr; 
    FILE *f; 
    size_t len; 
    char *line; 

    f = fopen("foobar.txt", "r"); 
    if (f == NULL) { 
     perror("foobar.txt"); 
     exit(1); 
    } 

    /* 
    * This loop reads each line. 
    * Remember that line is not a C string. 
    * There is no terminating '\0'. 
    */ 
    lr_init(&lr, f); 
    while (line = next_line(&lr, &len)) { 
     /* 
     * Do something with line. 
     */ 
     fputs("LINE: ", stdout); 
     fwrite(line, len, 1, stdout); 
    } 
    if (!feof(f)) { 
     perror("next_line"); 
     exit(1); 
    } 
    lr_free(&lr); 

    return 0; 
}