0

I am new to C++. I was just going through some code and got this doubt.

The code had some CStringList defined somewhere. I wanted to print that to a file. So I wrote the below code

 CStringList *stringListDev;
 .....
 .....
 .....
 ..... 
 ofstream myfile("example.txt");
 for(int i=0; i<stringListDev->Count; i++)
 {
    myfile << stringListDev[i];
 }

I was getting an error saying << not defined on list or something. Please guide me how to write contents of a stringlist to a file in C++.

Ragesh Chakkadath
  • 1,521
  • 1
  • 14
  • 32

8 Answers8

1

CString and associated containers define their character type according to the UNICODE settings in the file. You can either stick to wofstream if your program always follows UNICODE character set. Otherwise, please enclose the definition as below. So you can make sure your program will compile in UNICODE and ASCII/MBCS character set.

#ifdef UNICODE
typedef ofstream tstream;
#else
typedef wofstream tstream;
#endif

tstream myfile("example.txt");

It is good to see about BOM characters and some caveats on reading/writing Unicode strings.

Community
  • 1
  • 1
sarat
  • 10,512
  • 7
  • 43
  • 74
1

CStringList class itself is a collection class, you don't want it to be pointer.

CStringList stringListDev;
ofstream myfile("example.txt"); 
for(int i=0; i<stringListDev.GetCount(); i++) 
{ 
  myfile << stringListDev[i]; 
}
Ajay
  • 18,086
  • 12
  • 59
  • 105
1

Let me rewrite your code like this.

CStringList stringListDev; // CStringList doesn't need to be a pointer.
 .....
 .....
 .....
 ..... 
 ofstream myfile("example.txt");
 for(int i=0; i<stringListDev.Count; i++)
 {
    myfile << stringListDev[i].GetBuffer(stringListDev[i].GetLength());
    stringListDev[i].ReleaseBuffer();
 }

CStringList class contains the list of CString objects which is another MFC class. for cout, I think you need an LPTSTR as input. So, use GetBuffer() function to get the same and don't forget to call ReleaseBuffer(). For more info, See the documentation

From my experience, Passing the GetBuffer with no arguments (default parameter is 0) also returns a pointer to string and you don't need to call ReleaseBuffer() as it returns the pointer to original string without any memory allocation. but I don't recommend that as it is not in the documentation.

Ragesh Chakkadath
  • 1,521
  • 1
  • 14
  • 32
  • pass 0 to GetBuffer if you're not supposed to modify it. Calling getbuffer is not adviced as long as you're not supposed to modify it. CString has LPCTSTR operator overloaded. – sarat Jul 29 '11 at 07:00
  • I agree that it is not safe. I didn't recommend it either! But what's wrong with the former way? we are releasing it soon after the use. – Ragesh Chakkadath Jul 29 '11 at 07:09
  • 1
    What if an exception comes? This might be suitable for this situation. It's more a programming practice to pass whatever we need and make it safe. If you've read Effective C++, there's an good suggestion about exposing internals pointer to outside world. It clearly tells the problem – sarat Jul 29 '11 at 09:26
  • Agreed! If passing CString object automatically gets converted to LPCTSTR, then there is no need of GetBuffer – Ragesh Chakkadath Jul 29 '11 at 09:40
  • 1
    Yea.. that's people don't realize. Most of the people don't know an operator LPCTSTR is there, even those who know the explicitly call is strObj.operator LPCTSTR(); explicitly. In that case there's no difference between a function and operator. – sarat Jul 29 '11 at 12:36
1

If it serves your purpose, you can use the CStringList::Serialize to write the contents of your object to a file. See the sample code:

CStringList csList;
csList.AddTail( L"A" ); // Filling sample data
csList.AddTail( L"B" );
csList.AddTail( L"C" );
CFile File( L"foo.txt", CFile::modeCreate | CFile::modeWrite ); // File opened using CFile object
CArchive Arch( &File, CArchive::store , MAX_PATH ); // Assign it to CArchive object
csList.Serialize( Arch ); // Call Serialize
Arch.Close();
File.Close();

This code write the contents of csList to foo.txt as binary data. You can load it to an object by similar way.

Reference

Serialization CArchive CFile

Community
  • 1
  • 1
Ragesh Chakkadath
  • 1,521
  • 1
  • 14
  • 32
0

If this is really a question about the MFC CStringList, then the iterations are not correct (at least for MFC in Visual Studio 2010).

CStringList stringListDev;
// add to list
POSITION pos = stringListDev.GetHeadPosition();
while(pos != NULL)
{
    CString value = stringListDev.GetNext(pos);
    myfile << (LPCTSTR)value; // cast to use built in operator
}

As a side note: MFC is pretty archaic in structure and design compared to the standard library, and I would recommend to only use them if strictly needed for interfacing with other MFC code (CDialog, etc.)

crashmstr
  • 28,043
  • 9
  • 61
  • 79
0

Instead of writing your own class, you should use std::vector and std::string as:

#include <vector>
#include <string>

std::vector<std::string> stringArray;

stringArray.push_back("some string");
stringArray.push_back("some other string");
//..

for(size_t i = 0 ; i < stringArray.size(); i++ )
    std::cout << stringArray[i] << std::endl;

And you can also use myfile in place of std::cout in the above code.

You can also replace the for loop with this:

#include <iterator>
#include <algorithm>

std::copy(stringArray.begin(), stringArray.end(), 
          std::ostream_iterator<std::string>(myFile,"\n"));
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • +1 (for suggesting using standard classes), -1 (for suggesting std::copy) = 0. – 6502 Jul 28 '11 at 08:47
  • 2
    @6502: yeah, I want to know too :) – Diego Sevilla Jul 28 '11 at 09:19
  • Nothing wrong, except that makes the code 25% longer (not counting extra includes), takes more time and more memory to compile, in case of a typo will spit ~5 screens full of nonsense babbling instead of a clear error message, it cannot be step through, it is way less flexible (for example adding line numbering in the explicit case is trivial) and finally it will probably run a bit slower (not sure of this, tho). Actually IMO excluding the "Hey mama... look! No explicit loop!" plus of this approach (if you really want to call that a plus) what is the good part of it? – 6502 Jul 28 '11 at 10:26
  • @6502: I agree with that. But I didn't suggest it to be the best, rather I wanted him to get *familiar* with other things which come with the standard library. For example, I know I can use `std::copy`, but I've never used it for my real code (to replace *loop*), because of the same reason you mentioned, but then just because its slow, doesn't mean that I shouldn't get familiar with this. – Nawaz Jul 28 '11 at 10:38
0

CStringList have GetAt(pos) method, which returns CString. To output CString to ofstream use CT2A.

myfile << CT2A(stringListDev->getAt(i));

And don't forget close file:

myfile.close();

UPD Also you can use std::wofstream.

wofstream myfile("example.txt");
myfile << (LPCTSTR) stringListDev->getAt(i);
red1ynx
  • 3,639
  • 1
  • 18
  • 23
  • LPCTSTR is Long Pointer Constant TCHAR String . wofstream is solely UNICODE stuff. it works if project is of UNICODE stuff. Otherwise it will fail – sarat Jul 28 '11 at 09:29
0

I got it myself. The code was very simple

   CStringList *stringListDev;
   .....
   .....
   .....
   ..... 
   ofstream myfile("example.txt");
   for(int i=0; i<stringListDev->Count; i++)
   {
      myfile << stringListDev->Strings[i];
   }

Thanks for all your responses!! You people rock !!