Ifstream open () не устанавливает биты ошибок, когда аргумент является каталогом - PullRequest
9 голосов
/ 07 марта 2012

В программе на C ++, используя std :: ifstream, я пытаюсь открыть указанный пользователем файл - пока все хорошо. Однако я случайно ввел имя файла, которое на самом деле является каталогом, и я был очень удивлен, увидев, что попытка открыть () этот каталог не вызвала никаких ошибок.

Вот минимальный пример:

std::ifstream f;
f.open("..");
if(!f.is_open() || !f.good() || f.bad() || f.fail()) {
    std::cout << "error bit set on open" << std::endl;
    return 1;
}

Здесь нет признаков ошибки. Если я продолжу и попытаюсь получить getline (), getline () установит бит ошибки в порядке.

std::string str;
getline(f, str);

if(f.eof()) std::cout << "getline set eofbit" << std::endl;
else if(f.bad()) std::cout << "getline set badbit" << std::endl;
else if(f.fail()) std::cout << "getline set failbit" << std::endl;

Выводит "getline set badbit", что является разумным. Использование оператора >> вызывает исключение из-за переполнения, что тоже нормально.

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

Кроме того, почему это так? Я понимаю, что это все те же данные с точки зрения программы, но я бы предположил, что ОС также отправит сообщение типа "эй, это каталог".

1 Ответ

4 голосов
/ 07 марта 2012

Вы не говорите, что ваша система, так что трудно сказать, но в целом, filebuf::open вернет ошибку только если ваш системный уровень открыт выходит из строя. И я работал на системах Unix, где вы могли open() каталог; Я даже работал над некоторыми, где вы могли бы прочитать это после открыть (по крайней мере, если это была локально смонтированная файловая система).

Что делать с этим: все, что я могу придумать, это попытаться get первый персонаж, а затем положить его обратно. Но это не удается, если файл пусто, так что на самом деле это тоже не решение. На системном уровне (и с точки зрения QoI, я бы ожидал, что filebuf::open сделает это, если система позволила открыть каталог), вы можете использовать вызов системного уровня (stat в Unix), чтобы определить, является ли файл каталогом или нет. (Конечно, есть условие гонки: между моментом, когда вы обнаружите, что это обычный файл, и в тот момент, когда вы делаете открытие, другой процесс может удалить файл и создать каталог. Это, вероятно, не частое возникновение, однако.)

...