16

Im trying to copy a whole .txt file into a char array. My code works but it leaves out the white spaces. So for example if my .txt file reads "I Like Pie" and i copy it to myArray, if i cout my array using a for loop i get "ILikePie"

Here is my code

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

int main () 
{
  int arraysize = 100000;
  char myArray[arraysize];
  char current_char;
  int num_characters = 0;
  int i = 0;

  ifstream myfile ("FileReadExample.cpp");

     if (myfile.is_open())
        {
          while ( !myfile.eof())
          {
                myfile >> myArray[i];
                i++;
                num_characters ++;
          }      

 for (int i = 0; i <= num_characters; i++)
      {

         cout << myArray[i];
      } 

      system("pause");
    }

any suggestions? :/

user2710184
  • 307
  • 2
  • 3
  • 8
  • arraysize should be const. – Rapptz Aug 23 '13 at 08:26
  • The use of `!myfile.eof()` is incorrect. Even if you wanted to read words, rather than all of the characters, you're using the results of `myfile >> myArray[i]` without verifying that it succeeded, which is incorrect. If you want to read all of the characters, then `while ( myfile.get( myArray[i] ) ) ++i;` would work (but you'd still need bounds checking). But Nemanja's answer is far superior. – James Kanze Aug 23 '13 at 08:37

5 Answers5

46

With

myfile >> myArray[i]; 

you are reading file word by word which causes skipping of the spaces.

You can read entire file into the string with

std::ifstream in("FileReadExample.cpp");
std::string contents((std::istreambuf_iterator<char>(in)), 
    std::istreambuf_iterator<char>());

And then you can use contents.c_str() to get char array.

How this works

std::string has range constructor that copies the sequence of characters in the range [first,last) note that it will not copy last, in the same order:

template <class InputIterator>
  string  (InputIterator first, InputIterator last);

std::istreambuf_iterator iterator is input iterator that read successive elements from a stream buffer.

std::istreambuf_iterator<char>(in)

will create iterator for our ifstream in (beginning of the file), and if you don't pass any parameters to the constructor, it will create end-of-stream iterator (last position):

The default-constructed std::istreambuf_iterator is known as the end-of-stream iterator. When a valid std::istreambuf_iterator reaches the end of the underlying stream, it becomes equal to the end-of-stream iterator. Dereferencing or incrementing it further invokes undefined behavior.

So, this will copy all characters, starting from the first in the file, until the next character is end of the stream.

Nemanja Boric
  • 20,271
  • 6
  • 61
  • 86
  • 1
    This is, of course, the correct answer, but there are two details worth pointing out: first, if you want to see exactly the bytes in the file, you should open it in binary mode, and ensure that the file is imbued with the `"C"` locale; otherwise, various translations may occur. Second, if the file contains null characters, `contents.c_str()` is not the way to go. More generally, in such cases, I'd use `contents.data()` (but I don't see any reason not to work directly on the string). – James Kanze Aug 23 '13 at 08:40
  • @JamesKanze, thank you for the suggestions. I din't used binary mode, and I suggested `c_str`, as I assumed that OP is using ASCII txt files. However, thank you for the commenting, as this is the best way for me (and for the others) to learn something new (like "C" locale - I have no idea what is it, so I will look it up). – Nemanja Boric Aug 23 '13 at 08:43
  • 1
    It wasn't clear to me whether the OP wanted the exact bytes of the file in the string, or whether he wanted a textual representation of the string. My comments refer to the case where he wants the exact bytes; your code, exactly as written, is fine for an internal representation of the text in the file (assuming it is text---but otherwise, `std::vector` would make more sense than string. – James Kanze Aug 23 '13 at 09:18
  • Just a quick mention - I was typing out a long question before I remembered where I saw this before: https://stackoverflow.com/q/1424510/1043529. The 'extra' parentheses resolve the "most vexing parse". – John P Oct 03 '17 at 09:29
14

Use the following code snippet:

FILE *f = fopen("textfile.txt", "rb");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);

char *string = (char *)malloc(fsize + 1);
fread(string, fsize, 1, f);
fclose(f);

string[fsize] = 0;
Nick Mertin
  • 950
  • 10
  • 25
Didac Perez Parera
  • 3,513
  • 2
  • 42
  • 82
1

A simple solution if you're bound to using char arrays, and minimal modification to your code. The snippet below will include all spaces and line breaks until the end of the file.

      while (!myfile.eof())
      {
            myfile.get(myArray[i]);
            i++;
            num_characters ++;
      }  
HyperionX
  • 765
  • 1
  • 13
  • 29
  • This is the definition of poor performance. Good demonstration, just terrible for practicality because reading byte by byte really taxes the disk. – Jack Giffin Jan 09 '17 at 23:18
  • Thanks for the feedback, can you please provide a better solution for future readers? – HyperionX Jan 11 '17 at 00:36
  • Would you say this is potentially poor, or just poor? Also, poor as in speed or as in complexity? I don't know much about the hardware layer, but I assumed the compiler would do some unrolling/vectorization that would make the performance comparable (especially since the data is only pairwise-dependent.) As a general rule I use 'one-liner' methods where available over loops, but if I'm concerned about *speed*, I'd also be concerned about behind-the-scenes virtual method penalties and the like. – John P Oct 03 '17 at 09:39
1

A much simpler approach would be using the get() member function:

while(!myfile.eof() && i < arraysize)
{
    myfile.get(array[i]); //reading single character from file to array
    i++;
}
Theja
  • 2,428
  • 3
  • 11
  • 17
1

Here is the code snippet you need:

#include <string>
#include <fstream>
#include <streambuf>
#include <iostream>


int main()
{
  std::ifstream file("name.txt");
  std::string str((std::istreambuf_iterator<char>(file)),
                        std::istreambuf_iterator<char>());

  str.c_str();

  for( unsigned int a = 0; a < sizeof(str)/sizeof(str[0]); a = a + 1 )
  {
    std::cout << str[a] << std::endl;
  }

  return 0;
}
double-beep
  • 3,889
  • 12
  • 24
  • 35
GeneralCode
  • 444
  • 3
  • 13