Когда будет поток: open fail?

Я пытаюсь попробовать, ловить, вызывать утверждения в С++ для обработки файлов, и я написал фиктивный код, чтобы поймать все ошибки. Мой вопрос заключается в том, чтобы проверить, правильно ли я прав, мне нужна ошибка. Теперь я легко могу проверить infile.fail(), просто не создавая файл требуемого имени в каталоге. Но как я могу проверить то же самое для outfile.fail() (outfile is ofstream, где as infile - ifstream). В этом случае будет ли значение для outfile.fail() истинным?

пример кода [по комментариям к ответу ундерссона, упрощенному, чтобы сделать проблему более ясной -zack]:

#include <fstream>
using std::ofstream;

int main() 
{
    ofstream outfile;
    outfile.open("test.txt");
    if (outfile.fail()) 
        // do something...... 
    else 
        // do something else..... 
    return 0; 
}

Ответы

Ответ 1

open(2) man-страница в Linux имеет около 30 условий. Некоторые интересные:

  • Если файл существует, и у вас нет разрешения на его запись.
  • Если файл не существует, и у вас нет разрешения (в директории) для его создания.
  • Если у вас нет разрешения на поиск в каком-либо родительском каталоге.
  • Если вы передадите фиктивный char* для имени файла.
  • Если при открытии файла устройства нажмите CTRL-C.
  • Если ядро ​​обнаружило слишком много символических ссылок при разрешении имени.
  • Если вы попытаетесь открыть каталог для записи.
  • Если длина пути слишком длинная.
  • Если ваш процесс имеет слишком много файлов, открывайте их уже.
  • Если в системе слишком много файлов, открываемых уже.
  • Если имя пути относится к файлу устройства, и в системе нет такого устройства.
  • Если в ядре закончилась память.
  • Если файловая система заполнена.
  • Если компонент пути не является каталогом.
  • Если файл находится в файловой системе только для чтения.
  • Если файл является исполняемым файлом, который в настоящее время выполняется.

Ответ 2

По умолчанию и по дизайну потоки С++ никогда не вызывают исключения при ошибке. Вы не должны пытаться писать код, который предполагает, что они делают, даже если их можно получить. Вместо этого в вашей логике приложения проверяйте каждую операцию ввода-вывода на ошибку и обрабатывайте ее, возможно, выбирая собственное исключение, если эта ошибка не может быть решена в конкретном месте, которое оно встречается в вашем коде.

Канонический способ тестирования потоков и потоков - это не проверка определенных флагов потока, если только не нужно. Вместо этого:

ifstream ifs( "foo.txt" );

if ( ifs ) {
   // ifs is good
}
else {
   // ifs is bad - deal with it
}

аналогично для операций чтения:

int x;
while( cin >> x ) {
     // do something with x
}

// at this point test the stream (if you must)
if ( cin.eof() ) {
     // cool - what we expected
}
else {
     // bad 
}

Ответ 3

Чтобы сбой ofstream::open завершился неудачей, вам необходимо организовать невозможность создания именованного файла. Самый простой способ сделать это - создать каталог с таким же именем перед запуском программы. Вот почти полная демо-программа; чтобы надежно удалить тестовый каталог тогда и только тогда, когда вы его создали, я оставляю как упражнение.

#include <iostream>
#include <fstream>
#include <sys/stat.h>
#include <cstring>
#include <cerrno>

using std::ofstream;
using std::strerror;
using std::cerr;

int main() 
{
    ofstream outfile;

    // set up conditions so outfile.open will fail:
    if (mkdir("test.txt", 0700)) {
        cerr << "mkdir failed: " << strerror(errno) << '\n';
        return 2;
    }

    outfile.open("test.txt");
    if (outfile.fail()) {
        cerr << "open failure as expected: " << strerror(errno) << '\n';
        return 0;
    } else {
        cerr << "open success, not as expected\n";
        return 1;
    }
}

Нет никакого хорошего способа гарантировать, что запись в файл fstream завершится неудачно. Я, вероятно, создаю mock ostream, который не смог выполнить запись, если мне нужно было проверить это.