В С++ в файл пишутся разнообразные символы. Причем гарантированно из записанных символов хотя бы 1 – EOF(он же /0 он же 255 символ). Причем он может стоять как в начале, так и в середине так и в конце файла. после всего этого нужно считать их из файла в string. Кто-нибудь знает как это сделать?
17 сентября 2009 в 11:05
проверил, выдал всё, полез в документацию, в посиксе отменили различие текстовых и бинарных файлов и в линуксе эта функция совместима с посикс, т.е. понятия текстовых файлов там не осталось.
17 сентября 2009 в 11:04
проверил. выдало 00 и 04, так вот реализовано в винде… но лучше на это не закладываться, используйте системные функции для работы с информационными символами, а управляющими не злоупотребляйте от реализации к реализации аски могут очень различаться. та же новая строка где-то \r\n а где-то \n.
"Если 0×00 0×04, то как же с этим живут программисты под windows…"
правильные программисты не открывают бинарные файлы как текстовые
в 7-ой строчке добавляете букву b т.е.: dfile=fopen("data.dat", "rb"); и радуйтесь жизни.
#18 я же уже говорил в линуксе по умолчанию файлы открываются как бинарные. поставьте"rt" и попробуйте натыкать все предполагаемые концы файла, набейте файл 256 символов и в конце допишите пару букв натравить прогу и посмотрите все ли 258 символов считались?
17 сентября 2009 в 11:03
4-й символ это Ctrl+D, в юниксах обозначает конец файла при записи его из терминала или эмулятора терминала. Считается аналогом MS-DOS' овского Ctrl+Z. В линуксе конец файла – это физический конец файла, без разницы какие там символы. В CP/M, ка я понял, не был известен заранее размер текстового файла, и чтобы не прочесть лишнее, конец обозначался символом 26(0×1A). У меня программа вывела все вимволы, в винде наверное выведет
0×00
0×04
но все равно 0×1A != EOF, если говорить о EOF как об компиляторо-специфичной константе, а не аббревиатуре.
17 сентября 2009 в 9:02
Ну, теперь можешь пока считать, что ты несколько приблизился к истине, и помедитировать наедине с собой.
17 сентября 2009 в 9:02
просто вы путаете две вещи, символ eof и признак eof, константа EOF обычно равна -1 и возвращается fgetc при достижении конца потока, в данном случае текстового файла, в __кодировке__ в которой признаком конца потока принят __символ__ 0×1a . вам нужно разобраться что такое символ, что такое кодировка, что такое поток, конец потока и что такое конец файла, тогда станет ясно что конец текстового файла может не быть концом файла.
в линуксе по умолчанию файлы открываются как бинарные, (однажды пол дня ловил ошибку при переносе по как-раз в винде обрывалось чтение файла в середине), с тех пор в опен явно прописываю что бинарный и в других случаях стараюсь прописывать умолчательные флаги.
если не ошибаюсь в линуксе как-раз принят за обозначение конца потока конец перфокарты, т.е. 25-ый символ, но лучше проверить.
я не использую fgetc так как читать гораздо быстрей буферами, но скорей всего при открытии файла как бинарного она возвращает честные байты до самого честного конца файла, но лучше читать документацию, но читать её внимательно.
а ваш пример достаточно страшен, 00 символ вроде как по аски должен быть проигнорирован, за что отвечает 4 я не помню, дальше 3-ей позиции в файле fgetc не пойдёт. вполне вероятно что ваш fgets не выдаст вообще ничего вразумительного. но это предположения, как именно реализована в винде аски надо искать полное описание или экспериментировать. но в принципе в текстовых файлах управляющих символов быть не должно кроме перевода строки, каретки и конца файла(который можно не ставить).
16 сентября 2009 в 21:00
Я заглянул в стандарт. Сейчас в википедию, там написано, что 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.
16 сентября 2009 в 14:02
Кверос +1
Тимур Магомедов -1, умные люди говорят, что всё-таки 26 Так что вопрос о неучах остался открытым. Пробовал загуглить, прежде чем бить себя пяткой в грудь?
11 сентября 2009 в 0:00
с еофф там ещё всё хуже, он от оси зависит(вернее кодировки), в дос выньдов аски управляющий символ 26 это конец файла, а fgets возвращает номер символа, а если натыкается на конец файла то -1(вообще говоря он должен как-раз быть системо зависимым и на выньдосе и другой системе работать будет по разному и даже с локалями может быть корреляция)… из-за этой неразбирихи и не люблю работать с текстовыми файлами, хотя читаемость и компактность кода страдает зато я точно знаю какой байт где у меня лежит.
10 сентября 2009 в 23:04
в общем, понятно. ситуация как с NULL.
10 сентября 2009 в 23:03
C99:
EOF is 25 traditionally -1, but may be any negative integer, and hence distinguishable from any valid character code.
10 сентября 2009 в 22:04
что говорит по этому поводу стандарт?
10 сентября 2009 в 22:03
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. Сам учи матчасть, неуч.
10 сентября 2009 в 17:05
Кирилл, если EOF – cимвол 26, то как мне узнать, не дошел ли я до конца в бинарном файле?
10 сентября 2009 в 8:05
EOF имеет десятичный код 26. Учите матчасть.
Если хочешь читать файл за этот символ, открывай в двоичном режиме.
Кверос +1
Так как уровень знания матчасти оставляет ещё много надежд на будущее, то, с благими намерениями напоминаю, что не споткнуться бы вам ещё на NUL-символ в конце строки. А то начитаете, сколько надо, а потом будете думать, что у вас чтение об NUL споткнулось.
10 сентября 2009 в 0:03
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.
А предложенный метод – извините, почти что индийский говнокод.
9 сентября 2009 в 23:00
вобще-то eof это символ в потоке обозначающий конец файла. мало кто сейчас про это помнит.
Антон То-то Нургатин скорей всего вам нужно просто открывать файл не как текстовый (в компилерах под винду по умолчанию обычно файл открывается как текстовый). в случае бинарных файлов вам придётся самому разбивать всё на строки и т.д. но зато вы будете точно знать какой байт сейчас куда считывается.
если очень интересно, то можно в текстовых файлах читать дальше eof который в винде кодируется (как именно я уже не помню, помоему там комбинация из пары байт, нулевой байт вроде им не является.. надо найти спецификацию кодировки чтобы точно всё выверять).. вобщем читать дальше можно физически передвигая указатель в файле дальше признака конца файла ( lseek -ом) тогда читать можно будет до следующего признака конца файла. но это всё ересь, пишите прогу правильно открывая бинарный файл как бинарный.
9 сентября 2009 в 22:04
Василий, возможно я ошибаюсь но вроде 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();
}
оно сработало. так что спасибо.
9 сентября 2009 в 22:01
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 в конце.
9 сентября 2009 в 22:00
полагаю, тебе стоит обратиться к документации функции/метода, которой/которым ты читаешь из файла.
при достижении конца файла будет либо другое возвращаемое значение, либо некий errorState будет соответствующим.