Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Считывание строк из файла на С


Автор: NetJunky 4.1.2010, 05:53
Всем доброго времени суток.
Возможно тема и не очень разумна, но ничего не найдя по моему вопросу пришлось спрашивать тут.
Думаю сложного в этом ничего нету, но у меня немного проблемно.

Подскажите пожалуйста, как можно считать строку из файла, если я не знаю размера строки. Тоесть может быть, как мега большая, так и вообще пустая.

Заранее всем спасибо.

Автор: bourne 4.1.2010, 05:59
fgetc() должна помочь

Автор: NetJunky 4.1.2010, 12:05
Тоесть варианта, как разом считывать строку нету? Только по символьно?

Автор: zim22 4.1.2010, 12:55
http://www.cplusplus.com/reference/clibrary/cstdio/fgets/

Автор: zloyshprot 4.1.2010, 13:27
Я позволю себе влезть в данную тему, потому как вопрос мой связан с ней =)
Есть код, по вытаскиванию строчек из файла: 

Код

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <conio.h>

using namespace std;

int main(void)
{
    FILE *file;
    errno_t error;
    char line[128];

    int num = 0;

    if( ( error = fopen_s( &file, "whitelist.txt", "r" ) ) != 0 )
        printf("Unable to open file");
    else
    {
        printf("File opened\n");
        while( fgets( line, sizeof( line ), file ) != NULL )
        {
            printf( line );
//            remove( line );
        }
    }
    if( file )
        fclose( file );
    printf("\nPress any key... ");
    getchar();
    return 0;
}


Собственно вопрос в том, что каждая строка считывается с переносом на следующую строку. 
т.е. вывод: 
File opened
1bla.txt
2bla.txt
3bla.txt
4bla.txt
Press any key...

Есть варианты, чтобы не было переносов на новую строку? А то мне надо дальше удалять файлы из списка, а я получаю Invalid argument и удаляется только самый последний файл из списка. 

Автор: bourne 4.1.2010, 15:16
Цитата(zim22 @  4.1.2010,  12:55 Найти цитируемый пост)
fgets 

Она ж принимает в качестве аргумента количество символов...
Цитата(NetJunky @  4.1.2010,  05:53 Найти цитируемый пост)
может быть, как мега большая, так и вообще пустая.

Можно конечно указать 1000000 smile

Цитата(NetJunky @  4.1.2010,  12:05 Найти цитируемый пост)
Тоесть варианта, как разом считывать строку нету? Только по символьно? 

Ну если ты не знаешь  какая длина у строки, то имхо только посимвольно, т.к. надо "поймать" конец строки...

Добавлено через 3 минуты и 9 секунд
Цитата(zloyshprot @  4.1.2010,  13:27 Найти цитируемый пост)
Собственно вопрос в том, что каждая строка считывается с переносом на следующую строку. 

С каким переносом?

Автор: zim22 4.1.2010, 15:23
Цитата(bourne @  4.1.2010,  14:16 Найти цитируемый пост)
может быть, как мега большая, так и вообще пустая.

не обратил на это внимание. тогда fgetc  smile 

Автор: NetJunky 4.1.2010, 17:08
zloyshprot, тебе надо fgetc. Так как тогда ты можешь каждый считываемый символ проверять на \n и если так, то делать запись за место \n на \0 и переходить на следующую строку.

Вопрос такой. Если у меня массив вышел, который из трёх ячеек [1][3][\0]. Можно ли как-то верно перевести его в int или может есть какой-то алгоритм, как можно считать в int так чтобы получилось такое число?

П.С. 13 привёл, как пример, может быть и любое другое.

Автор: ller 4.1.2010, 17:13
Цитата(NetJunky @  4.1.2010,  17:08 Найти цитируемый пост)
Вопрос такой. Если у меня массив вышел, который из трёх ячеек [1][3][\0]. Можно ли как-то верно перевести его в int или может есть какой-то алгоритм, как можно считать в int так чтобы получилось такое число?


atoi() ?

Автор: djamshud 4.1.2010, 17:37
Не сходите с ума, к черту посимвольное чтение. Читайте буферами и ищите в нем перенос строки.

Также в GNU еще есть специальное расширение: man getline.

Автор: xvr 5.1.2010, 12:52
Надо замэпить файл в память и искать строки в ней (с помощью memcmp например)

Автор: djamshud 5.1.2010, 14:47
xvr предложил наилучший способ. Вечно я про него забываю.

Автор: NetJunky 6.1.2010, 02:19
xvr, djamshud, я так понимаю, что Ваши советы были уже не на млй вопрос)

Автор: djamshud 6.1.2010, 02:27
NetJunky, нет, на ваш:). Только это советы не в духе "вызвать такую-то функцию", а впринципе, как делать. Код получится более громоздким, но куда более эффективным.

Автор: NetJunky 6.1.2010, 03:54
djamshud, просто memcmp ещё я могу понять, а вот getline() если я не ошибаюсь используется только начиная с С++, а значит уже изначально не подходила. Так как спрашивал именно про Си, но всёравно спасибо.
Просто далее был вопрос от человека у котого пример на С++, вот и решил, что ответ уже ему адресуются.

Автор: djamshud 6.1.2010, 14:24
Код

#define _GNU_SOURCE
#include <stdio.h>
ssize_t getline(char **lineptr, size_t *n, FILE *stream);


Это сишная функция, но, как я писал, ГНУтое расширение, т.е. не кроссплатформенно.

Автор: Powerhead77 6.1.2010, 17:57
Код
   while (!infile.eof()){
        infile.getline(str,255);      // считываем строку из файла
for (i; i<strlen(str);i++){ //определяем длинну строки            
str[i] = tolower(str[i]); //переводим все символы в строчные буквы                
if (str[i]=='#'||str[i]==';'){str[i]='\0'; break;}  //отсекаем коментарий (#;)
if (str[i]=='    '){str[i]=' ';} //подменяем символы табуляции на пробелы    
}

    }


Видимо не в тему. 
Считываем строку в буфер char str[]. Далее определяем длинну считанной строки и обрабатываем как нам надо.


Модератор: не забываем пользоваться кнопочкой "Код"

Автор: NetJunky 10.1.2010, 19:34
Powerhead77, табуляцию можно было вроде сделать через \t.

Вопрос такого характера вроде всё по этойже тематике.
Если всёже не пользовать getline, а посимвольное считывание.
Вот например. Имею файл, в нём матрица определённого размера. Между каждым значением ячейки матрицы, в файле может быть один или более пробелов.
Код

            getSize = (char*)malloc(sizeof(char));
            i = 0;
            j = 0;
            z = 0;
            while(!feof(in)) {
                c = fgetc(in);
                if(c == '\n') {
                    if(z == mSize) {
                        break;
                    }
                    tmp = "";
                    tmp = strtok(getSize, " ");
                    for(j = 0; j <= mSize; j++) {
                        TSPmatrix[z][j] = atoi(tmp);
                        tmp = strtok(NULL, " ");
                    }
                    z++;
                    free(getSize);
                    i = 0;
                    getSize = (char*)malloc(sizeof(char));
                } else {
                    getSize[i] = c;
                    i++;
#ifdef DEBUG
    printf("%c\n", c);
#endif
                    getSize = (char*)realloc(getSize, sizeof(char) + i);
                }
            }
            free(getSize);

Но данный вариант никак не получается из-за того, что чтобы atoi грамотно перевёл, после каждого значения должен стоять знак конца строки '\0'.

Пример матрицы:
Код

0 128 71 85 185 257 232 193 199 25 130 65 171
128 0 91 62 58 161 108 151 97 126 48 179 72
71 91 0 29 149 252 199 212 143 89 149 136 163
85 62 29 0 120 223 170 195 114 89 110 143 134
185 58 149 120 0 107 50 98 85 165 56 215 14
257 161 252 223 107 0 48 99 129 237 128 287 93
232 108 199 170 50 48 0 148 84 212 106 262 64
193 151 212 195 98 99 148 0 183 174 101 223 84
199 97 143 114 85 129 84 183 0 203 130 257 99
25 126 89 89 165 237 212 174 203 0 107 54 151
130 48 149 110 56 128 106 101 130 107 0 160 42
65 179 136 143 215 287 262 223 257 54 160 0 201
171 72 163 134 14 93 64 84 99 151 42 201 0


Возможно в данном примере нету таких мест, где более одного пробела, но такое надо рассматривать.

Есть ли у кого-то предложения, как данное содержимое грамотно считать в двумерный динамический массив для которого память на этом этапе уже выдана?

Выше, код того, как я пытался.

Автор: bsa 10.1.2010, 19:39
а почему нельзя воспользоваться scanf/fscanf/sscanf со спецификатором %d"?

Автор: Dayx 10.1.2010, 20:14
Много лет назад столкнулся с проблемой чтения разных строк.
Ну и создал себе такую маленькую функцию.
С тех пор горя не знаю...
Код

char *fgm(FILE *f)  /* Чтение строки с выделением памяти  */
{ char *b;  int c, j=0, l=81;

   if (f==NULL || feof(f)) return(NULL);
   b = malloc(l);
a: c = getc(f);
   if (c=='\n' || c==EOF) {
       b[j++] = '\0';
       if (j!=l) b = realloc(b,j);  // Чтоб лишнего не брать
       return(b);
   }
   if (j >= l-1) {
     l += 80;
     b = realloc(b,l);
   }
   b[j++] = c;
   goto a;
}

Конечно, надо еще проверять удачность выполнения malloc и realloc.
Но это уж каждый делает по своему вкусу...

Автор: bsa 10.1.2010, 21:28
Велосипедисты, блин. Тогда уж так:
Код
size_t getline(char **lineptr, size_t *n, FILE *stream)
{
   if ( !(lineptr && n && stream) ) {
       errno = EINVAL;
       return -1;
   }
   if ( *lineptr == NULL )
      *n = 0;
   else if (*n > 0)
      **lineptr = '\0';
   size_t pos = 0;
   for(; !feof(stream); ) { //пока файл не кончился
      if (pos >= *n) { 
          if (n == 0)
             n = 64;  //минимальный размер буфера, полностью выделяемого функцией
          else
             *n *= 2; //размер следующего буфера будет в 2 раза больше текущего
          *lineptr = (char*)realloc(*lineptr, *n); //увеличиваем буфер
          (*lineptr)[pos] = '\0'; //на всякий случай
      }
      fgets(*lineptr + pos, *n - pos, stream);
      pos += strlen(*lineptr + pos); //смещаем позицию на количество считанных символов
      if  ( (pos > 0) && ( (*lineptr)[pos - 1] == '\n' ) ) //если были считаны данные и последний символ строки равен '\n'
         return pos; //то строка считана полностью, возвращаем количество считанных символов
   }
   return -1; //возвращаем индикатор ошибки
}

Автор: Dayx 12.1.2010, 23:12
Цитата(bsa @  10.1.2010,  21:28 Найти цитируемый пост)
Велосипедисты, блин. 

Но в то время колеса у велосипедов были квадратные!
Все равно, спасибо

Автор: bsa 13.1.2010, 11:05
Цитата(Dayx @  12.1.2010,  23:12 Найти цитируемый пост)
Но в то время колеса у велосипедов были квадратные!
мне вообще непонятно, почему использовался goto вместо цикла (for или do/while)? Не слышал, что новичкам goto строго противопоказан?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)