Thread: file manager

  1. #1
    Sanity is for the weak! beene's Avatar
    Join Date
    Jul 2006
    Posts
    321

    file manager

    I have created what looks like a basic file manager class for my text engine, it compiles and runs with no warnings but it dusn't ouput the text in the file.

    I have no idea how to fix it, maybe someone here could help me out with the problem.

    Here is the code......

    CFile_mngr.h

    Code:
    #include<fstream>
    
    class CFile_mngr
    {
        public:
        /*CFile_mngr();
        ~CFile_mngr();*/
    
        /*function to load a file*/
        void CLoad_file(std::string filename);
    
        protected:
        std::string filename; /*the filename*/
        std::string file_contents; /*file contents to be read*/
        std::ifstream fin; /*instance of ifstream*/
    };
    CFile_mngr.cpp

    Code:
    #include "CFile_mngr.h"
    #include <iostream>
    #include <fstream>
    
    void CFile_mngr::CLoad_file(std::string filename)
    {
        fin >> file_contents; /*read the contents of the file into file_contents*/
        std::cout << file_contents << std::endl;
    }
    CMain.cpp

    Code:
    #include "CFile_mngr.h"
    #include <iostream>
    #include <fstream>
    
    int main()
    {
        CFile_mngr CFile;
        CFile.CLoad_file("example.txt");
        std::cin.get();
        return 0;
    }
    .....it's probably a simple problem but i can't find it :'(

    All help is appreciated.

  2. #2
    The superhaterodyne twomers's Avatar
    Join Date
    Dec 2005
    Location
    Ireland
    Posts
    2,273
    Well... in the load file method you should open fin with the filename, and fin-ning file_contents will not read the whole file it'll only read the first segment to whitespace.

    fin.open( filename.c_str() );
    cin >> file_contents;
    std::cout<< file_contents << "\n";

    To read the whole file you could think about looping through and getline()ing every line and adding to contents. Or file contents could be a vector of strings with each line being an element. Or there's something about rdbuf around. Opening the file in binary format can give you the size of it too and you can read it in one big chunk.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    How about opening the file before trying to read it?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Sanity is for the weak! beene's Avatar
    Join Date
    Jul 2006
    Posts
    321
    Thanks, i'm not on the ball tonight :'(

    How would I go about adding each line to different elements in the vector i now have?

  5. #5
    The superhaterodyne twomers's Avatar
    Join Date
    Dec 2005
    Location
    Ireland
    Posts
    2,273
    Code:
    #include <string>
    #include <vector>
    
    // ...
    
    std::string line;
    std::vector<std::string> vec;
    while ( std::getline( fin, line ) )
      vec.push_back( line );

  6. #6
    Sanity is for the weak! beene's Avatar
    Join Date
    Jul 2006
    Posts
    321
    Thanks, that did work, but then i loaded up another file and nothing printed.....very strange.....
    Anyways, heres the code:

    CFile_mngr.h

    Code:
    #include<fstream>
    #include<vector>
    
    class CFile_mngr
    {
        public:
        /*CFile_mngr();
        ~CFile_mngr();*/
    
        /*function to load a file*/
        void CLoad_files();
    
        /*function to read the contents of a file*/
        void CRead_file_contents(std::string filename);
    
        protected:
        std::string filename; /*the filename*/
        std::string line; /*line of text*/
        std::vector<std::string>file_contents; /*file contents to be read*/
        std::ifstream fin; /*instance of ifstream*/
    };
    CFile_mngr.cpp

    Code:
    #include "CFile_mngr.h"
    #include <iostream>
    #include <fstream>
    
    /*define the function we declared in the CFile_mngr class*/
    void CFile_mngr::CRead_file_contents(std::string filename)
    {
        while(std::getline(fin, line))
        {
            file_contents.push_back(line); /*add a line to the end of the vector*/
        }
        for(int x = 0; x < file_contents.size(); x++) /*while x = 0, and x is smaller than file_contents, incrememt x*/
        {
            std::cout << file_contents[x]; /*output the file_contents*/
        }
    }
    
    void CFile_mngr::CLoad_files()
    {
        fin.open("example.txt"); /*open the txt file*/
        fin.open("example2.txt");
    }
    CMain.cpp

    Code:
    #include "CFile_mngr.h"
    #include <iostream>
    #include <fstream>
    
    int main()
    {
        CFile_mngr CFile;
        CFile.CLoad_files();
        CFile.CRead_file_contents("example2.txt");
        std::cin.get();
        return 0;
    }
    Starting to bug me now :'(

    Can anyone help?

  7. #7
    The superhaterodyne twomers's Avatar
    Join Date
    Dec 2005
    Location
    Ireland
    Posts
    2,273
    Well. Your stream can't have two simultaneous streams open. There's no need for the load files method (at least not yet), so don't call it. Just fstr.open(filename.c_str()) in the CRead_file method. Also the methods might want to return bools in case the streaming fails. Is there something in example2.txt?

  8. #8
    Sanity is for the weak! beene's Avatar
    Join Date
    Jul 2006
    Posts
    321
    Yes, there's something in example2.txt, and in my game there's going to be more than 1 text file so i want to distinguish between them and read them when i choose to, that's why i used std::string filename for the parameters of CRead_file_contents, but that dusn't work, should i make more than 1 instance of ifstream? 1 for each file?

  9. #9
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    You could have your file manager have a map of file classes, associated with the name of the file. Each file class of yours can have the stream it needs or the vector of lines of the text file or whatever represents a file in your game.

  10. #10
    Sanity is for the weak! beene's Avatar
    Join Date
    Jul 2006
    Posts
    321
    Never really thought of that, how would i go about that? Is there an easier way?

  11. #11
    The superhaterodyne twomers's Avatar
    Join Date
    Dec 2005
    Location
    Ireland
    Posts
    2,273
    I'd say concentrate on what you are doing at the moment and then think about the possible enhancements. Does the class work yet? Make it work for one stream and then add the map or vector or array or whatever.

    >> how would i go about that?
    Well... I did something very very like this before... here's an extremely cut down version of it:
    Code:
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <vector>
    #include <map>
    #include <algorithm>
    
    class fmngr {
    private:
      typedef std::map<std::string, std::ifstream*> stream_map;
      typedef std::map<std::string, std::vector<std::string> > contents_map;
    
      stream_map file_streams;
      contents_map file_contents;
    
    
    public:
      fmngr( void ) {
      }
      ~fmngr( void ) {
        for ( stream_map::iterator iter=file_streams.begin(), end=file_streams.end();
          iter != end; iter++ ) 
            delete *iter->second;
      }
    
      void read_file( const std::string &filename ) {
        // No error checking done here! Needs to be added
        file_streams[filename] = new std::ifstream(filename.c_str());
        
        std::string line;
    
        while ( std::getline( *file_streams[filename], line ) )
          file_contents[filename].push_back( line );
      }
    
      friend std::ostream &operator << ( std::ostream &out, fmngr inst ) {
        fmngr::contents_map::iterator iter( inst.file_contents.begin() ), 
                                      end ( inst.file_contents.end() );
        for ( ; iter != end; iter ++ ) {
          std::copy( iter->second.begin(), 
                     iter->second.end(), 
                     std::ostream_iterator<std::string>( out, " | " ) );
          out<< "\n";
        }
        return out;
      }
    };
    
    
    int main( void ) {
      fmngr mang;
    
      mang.read_file( "example1.txt" );
      mang.read_file( "example2.txt" );
    
      std::cout<< mang;
    
      return 0;
    }
    My output:
    This is a test | And it | should hopefully | work! |
    This is a second test | woof! |
    Which is correct.

    you could alternatively create a structure which has the stream and vector grouped in one variable if you wanted. Would probably be better.

  12. #12
    Sanity is for the weak! beene's Avatar
    Join Date
    Jul 2006
    Posts
    321
    You might have to help me through this, I need you to explain a few things about your code, if you don't mind ofcourse.

    Code:
    #include <algorithm>
    ....what's that there for?

    Code:
    typedef std::map<std::string, std::ifstream*> stream_map;
    typedef std::map<std::string, std::vector<std::string> > contents_map;
    ...can you explain exactly what is going on here?

    Code:
    delete *iter->second;
    ....what's the ->second in there for?

    Code:
    file_streams[filename] = new std::ifstream(filename.c_str());
    ...i think i have an idea on what's going on here but can you explain it anyways?

    Code:
    friend std::ostream &operator << ( std::ostream &out, fmngr inst ) {
    fmngr::contents_map::iterator iter( inst.file_contents.begin() ), 
                                                     end ( inst.file_contents.end() );
    for ( ; iter != end; iter ++ ) {
        std::copy( iter->second.begin(), 
        iter->second.end(), 
        std::ostream_iterator<std::string>( out, " | " ) );
        out<< "\n";
        }
        return out;
      }
    ....i understand some of that but i decided to copy and paste all of it because i would still like to get it cleared up.

    Thanks.
    Last edited by beene; 10-28-2007 at 10:23 AM.

  13. #13
    Sanity is for the weak! beene's Avatar
    Join Date
    Jul 2006
    Posts
    321
    I have implimented your method twomers, but i get this error:

    Code:
    error: 'ostream_iterator' is not a member of 'std'
    ...any ideas?

  14. #14
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    You need to #include <ostream> or <iterator>, I cannot remember which offhand.

    EDIT:
    Silly of me, of course you already have <iostream>, so it should be #include <iterator>.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  15. #15
    The superhaterodyne twomers's Avatar
    Join Date
    Dec 2005
    Location
    Ireland
    Posts
    2,273
    OK...

    (algorithm) Well you include <string> for std::string. You include algorithm for a number of useful functions. Here it's for std::copy (I think).

    (typedef) The typedef-fing is simply to make things look simpler - I knew when I was writing the above that I'd be using those maps all over the place and it would get on my nerves all the time (to both do the typing and reading), so making typedefs of the variables help. Or do you mean what's being typdeffed? The first associates a string with an input file stream. The second associates a string with a vector of strings. In both cases the string is the name of a file.

    (new) In the stream mapping I have a pointer to a stream. Try to have it as just a regular variable. It's not allowed. I believe it's the same reason why streams must be passed by reference but never cared enough to see . I allocate a new stream which is defaulted to the name of the file passed into the function. Streams take a c-style string and what's passed into the function is a std::string so you need to use its c_str() method.

    (second) Maps associate one variable with a second. So there are two 'variables' in each element - first and second. Earlier I used new to create a stream for each element and when you use new you must use delete but since only the second part of the map (the stream), was dynamically allocated you only delete that second part. In the above case that's the second parameter of the map. So you use the iterator's "->second" return the stream to delete it.

    (operator<<) The number of elements in the maps are a function of the number of files you need to load. So your last query iterates through the file contents map on a per-file basis and prints out what's stored in the vector... the std::copy is equivalent to going through the vector element by element and printing out. (ie for (size_t i=0; i<vec.size(); i++)).

    Anything else?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Encryption program
    By zeiffelz in forum C Programming
    Replies: 1
    Last Post: 06-15-2005, 03:39 AM
  2. archive format
    By Nor in forum A Brief History of Cprogramming.com
    Replies: 0
    Last Post: 08-05-2003, 07:01 PM
  3. Making a LIB file from a DEF file for a DLL
    By JMPACS in forum C++ Programming
    Replies: 0
    Last Post: 08-02-2003, 08:19 PM
  4. System
    By drdroid in forum C++ Programming
    Replies: 3
    Last Post: 06-28-2002, 10:12 PM
  5. Need a suggestion on a school project..
    By Screwz Luse in forum C Programming
    Replies: 5
    Last Post: 11-27-2001, 02:58 AM