Link to home
Start Free TrialLog in
Avatar of showbix
showbix

asked on

Read and write files

I would like to read a text file which contains 1000 lines of data (mainly text data) and split the contents into 4 output text files, in which each file will contain 250 lines of data.
I've noticed the need to use _hread function (Turbo C++ function) but need some sample programs related to it.
Please throw some ideas on this matter. My environment is Borland Turbo C++.
Avatar of Sys_Prog
Sys_Prog
Flag of India image

There are two approaches

1) You know the no of characters appearing in each line & it remains constant across all the lines

In this, u can use fread () to read       250 * No. Of Characters in Each Line       and then use write () to write this data to other file

2) The no of characters in each line is different
You should read line by line using getline() and write then other files keeping a count of the no of lines read & changing the other output file after each 250 lines have been written

Amit
The following example reads the first line & writes it to other file

#include <iostream>
#include <fstream>

using namespace std ;

int main(int argc, char* argv[])
{
      ifstream ifile ( "c:\\input.txt" ) ;
      ofstream ofile ( "c:\\output.txt" ) ;
      string line ;
      getline ( ifile, line ) ;
      ofile << line ;
      
    system("pause");
      return 0;
}



Amit
Likewise, as shown above, u could build the logic for writing 250 lines and then changing the output file

Here is a reference to the I/O library

http://www.cplusplus.com/ref/iostream/

Amit
Try this:

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

void main()
{
  ifstream ifs("x1000.dat");
  ofstream ofs1("x1.dat");
  ofstream ofs2("x2.dat");
  ofstream ofs3("x3.dat");
  ofstream ofs4("x4.dat");
  ofstream* pofsArr[] = { &ofs1, &ofs2, &ofs3, &ofs4 };
  ofstream* pofs = &ofs1;

  int nLines = 0;
  int nFile  = 0;
  string line;
  while (!ifs.eof())
  {
      getline(ifs, line);
      *pofs << line << endl;
      if ((++nLines)%250==0)
      {
          pofs = pofsArr[++nFile];
      }
  }

  for (int i = 0; i < 4; i++)
  {
     pofsArr[i]->close();
  }
}

Regards, Alex
Avatar of showbix
showbix

ASKER

Hi Sys_Prog.
Is your sample program work in Turbo C++?
Yep, it works

U probably have include this way

#include <iostream.h>
#include <fstream.h>

instead of

#include <iostream>
#include <fstream>

But the later one (as I shown in my example) is the new standard
Amit


Avatar of showbix

ASKER

Hi Sys_Prog.
declaration sysntax error at this line -->>using namespace std ;
Do not use
using namespace std ;


Just comment it
Amit
Avatar of showbix

ASKER

Hi Sys_Prog.
Can you explain me line by line your program code as I need to understand it.
The Turbo C++ compiler must be comliang to the old C++ standard,

Amit
Try this, that is 'old' C++ not using C++ Standard

#include <stdio.h>
#include <fstream.h>
#include <iostream.h>

void ff()
{
  ifstream ifs("x1000.dat");
  ofstream ofs1("x1.dat");
  ofstream ofs2("x2.dat");
  ofstream ofs3("x3.dat");
  ofstream ofs4("x4.dat");
  ofstream* pofsArr[] = { &ofs1, &ofs2, &ofs3, &ofs4 };
  ofstream* pofs = &ofs1;

  int nLines = 0;
  int nFile  = 0;
  char line[1024];
  while (!ifs.eof())
  {
      ifs.getline(line, sizeof(char));
      *pofs << line << endl;
      if ((++nLines)%250==0)
      {
          pofs = pofsArr[++nFile];
      }
  }

  for (int i = 0; i < 4; i++)
  {
     pofsArr[i]->close();
  }
}

Regards, Alex
int main(int argc, char* argv[])
{
     ifstream ifile ( "c:\\input.txt" ) ;              // declare an input stream type of object which is used to read a file, It also        opens the file "c:\\input.txt"
     ofstream ofile ( "c:\\output.txt" ) ;           // declare an output stream type of object which is used to write to a file, It also opens the file "c:\\output.txt" for writing
     string line ;                                            // Declare a string type of object to read a line
     getline ( ifile, line ) ;                               // Read a line from the input file and store it in the line variable
     ofile << line ;                                         // Write the read line into the output file
     return 0;
}

Amit
Sorry a typo, it should be

    sizeof(line)

and not

    sizeof(char)

Regards, Alex
Avatar of showbix

ASKER

Hi itsmeandnobodyelse.
Linker Warning.
No module definition file specified.

Linker Error.
Un defined symbol _main in library file C:\TCWIN45\LIB\cwl.lib in module winmain.

Could you explain me what's the error all about.
I made function ff() and not main() as i compiled it  using an existing project

Simply change

   void ff()

to

   int main(int argc, char* argv[])

and add

   return 0;

to the end of the function.

Regards, Alex

 



Avatar of showbix

ASKER

Hi itsmeandnobodyelse.
I have changed your code from
--->> void ff()
to
-->> int main(int argc, char* argv[])
and it works fine.
Avatar of showbix

ASKER

Hi

The content of my source file is like this
COMMAND=print  
LENGTH=63    
LENGTH_COL=32    
CUTFORM=nd70  
CUTFORM_DTL=rec  
DATA=I'm learning C++
COMMAND=print  
LENGTH=63    
LENGTH_COL=32    
CUTFORM=nd70  
CUTFORM_DTL=rec  
DATA=I'm also learning Java
COMMAND=print  
LENGTH=63    
LENGTH_COL=32    
CUTFORM=nd70  
CUTFORM_DTL=rec  
DATA=Now I'm trying to learn Turbo C++

and so on....
How do I check for
COMMAND, LENGTH, LENGTH_COL, CUTFORM, CUTFORM_DTL, DATA in every line, get the value of them and write to output files?






Avatar of showbix

ASKER

COMMAND, LENGTH, LENGTH_COL, CUTFORM, CUTFORM_DTL, DATA
is considered as one block of data. How do I read a block and write to a file, read next block and write to a new next file and so on.
Avatar of showbix

ASKER

I have increased the points as you guys really helpful in this problems.

     ...
     ifs.getline(line, sizeof(line));

     // find "=" , e. g. in "COMMAND=print"
     char* p = strchr(line, '=');
     if (p != NULL)  
         // p points now to "=print"
         *pofs << ++p << endl;       // skip '='
     else
         *pofs << line << endl;      
     ...

Regards, Alex
Avatar of showbix

ASKER

Hi itsmeandnobodyelse.
As per your code, the output are defined early in the process, that is
  ofstream ofs1("x1.dat");
  ofstream ofs2("x2.dat");
  ofstream ofs3("x3.dat");
  ofstream ofs4("x4.dat");

Is there any possibility to dynamically create the output file based on the total numbers of "data block".
-----------------------------------------------------------------------------
my previous question...
COMMAND, LENGTH, LENGTH_COL, CUTFORM, CUTFORM_DTL, DATA
is considered as one block of data. How do I read a block and write to a file, read next block and write to a new next file and so on.
------------------------------------------------------------------------------
Look at this,

#include <stdio.h>
#include <stdlib.h>
#include <fstream.h>
#include <iostream.h>
#include <string.h>

#define MAX_OPT  100
#define MAX_CMD  100
#define MAX_KEY  100
#define MAX_VAL  100

struct CommandOption
{
    char  pszKey[MAX_KEY];
    char  pszVal[MAX_VAL];
};

struct CommandData
{
    CommandOption* optArr[MAX_OPT];
    int            nOpts;
    CommandData() :  nOpts(0) { memcpy(optArr, 0, MAX_OPT*sizeof(CommandOption)); }
};

int main(int argc, char* argv[])
{
  ifstream ifs("x1000.dat");

  int nLines = 0;
  int nFile  = 0;
  char line[1024];
  char file[32] = "x";
  ofstream* pofs = NULL;

  CommandData* cmdArr[MAX_CMD];
  CommandData* pCmd = NULL;


  while (!ifs.eof())
  {
      ifs.getline(line, sizeof(char));
      if (strstr(line, "COMMAND=") == line)
      {
          if (pofs != NULL)
              pofs->close();

          itoa(nFile, &file[strlen(file)], 10);
          pofs = new ofstream(file);

          pCmd = cmdArr[nFile] = new CommandData;
      }
      if (pCmd != NULL)
      {
          // write full line to output file
          *pofs << line << endl;

          // find '='
          char* p = strchr(line, '=');
          if (p != NULL)  
          {
              *p = '\0';   // change '=' to terminating zero
              CommandOption* pOpt = new CommandOption;
              strcpy(pOpt->pszKey, line);
              strcpy(pOpt->pszVal, ++p);
              int n = pCmd->nOpts++;
              pCmd->optArr[n] = pOpt;

          }
      }
  }
  if (pofs != NULL)
      pofs->close();

  return 0;
}

That dynamically creates output files and all keys and values are stored to struct CommandOption. All options til next command get stored to struct CommandData and main holds an array of these. Maybe you have to increase MAX_.... constants or try to make it fully dynamically. You also have to add some checks on wrong input.

Regards, Alex

There is a missing

   ++nFile;

below

     pCmd = cmdArr[nFile] = new CommandData;


Regards, Alex

Avatar of showbix

ASKER

Hi itsmeandnobodyelse
1. The program hang.
2. What are name extension of the output files?

My sample data
COMMAND=display  
LENGTH=40    
LENGTH_COL=0    
CUTFORM=  
CUTFORM_DTL=  
DATA=   The testing data
COMMAND=display  
LENGTH=40    
LENGTH_COL=0    
CUTFORM=  
CUTFORM_DTL=  
DATA=   Payment   5.00    
COMMAND=display  
LENGTH=40    
LENGTH_COL=0    
CUTFORM=  
CUTFORM_DTL=  
DATA=   Payment   45.00    
COMMAND=display  
LENGTH=40    
LENGTH_COL=0    
CUTFORM=  
CUTFORM_DTL=  
DATA=Balance                        5.00    
COMMAND=printlogo  
LENGTH=25    
LENGTH_COL=140  
CUTFORM=nd70  
CUTFORM_DTL=rec  
DATA=                        
Avatar of showbix

ASKER

I have already put the "++nFile;" syntax in the code below.
-------------------------------------------------------------------------
      if (strstr(line, "COMMAND=") == line)
      {
          if (pofs != NULL)
              pofs->close();

          itoa(nFile, &file[strlen(file)], 10);
          pofs = new ofstream(file);

                   pCmd = cmdArr[nFile] = new CommandData;
          ++nFile;
      }
-------------------------------------------------------------------------
ASKER CERTIFIED SOLUTION
Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Axter
showbix,
There are free compilers available that are much more compliant to the correct C++ standard.
The GNU compiler is free, and would probably better for your requirements then Turbo C++.

I recommend you upgrade to something better.

See following links for free compilers and IDE's.


Bloodshed Dev-C++ Compiler is available at
http://www.bloodshed.nu/devc.html

http://visual-mingw.sourceforge.net/ (IDE ONLY)  use with MinGW compiler

http://www.mingw.org/index.shtml (MinGW compiler only)

http://www.delorie.com/ (DJGPP compiler only)

http://www.digitalmars.com/ (Digital Mars compiler only)

http://www.openwatcom.org/ (Watcom  compiler and IDE)

http://www.gnu.org/software/gcc/gcc.html (GCC compiler)

http://www.cygwin.com
Correction:
>>There are free compilers available that are much more compliant to the *current* C++ standard.
If you change to any of the Compilers Axter has recommended (i would buy  VC6.0 from ebay for little money) that supports C++ standard - and i recommend it also -, you had to do this:

#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <iostream>
#include <string>

using namespace std;

#define MAX_OPT  100
#define MAX_CMD  100

struct CommandOption
{
    string strkey;
    string strVal;
};

struct CommandData
{
    CommandOption* optArr[MAX_OPT];
    int            nOpts;
    CommandData() :  nOpts(0) { memset(optArr, 0, MAX_OPT*sizeof(CommandOption*));
    }
};

int main(int argc, char* argv[])
{
    ifstream ifs("x1000.txt");
  if (ifs.fail())
  {
      cout << "open failed" << endl;
      return 1;
  }

  int nLines = 0;
  int nFile  = 0;
  string line;
  string file = "x";
  ofstream* pofs = NULL;

  CommandData* cmdArr[MAX_CMD] = { NULL };
  CommandData* pCmd = NULL;

  int pos = 0;

  while (!ifs.eof())
  {
      getline(ifs, line);
      if ((pos = line.find("COMMAND=")) != string::npos )
      {
          if (pofs != NULL)
              pofs->close();
          char fnum[11];
          itoa(nFile, fnum, 10);
          file += fnum;
          file += ".txt";
          pofs = new ofstream(file);

          pCmd = new CommandData;    
          cmdArr[nFile++] = pCmd;
      }
      if (pCmd != NULL)
      {
          // write full line to output file
          *pofs << line << endl;

          // find '='
          pos = line.find('=');
          if (pos  != string::npos)  
          {
              CommandOption* pOpt = new CommandOption;
              pOpt->strKey = line.substr(0, pos);
              pOpt->strVal  = line.substr(pos+1);
              int n = pCmd->nOpts++;
              pCmd->optArr[n] = pOpt;

          }
      }
  }
  if (pofs != NULL)
      pofs->close();

  for (int i = 0; i < nFile; i++)
  {
      cout << "-------------------------  file x" << i << ".txt ----------------------" << endl;
      for (int n = 0; n < cmdArr[i]->nOpts; n++)
      {
          cout << cmdArr[i]->optArr[n]->strKey << "=" << cmdArr[i]->optArr[n]->strVal << endl;
      }
  }
  cout << "------------------------------------------------ ----------------------" << endl;
  cout << "Total: " << nFile << " files" << endl << endl;
  return 0;
}

Regards, Alex


Try this code,
this would work for any number of sections

#include <iostream>
#include <fstream>
#include <sstream>

using namespace std ;

int main(int argc, char* argv[])
{
      ifstream ifile ( "c:\\input.txt" ) ;
      fstream ofile ;
      
      int outFileCount = 0 ;
      string      outFileName ;
      string line ;
      
       ofile.open ( "c:\\outputFile1.txt", ofstream::out ) ;                  
      
      while ( getline ( ifile, line ) ) {
            if ( line.find ( "COMMAND=", 0 ) != string::npos )  {
                  outFileCount++ ;
                  ofile.close () ;
                  ostringstream s ;
                     s << outFileCount ;
                  outFileName = "c:\\outputFile" + s.str() + ".txt" ;
                  ofile.open ( outFileName.c_str(), ofstream::out ) ;            
            }
            ofile << line << endl ;
       }
      ofile.close () ;      
    system("pause");
      return 0;
}


Amit
Basically the logic goes this way

Read a Line from Input File
Check if it is containing "COMMAND=" string indicating that it is to be written in a new file
IF the line contains "COMMAND=", Close the output file already opened, Open a new file with a name generated as c:\outputFile1.txt OR c:\outputFile2.txt OR c:\outputFile3.txt........so on

Write the line to the file
Continue from first step


Amit
Bloodshed Dev-C++ Compiler is available at
http://www.bloodshed.nu/devc.html

is much much better (complaint) than VC++ 6.0

and its free

Amit
>>is much much better (complaint) than VC++ 6.0

My 2 Cents:
The GNU 3.x compiler is much better for C/C++ compliance then VC++ 6.0.
However, the available free IDE's are not as good as VC++ 6.0.

VC++ 6.0 has the best IDE out of all the compilers/IDE's I've used in the past.  (IMHO even better then VC++ 7.x)

So even though it has a poor rating for C/C++ compliance, I would still recommend it over the GNU compiler.

However, if you don't have the money to spend, then of course the GNU compiler is the best choice IMHO.
Avatar of showbix

ASKER

Hey guys,

I have tried execute code above but sometimes it throws "general protection error" and I suspect this is due to the file size and limitation of the functions being used.

I have read something about IO operation in Turbo C++ which mentioned that _hread and GlobalAlloc is good for reading file larger than 64K in size. Have any ideas of it?
Avatar of showbix

ASKER

Hi itsmeandnobodyelse.
I have tested your code with 2K size of source file and it works fine but when I tried with 48K size file, it throws "General Protection Error". What's that error means?
FYI, Several output files are generated in the directory.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of showbix

ASKER

Hi Amit.
Your program hang when it executed.
This is the file that I have modified i.e input and output path.
----------------------------------------------------------------------------
#include <iostream.h>
#include <fstream.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
        ifstream ifile ( "c:\tmp3\inputf.txt" ) ;
     ofstream ofile ;
     
     int outFileCount = 0 ;
     char line[100] ;
     
            ofile.open ( "c:\tmp3\out1.txt", ofstream::out ) ;
     
     while ( !ifile.eof() ) {
       ifile.getline ( line, 100 ) ;
       if ( strstr ( line, "COMMAND" ) != NULL ) {
            outFileCount++ ;
               ofile.close () ;
               
               // Generate the new file name
            char outFileName [30] = { '\0' } ;
            strcat ( outFileName, "c:\tmp3\out" ) ;
            char temp [10] = { '\0' } ;
            itoa ( outFileCount, temp, 10 ) ;
            strcat ( outFileName, temp ) ;
            strcat ( outFileName, ".txt" ) ;

            ofile.open ( outFileName, ofstream::out ) ;
       }
       ofile << line ;
      }
     ofile.close () ;
     cout << "done" ;
    return 0;
}
"c:\tmp3\out"

should be

"c:\\tmp3\\out"

Likewise, at other places also, wherever u use one backslash for a filepath, u should specify two

Amit
Avatar of showbix

ASKER

Hi amit.
The output format is wrong.
COMMAND=print  LENGTH=63    LENGTH_COL=32    CUTFORM=nd70  CUTFORM_DTL=rec  DATA=================================                      
It should be like this.
COMMAND=print
 LENGTH=63    
LENGTH_COL=32    
CUTFORM=nd70  
CUTFORM_DTL=rec  DATA=================================                      
showbix,

I get the output as u expect
Ayway, if u do not, then just replace the line
 ofile << line ;
with
 ofile << line << endl ;
in my code

Amit
Avatar of showbix

ASKER

Thanks amit.
Great solution from you. Hope you can look into my other Question at
https://www.experts-exchange.com/questions/20949578/What's-wrong-with-this-code.html
I changed the program by removing any limitations.

I don't know whether you'll need it after all.

Regards, Alex

#include <stdio.h>
#include <stdlib.h>
#include <fstream.h>
#include <iostream.h>
#include <string.h>

struct CommandOption
{
    char*  pszKey;
    char*  pszVal;
    CommandOption() : pszKey(NULL), pszVal(NULL) {}
    CommandOption( const char* pszK, const char* pszV)  
    {
        pszKey = new char[strlen(pszK)+1]; strcpy(pszKey, pszK);
        pszVal = new char[strlen(pszV)+1]; strcpy(pszVal, pszV);
    }
    ~CommandOption() { delete [] pszKey; delete [] pszVal; }
};

struct CommandData
{
    CommandOption** pOptArr;
    int             nOpts;
    CommandData() : nOpts(0), pOptArr(NULL) {}
    ~CommandData()
    {
        for (int i = 0; i < nOpts; i++)
            delete pOptArr[i];
        delete [] pOptArr;
    }
    void AddOpt(const char* pszK, const char* pszV)
    {
        CommandOption** pOpts = new CommandOption*[nOpts+1];
        if (nOpts > 0)
        {
            memcpy(pOpts, pOptArr, sizeof(CommandOption*)*nOpts);
            delete []pOptArr;
        }
        pOpts[nOpts++] = new CommandOption(pszK, pszV);
        pOptArr        = pOpts;
    }
};

int main(int argc, char* argv[])
{
    ifstream ifs("xall.txt", ios::in | ios::nocreate );
    if (ifs.fail())
    {
        cout << "open failed" << endl;
        return 1;
    }
   
    int nLines = 0;
    int nFile  = 0;
    char line[1024];
    char file[32] = "x";
    ofstream* pofs = NULL;
   
    CommandData** pCmdArr = NULL;
    CommandData** pCmds   = NULL;
    CommandData*  pCmd    = NULL;
   
   
    while (!ifs.eof())
    {
        ifs.getline(line, sizeof(line));
        if (strstr(line, "COMMAND=") == line)
        {
            if (pofs != NULL)
                pofs->close();
           
            itoa(nFile, &file[1], 10);
            strcpy(&file[strlen(file)], ".txt");
            pofs = new ofstream(file);
           
            pCmd  = new CommandData;
            pCmds = new CommandData*[nFile+1];
            if (pCmdArr != NULL)
            {
                memcpy(pCmds, pCmdArr, sizeof(CommandData*)*nFile);
                delete [] pCmdArr;
            }
            pCmds[nFile++] = pCmd;
            pCmdArr = pCmds;
        }
        if (pCmd != NULL)
        {
            // write full line to output file
            *pofs << line << endl;
           
            // find '='
            char* p = strchr(line, '=');
            if (p != NULL)  
            {
                *p = '\0';   // change '=' to terminating zero
                pCmd->AddOpt(line, ++p);  
            }
        }
    }
    if (pofs != NULL)
        pofs->close();
   
    for (int i = 0; i < nFile; i++)
    {
        cout << "-------------------------  file x" << i << ".txt ----------------------" << endl;
        for (int n = 0; n < pCmdArr[i]->nOpts; n++)
        {
            cout << pCmdArr[i]->pOptArr[n]->pszKey << "=" << pCmdArr[i]->pOptArr[n]->pszVal << endl;
        }
    }
    cout << "------------------------------------------------ ----------------------" << endl;
    cout << "Total: " << nFile << " files" << endl << endl;

    delete [] pCmdArr;
    return 0;
}
Avatar of showbix

ASKER

Thanks  itsmeandnobodyelse.
I still need your code eventhough Sys_Prog already done the solution earlier. BTW, thanks to you guys for helping me out.