2011-01-26 32 views
6

Estoy usando un FileManager para un proyecto, de modo que la lectura y la escritura no son tan complicadas para mí. O lo sería, si no me hubiera pasado todo este tiempo depurándolo. Entonces, esta clase de confort realmente me causó estrés y tiempo. Increíble.Fstream no puede crear un nuevo archivo

El problema parece ser el fstream. Antes de seguir adelante, aquí está la estructura de mi clase 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_; 
}; 

Muy simple. El búfer se carga con datos durante la función de lectura, el parámetro de datos es lo que se debe escribir en el archivo. Antes de leer y escribir, debe abrir el archivo o arriesgarse a recibir una gran excepción en su cara. Algo así como el que estoy obteniendo ahora.

Escenario: Registro simple de línea de comandos de un usuario, y luego escribir los datos en un archivo. Pido un nombre y una contraseña. El nombre se copia y se agrega con .txt (el nombre de archivo). Por lo tanto, se ve así:

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; 
    } 
} 

Problema: la apertura falla. El archivo nunca se crea, y durante la escritura obtengo una excepción por no tener un archivo abierto. función

el FileManager :: Open():

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

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

y escribir

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

Sin embargo, si se crea el archivo de antemano, entonces no tiene ningún problema de abrir el archivo. Sin embargo, cuando reviso, el valor predeterminado std::ios::openmode es std::ios::in | std::ios::out. Puedo crear el archivo muy bien cuando solo marque std::ios::out, pero quiero mantener la transmisión en un estado de lectura/escritura.

¿Cómo puedo lograr esto?

Respuesta

7

Mejor método:

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); 
} 

lo que las pruebas de código para un archivo existente y, si no, la crea.

2

Así es como funciona la biblioteca: std::ios::in | std::ios::out la abre en el equivalente de stdio 's "r+", es decir, solo abrirá un archivo existente. No creo que haya un modo que haga lo que usted desea, deberá hacernos una llamada específica del sistema operativo o verificar la existencia del archivo (nuevamente, utilizando una llamada específica del sistema operativo) y abrirlo en un modo o el otro dependiendo de si ya existe.

Editar: Supuse que no deseaba que el archivo se truncara si ya existe. Como han señalado otras personas, si está contento de truncar cualquier archivo existente, entonces in | out | trunc es una opción.

3

No puede usar std::ios::in en un archivo no existente. Use

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

en su lugar (pero asegúrese de que no existe o se truncará a cero bytes).

3

usted tiene que llamar fstream::open con un openmode argumento explícito de

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

De lo contrario open fallará debido a ENOENT.

La Tabla 95 del borrador de las listas estándar de C++ permite abrir los modos abiertos y sus equivalentes en stdio.El valor predeterminado es ios_base::out | ios_base::in es r+. El que enumeré arriba es equivalente a w+. ios_base::out | ios_base::app es equivalente a a. Todas las otras combinaciones que implican ios_base::app no son válidas.

(A riesgo de ser burlado de:. Usted podría cambiar a stdio y utilizar el modo de archivo a+, que lee desde el principio y añade al final)

+0

Desde C++ 11, 'ios_base :: app' por sí mismo está permitido, y es equivalente a" a ". Vea la Tabla 132 en C++ 11 o C++ 14 para la tabla actualizada. –

3

¿Cómo puedo lograr esto?

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

¿No es más sencillo?

+0

"pero quiero mantener la transmisión en un estado de lectura/escritura". –

+0

Admitiré que no veo el punto en esta clase 'FileManager', pero el OP quiere una secuencia de lectura/escritura. –

1

acaba de obtener su función para abrir

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); 
} 

si ese es el modo de servicio deseado.

No existe una forma mágica para abrir un archivo de lectura/escritura, crearlo si no existe pero no truncarlo (eliminando su contenido) si lo hace. Tienes que hacer eso en varios pasos.

Cuestiones relacionadas