2015-01-18 5 views
3

Почему, когда я использую следующий фрагмент кода, результат равен нулю независимо от размера файла, но когда я удаляю ios::binary в open(), он делает то, что он должен делать?Почему этот код всегда возвращает нулевой размер файла?

fstream f1;  
streampos begin, end; 
f1.open("file1", ios::binary); 
f1.seekg(0, ios::beg); 
begin = f1.tellg(); 
f1.seekg(0, ios::end); 
end = f1.tellg(); 
f1.close(); 
cout << end - begin << endl; 
+1

Это честно расстраивает меня, как люди могут писать код, который не проверяет наличие ошибок. Просто почему?! –

ответ

8

Я полагаю, что «когда я удалить ios::binary» вы имеете в виду вы удалите весь аргумент:

f1.open("file1"); 

Функция open() имеет два параметра - имя файла и режим. В режиме один есть аргумент по умолчанию std::ios_base::in | std::ios_base::out. Поэтому, если вы ничего не укажете, это использование будет использовано.

Если вы укажете ios::binary, однако, вы установили вместо аргумента по умолчанию. И так как вы не указали ни in, ни out, вызов open() не выполняется. Помещение if() вокруг open() сообщит вам —. Помните, что вы всегда должны проверять наличие ошибок с помощью ввода-вывода.

+1

Ха-ха ... прекрасная демонстрация того, почему проверка ошибок важна. – bgoldst

+0

thanx Angew, но почему этот код работает? 'ifstream myfile (" example.bin ", ios :: binary);' – MojeeKD

+1

@MojtabaKarimdokht Очевидно, что вы будете использовать 'std :: basic_ifstream' для ввода, чтобы конструктор вызывал' open' в буфере через 'rdbuf() -> open (s, mode | ios_base :: in) 'где режим' ios_base :: binary' в вашем случае. – 0x499602D2

0

Если вы получаете размер 0, проверьте, чтобы увидеть, если файл открыт ...

#include<iostream> 
#include<fstream> 

using namespace std; 

int main(){ 

    fstream f1; 
    streampos begin, end; 
    f1.open("Data.txt", ios::binary); 
    if (f1.is_open()) { 
     cout << "Open" << endl; 
    } 
    f1.seekg(0, ios::beg); 
    begin = f1.tellg(); 
    f1.seekg(0, ios::end); 
    end = f1.tellg(); 
    f1.close(); 
    cout << end - begin << endl; 

    system("pause"); 
} 

Если это не так открыто, вы, возможно, пытались открыть текстовый файл.

В текстовых файлах ios :: двоичный флаг не включен в режим открытия. Текстовые файлы предназначены для хранения текстовых данных и при выполнении двоичных операций ввода/вывода, это может привести к форматированию преобразований.

+0

Что заставляет вас думать, что открытие любого файла в двоичном режиме является проблемой? Двоичный режим является нормой. Текстовый режим существует только для перевода символов конца строки на конкретную строку в '' \ n'' при чтении и обратно при записи. Сам файл - это просто (двоичные) данные на диске. – Angew

+0

Когда я пытаюсь открыть текстовый файл с двоичным флагом, file.is_open() возвращает false. Когда этот флаг будет удален, откроется файл. – dspfnder

+0

Какая ОС и файловая система? Должно быть довольно экзотическая комбинация для различения двоичных и текстовых файлов, подобных этому. Или вы делаете ту же ошибку, что и OP, и передаете * just * 'ios :: binary' в' fstream :: open() '(без' ios :: in' или 'ios :: out')? – Angew

1

std::ios_base::binary сам по себе не является действительным открытым моментом для std::basic_fstream. Допустимые комбинации OpenMode можно найти в таблице 132:

Конструктор std::basic_fstream и способ его open() как вперед метод open() на внутренней std::basic_filebuf через rdbuf()->open(s, mode), где mode является OpenMode. Как видно из таблицы, mode (где режим ios_base::binary) сам по себе не является допустимым. Когда буфер файла определяет это открыть файл не удалось:

НТБ modstr определяется из mode & ~ios_base::ate, как указано в таблице 132. Если mode не какая-то комбинация флагов, показанных в таблице, то открытое терпит неудачу.

Причина mode не побитовое-с out | in AND-ed при открытии файла, потому что это не ясно, хотите ли вы использовать поток для ввода или вывода (это предполагает, что вы знаете, что вы хотите). Поскольку режим не является допустимой комбинацией флагов, std::basic_filebuf::open() возвращает нулевой указатель. Это поднимается потоком, который в свою очередь вызывает setstate(std::ios_base::failbit).

[..] звонки rdbuf()->open(s, mode). Если эта функция возвращает нулевой указатель, вызывает setstate(failbit).

Когда поток находится в состоянии сбоя, его методы tell возвращают -1. Вот почему вы получаете 0 при вычитании.

Это правильный путь, чтобы открыть его, если все, что вы хотите, размер:

std::fstream f1("file1", std::ios_base::in | std::ios_base::ate | std::ios_base::binary); 
std::cout << f1.tellg(); 
+0

О, боже мой! Я не знал, что проблема имеет этот сложный длинный страшный фон! : O – MojeeKD