singlepost

Есть ли жизнь после EOF или как считать из файла до его действительного конца, а не первого символа конца файла? << На главную или назад  

В С++ в файл пишутся разнообразные символы. Причем гарантированно из записанных символов хотя бы 1 – EOF(он же /0 он же 255 символ). Причем он может стоять как в начале, так и в середине так и в конце файла. после всего этого нужно считать их из файла в string. Кто-нибудь знает как это сделать?

57 ответов в теме “Есть ли жизнь после EOF или как считать из файла до его действительного конца, а не первого символа конца файла?”

  1. 19
    Нгамдкхе Кверос ответил:

    проверил, выдал всё, полез в документацию, в посиксе отменили различие текстовых и бинарных файлов и в линуксе эта функция совместима с посикс, т.е. понятия текстовых файлов там не осталось.

  2. 18
    Нгамдкхе Кверос ответил:

    проверил. выдало 00 и 04, так вот реализовано в винде… но лучше на это не закладываться, используйте системные функции для работы с информационными символами, а управляющими не злоупотребляйте от реализации к реализации аски могут очень различаться. та же новая строка где-то \r\n а где-то \n.

    "Если 0×00 0×04, то как же с этим живут программисты под windows…"
    правильные программисты не открывают бинарные файлы как текстовые ;-)

    в 7-ой строчке добавляете букву b т.е.: dfile=fopen("data.dat", "rb"); и радуйтесь жизни.

    #18 я же уже говорил в линуксе по умолчанию файлы открываются как бинарные. поставьте"rt" и попробуйте натыкать все предполагаемые концы файла, набейте файл 256 символов и в конце допишите пару букв натравить прогу и посмотрите все ли 258 символов считались?

  3. 17
    Тимур Магомедов ответил:

    4-й символ это Ctrl+D, в юниксах обозначает конец файла при записи его из терминала или эмулятора терминала. Считается аналогом MS-DOS' овского Ctrl+Z. В линуксе конец файла – это физический конец файла, без разницы какие там символы. В CP/M, ка я понял, не был известен заранее размер текстового файла, и чтобы не прочесть лишнее, конец обозначался символом 26(0×1A). У меня программа вывела все вимволы, в винде наверное выведет
    0×00
    0×04
    но все равно 0×1A != EOF, если говорить о EOF как об компиляторо-специфичной константе, а не аббревиатуре.

  4. 16
    Кирилл Быков ответил:

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

  5. 15
    Нгамдкхе Кверос ответил:

    просто вы путаете две вещи, символ eof и признак eof, константа EOF обычно равна -1 и возвращается fgetc при достижении конца потока, в данном случае текстового файла, в __кодировке__ в которой признаком конца потока принят __символ__ 0×1a . вам нужно разобраться что такое символ, что такое кодировка, что такое поток, конец потока и что такое конец файла, тогда станет ясно что конец текстового файла может не быть концом файла.

    в линуксе по умолчанию файлы открываются как бинарные, (однажды пол дня ловил ошибку при переносе по как-раз в винде обрывалось чтение файла в середине), с тех пор в опен явно прописываю что бинарный и в других случаях стараюсь прописывать умолчательные флаги.
    если не ошибаюсь в линуксе как-раз принят за обозначение конца потока конец перфокарты, т.е. 25-ый символ, но лучше проверить.

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

    а ваш пример достаточно страшен, 00 символ вроде как по аски должен быть проигнорирован, за что отвечает 4 я не помню, дальше 3-ей позиции в файле fgetc не пойдёт. вполне вероятно что ваш fgets не выдаст вообще ничего вразумительного. но это предположения, как именно реализована в винде аски надо искать полное описание или экспериментировать. но в принципе в текстовых файлах управляющих символов быть не должно кроме перевода строки, каретки и конца файла(который можно не ставить).

  6. 14
    Тимур Магомедов ответил:

    Я заглянул в стандарт. Сейчас в википедию, там написано, что 26 (0×1A) – это Ctrl+Z, используется в MS-DOS для обозначения конца файла или пользовательского ввода, унаследовав такое поведение от CP/M. Но что выдаст такая программа

    1 #include <stdio.h>
    2
    3 int main(int argc, char *argv)
    4 {
    5 FILE *dfile;
    6 int c;
    7 dfile=fopen("data.dat", "r");
    8 while((c=fgetc(dfile))!=EOF) {
    9 printf("0x%02x\n",c);
    10 }
    11 fclose(dfile);
    12 return 0;
    13 }
    14
    На бинарном файле

    0×00
    0×04
    0×1a
    0×1a
    0×1a
    0×1a
    0×1a
    0×1a
    0×1a
    0×1a
    0×37
    0×38
    0×39
    0×0a
    ?
    Если 0×00 0×04, то как же с этим живут программисты под windows…

    Я ещё погуглил, все-таки Substitute character (26) это Substitute character, из MS-DOS, а EOF- это EOF, значение <0, не совпадающее ни с одним символом, которое возвращают функции C.

  7. 13
    Кирилл Быков ответил:

    Кверос +1

    Тимур Магомедов -1, умные люди говорят, что всё-таки 26 :) Так что вопрос о неучах остался открытым. Пробовал загуглить, прежде чем бить себя пяткой в грудь?

  8. 12
    Нгамдкхе Кверос ответил:

    с еофф там ещё всё хуже, он от оси зависит(вернее кодировки), в дос выньдов аски управляющий символ 26 это конец файла, а fgets возвращает номер символа, а если натыкается на конец файла то -1(вообще говоря он должен как-раз быть системо зависимым и на выньдосе и другой системе работать будет по разному и даже с локалями может быть корреляция)… из-за этой неразбирихи и не люблю работать с текстовыми файлами, хотя читаемость и компактность кода страдает зато я точно знаю какой байт где у меня лежит.

  9. 11
    Леонид Максимов ответил:

    в общем, понятно. ситуация как с NULL.

  10. 10
    Тимур Магомедов ответил:

    C99:
    EOF is 25 traditionally -1, but may be any negative integer, and hence distinguishable from any valid character code.

  11. 9
    Леонид Максимов ответил:

    что говорит по этому поводу стандарт?

  12. 8
    Тимур Магомедов ответил:

    1 #include <stdio.h>
    2 int main(int argc, char *argv[])
    3 {
    4 printf("%d\n", EOF);
    5 }
    6
    $ gcc botva.c
    ./a.out
    -1
    EOF – не символ. Его десятичный код вне значений типа char. Сам учи матчасть, неуч.

  13. 7
    Владимир Муромский ответил:

    Кирилл, если EOF – cимвол 26, то как мне узнать, не дошел ли я до конца в бинарном файле?

  14. 6
    Кирилл Быков ответил:

    EOF имеет десятичный код 26. Учите матчасть.
    Если хочешь читать файл за этот символ, открывай в двоичном режиме.

    Кверос +1

    Так как уровень знания матчасти оставляет ещё много надежд на будущее, то, с благими намерениями напоминаю, что не споткнуться бы вам ещё на NUL-символ в конце строки. А то начитаете, сколько надо, а потом будете думать, что у вас чтение об NUL споткнулось.

  15. 5
    Тимур Магомедов ответил:

    EOF не типа char, поэтому он не "255 символ"
    Вот в C, например, есть функция int getchar(void); – она специально имеет тип int, а не char.
    Цитата из man'а:
    fgetc(),getc() and getchar() return the character read as an unsigned char cast to
    an int or EOF on end of file or error.

    А предложенный метод – извините, почти что индийский говнокод.

  16. 4
    Нгамдкхе Кверос ответил:

    вобще-то eof это символ в потоке обозначающий конец файла. мало кто сейчас про это помнит.

    Антон То-то Нургатин скорей всего вам нужно просто открывать файл не как текстовый (в компилерах под винду по умолчанию обычно файл открывается как текстовый). в случае бинарных файлов вам придётся самому разбивать всё на строки и т.д. но зато вы будете точно знать какой байт сейчас куда считывается.

    если очень интересно, то можно в текстовых файлах читать дальше eof который в винде кодируется (как именно я уже не помню, помоему там комбинация из пары байт, нулевой байт вроде им не является.. надо найти спецификацию кодировки чтобы точно всё выверять).. вобщем читать дальше можно физически передвигая указатель в файле дальше признака конца файла ( lseek -ом) тогда читать можно будет до следующего признака конца файла. но это всё ересь, пишите прогу правильно открывая бинарный файл как бинарный.

  17. 3
    Антон Нургатин ответил:

    Василий, возможно я ошибаюсь но вроде EOF это -1. а так как -1 в чар это 255 символ то рискну предположить что все-таки это одно и тоже.

    Предложеный метод также читает до еофа. но он меня натолкнул на мысли об этом
    string str;

    ifstream is;
    is.open("1.txt", ios::binary);
    if(is.good())
    {
    is.seekg( 0, ios::end );
    str.resize( is.tellg() );
    is.seekg( 0, ios::beg );

    is.read( (char*)str.data(), str.size() );
    is.close();
    }

    оно сработало. так что спасибо.

  18. 2
    Василий Степанов ответил:

    0 и 255 разные символы. А EOF вообще не символ.

    std::ostringstream oss;
    oss << std::ifstream("file", std::ios::binary).rdbuf();
    std::string s = oss.str();

    Нужно только понимать, что мы в первый раз скопировали память оператором <<, второй раз str() и третьий (на старых компиляторах без RVO) на конструкторе s.
    В жизни так никто не делает :)

    s.length() должно быть равен размеру файла.
    std::cout << s выведит до первого \0, что и ожидается от данной операции.
    s.c_str() будет поинтить на всю строку да ещё и с \0 в конце неё, но printf(s.c_str()) так же закончится на первом \0.
    s.data() будет поинтить на всю строку без \0 в конце.

  19. 1
    Аристарх Анонимусов ответил:

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

Клуб программистов работает уже ой-ой-ой сколько, а если поточнее, то с 2007 года.