Fstream не может создать новый файл - PullRequest
6 голосов
/ 26 января 2011

Я использую FileManager для проекта, так что чтение и запись не доставляют мне хлопот. Или было бы, если бы я не тратил все это время на его отладку. Итак, этот комфорт-класс действительно вызвал у меня стресс и время. Потрясающие.

Проблема, похоже, fstream. Прежде чем продолжить, вот структура моего класса FileManager.

class FileManager : Utility::Uncopyable
{
public:
    FileManager();

    void open(std::string const& filename);
    void close();

    void read(std::string& buffer);
    void write(std::string const& data);

private:
    std::fstream stream_;
};

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

Сценарий: простая регистрация пользователя в командной строке с последующей записью данных в файл. Я прошу имя и пароль. Имя копируется и добавляется с .txt (имя файла). Так это выглядит так:

void SessionManager::writeToFile(std::string const& name, 
                                 std::string const& password)
{
    std::string filename = name + ".txt";
    std::string data;
    data += name +", " +password;

    try
    {
        fileManager_->open(filename);
        fileManager_->write(data);
        fileManager_->close();
    } 
    catch(FileException& exception)
    {
        /* Clean it up. */
        std::cerr << exception.what() << "\n";
        throw;
    }
}

Проблема: не удается открыть. Файл никогда не создается, и во время записи я получаю исключение из-за отсутствия открытого файла.

Функция FileManager :: open ():

void FileManager::open(std::string const& filename)
{
    if(stream_.is_open())
        stream_.close();

    stream_.open(filename.c_str());
}

и напишите

void FileManager::write(std::string const& data)
{
    if(stream_.is_open())
        stream_ << data;
    else
        throw FileException("Error. No file opened.\n");
}

Однако, если я создаю файл заранее, то у него нет проблем с открытием файла. Тем не менее, когда я проверяю, по умолчанию std::ios::openmode составляет std::ios::in | std::ios::out. Я могу создать файл очень хорошо, когда я только отмечаю std::ios::out, но я хочу сохранить поток в состоянии чтения / записи.

Как мне это сделать?

Ответы [ 6 ]

7 голосов
/ 09 февраля 2011

Лучший метод:

void FileManager::open(std::string const& filename)
{
    using std::ios_base;
    if( stream_.is_open() )
        stream_.close();

    stream_.open( filename.c_str() ); // ...try existing file
    if( !stream_.is_open() ) // ...else, create new file...
        stream_.open(filename.c_str(), ios_base::in | ios_base::out | ios_base::trunc);
}

Таким образом, код проверяет существующий файл и, если нет, создает его.

3 голосов
/ 26 января 2011

Как мне это сделать?

std::ofstream file("file.txt");
file << data;

Разве это не проще?

3 голосов
/ 26 января 2011

Вы должны вызвать fstream::open с явным аргументом openmode

ios_base::in | ios_base::out | ios_base::trunc

В противном случае open не удастся из-за ENOENT.

Таблица 95 черновикаСтандарт C ++ перечисляет возможные режимы открытия файлов и их эквиваленты в stdio.По умолчанию ios_base::out | ios_base::in равно r+.Тот, который я перечислил выше, эквивалентен w+.ios_base::out | ios_base::app эквивалентно a.Все другие комбинации, включающие ios_base::app, недопустимы.

(На риск насмешки: вы можете переключиться на stdio и использовать файловый режим a+, который читает с начала и добавляет вконец.) * * тысяча двадцать-один

3 голосов
/ 26 января 2011

Нельзя использовать std::ios::in для несуществующего файла. Используйте

std::ios::in | std::ios::out | std::ios::trunc

вместо этого (но убедитесь, что он не существует или будет обрезан до нуля байтов).

2 голосов
/ 26 января 2011

Так работает библиотека: std::ios::in | std::ios::out открывает ее в эквиваленте stdio "r+", то есть открывает только существующий файл.Я не верю, что есть режим, который будет делать то, что вы хотите, вам придется нам вызов для конкретной ОС или проверить файл на наличие (опять же, используя вызов для конкретной ОС) и открыть его в одном режиме илидругой в зависимости от того, существует ли он.

Редактировать : Я предположил, что вы не хотите, чтобы файл был обрезан, если он уже существует.Как отметили другие люди, если вы счастливы урезать любой существующий файл, тогда опция in | out | trunc является опцией.

1 голос
/ 26 января 2011

Просто заставьте свою функцию открыться

void FileManager::open(std::string const& filename)
{
    using std::ios_base;
    if(stream_.is_open())
        stream_.close();

    stream_.open(filename.c_str(), ios_base::in | ios_base::out | ios_base::trunc);
}

, если вам нужен этот режим.

Нет волшебного способа открыть файл для чтения / записи, создав его, если он не существует, но не обрезая его (удаляя его содержимое), если он существует. Вы должны сделать это в несколько этапов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...