Sign in to follow this  
brandonman

Reading Text file to an array

Recommended Posts

brandonman    102
I'm currently working on terrain, and I need to know how to read a text file to a 1D or 2D array, which ever. I know how to read to say, a string, but not an array. any help is appreciated. edit: in C++

Share this post


Link to post
Share on other sites
Palidine    1315
Well. If it's a text file then it's a string. Read the string, convert it to an int or whatever and store it in your array. You'll need to parse the string looking for separators like spaces or tabs or whatever you delineate your data with.

Basically:
1: read a line of text
2: loop over the line creating substrings of the characters that appear between the spaces/tabs
3: for each substring, try to convert it to the correct datatype and if the conversion is successful, store it in your array.

You may need to loop over everything once to count the size of the array you need to allocate (unless you're using a dynamic container like std::vector or std::list).

Better, of course, would be to have a program to generate a binary file of terrain data since string parsing is: (1) a giant pain in the butt (2) really slow.

-me

Share this post


Link to post
Share on other sites
antiquechrono    100
You really didnt say enough about what you are doing to get proper advice. If you just want to flat out read a text file into a character array then here is how...


#include <iostream>
#include <fstream>
#include <memory>

using namespace std;

int main(){
int length; //length of the file
auto_ptr<char> myarray; //pointer to character array
ifstream in_file("myfile.txt", ios::binary); //open file for input

if(in_file.is_open()){ //if the file is open continue with operations

in_file.seekg(0, ios_base::end); //go to the end of the file
length = in_file.tellg(); //see how many bytes the last operation skipped
in_file.seekg(0, ios_base::beg); //go back to beginning

myarray.reset(new char[length]); //create a new array
in_file.read(myarray.get(),length); //read the file into the array
}
//No need to delete the char array
//Don't acctually have to close the file but it is a nice to do so anyway
in_file.close();

return 0;
}



If you need to parse individual words from the file like the previous poster suggested then you should probobly [google] strtok or string tokenizer.

Also if effiency matters then you should probobly ignore Palidine's suggestion to read in a line at a time as I believe it is very inefficient unless the file is acctually in memory. Due to the nature of hard drives the time it takes to return one byte or its maximum is going to be the same so you should grab as many as possible. However I'm going off older information and it may or may not be right.

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
Original post by antiquechrono
You really didnt say enough about what you are doing to get proper advice. If you just want to flat out read a text file into a character array then here is how...

*** Source Snippet Removed ***

If you need to parse individual words from the file like the previous poster suggested then you should probobly [google] strtok or string tokenizer.


1) You wouldn't normally open a text file in binary mode, and you usually don't want to read the whole thing into an array either.

2) Parsing *words* is normally done most effectively with good old operator>>. In somewhat more complex circumstances, std::getline is useful.

3) Even strtok()'s own documentation says never to use it.

Quote:
Also if effiency matters then you should probobly ignore Palidine's suggestion to read in a line at a time as I believe it is very inefficient unless the file is acctually in memory. Due to the nature of hard drives the time it takes to return one byte or its maximum is going to be the same so you should grab as many as possible. However I'm going off older information and it may or may not be right.


4) The stream object buffers all reads from disk anyway, so this is irrelevant.

5) It's a bad idea to talk about the situation "if efficiency matters" preemptively, when presenting introductory material.

Share this post


Link to post
Share on other sites
antiquechrono    100
Quote:
Original post by Zahlman
1) You wouldn't normally open a text file in binary mode, and you usually don't want to read the whole thing into an array either.

If all the op wants is to move a whole file into an array then thats a great way to do it. If we are talking about a 4GB file then of course thats dumb, but if its a 100k file then theres nothing wrong with it depending on what you need it for. Then again the op has not said exactly what he wants so I can only guess.

Quote:

2) Parsing *words* is normally done most effectively with good old operator>>. In somewhat more complex circumstances, std::getline is useful.

Yes that is a fine solution, but by all means not the only one. Again, we don't know what the op wants unless I am the only one who was slightly confused by the post

Quote:

3) Even strtok()'s own documentation says never to use it.

Where is your source? Just because it isn't thread safe and can bite you in the rear if you are feeling stupid while using it does not make the tool broken. Some people will use it and others won't, it is a personal prefrence. If the op researched my suggestions then he could learn how it works. There is certainly nothing stopping him from writing his own implementation.

Quote:

4) The stream object buffers all reads from disk anyway, so this is irrelevant.

My bad, I forgot that they were buffered.

Quote:

5) It's a bad idea to talk about the situation "if efficiency matters" preemptively, when presenting introductory material.

It's also a bad idea to try and correct people's assumptions based on a vague post. For all we know at this point he may not need to "parse" anything.

Share this post


Link to post
Share on other sites
brandonman    102
Sorry I didn't post more details, the forums had some sort of problem last night. I'm just trying to read a file that has either a line of numbers like so:
 1253795 
or a number on each line:

1
4
9
7
3



whichever would work good for loading it into an array for the heights of a terrain.

Share this post


Link to post
Share on other sites
antiquechrono    100
Yeah I was having problems last night as well. Just put a space between each number or a number on each line and this will work.


#include <iostream>
#include <fstream>
#include <vector>

using namespace std;

int main(){

ifstream file("myfile.txt");
int temp;
vector<int> myarray;

while(file >> temp){
myarray.push_back(temp);
}

for(int i=0; i < (int)myarray.size(); i++){
cout << myarray[i]<<" ";
}

system("pause");

return 0;
}

Share this post


Link to post
Share on other sites
rip-off    10976
antiquechrono be aware that in your first code example you used a std::auto_ptr instance to hold the address of something allocated with new []. This is incorrect, as the std::auto_ptr destructor will call delete on this, not delete [] which is required.

Moral: never use new[]/delete[] Always use std::vector or boost::array.

Share this post


Link to post
Share on other sites
antiquechrono    100
Quote:
Original post by rip-off
antiquechrono be aware that in your first code example you used a std::auto_ptr instance to hold the address of something allocated with new []. This is incorrect, as the std::auto_ptr destructor will call delete on this, not delete [] which is required.

Moral: never use new[]/delete[] Always use std::vector or boost::array.


Ugh, that is what I get for trying to be creative lol. Thanks for the heads up though.

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
Original post by antiquechrono
Quote:

3) Even strtok()'s own documentation says never to use it.

Where is your source?


Um, strtok()'s own documentation. If you're on a Unix-compatible system, try 'man strtok'. Otherwise, try googling that. Third hit for me.

Quote:
(Emphasis mine)
BUGS
Never use this function. This function modifies its first
argument. The identity of the delimiting character is
lost. This function cannot be used on constant strings.


It's actually right there, literally, for many implementations.

Of course, there would be plenty of reason not to use it in C++ anyway: it's yet another function treating null-delimited sequences of text as somehow special, instead of supporting an actual string type.

Incidentally, the null-delimited approach to string representation is pretty brain-dead. Compared to the main not-a-real-string-type alternative - "raw Pascal strings", where a length count is stored at the beginning of the string, they are never any better algorithmically, prevent you from including nulls in the string text (which is useful for some applications), and generally speaking, save a whopping three bytes of memory. (It's possible to encode the length count as a variable length integer, squeezing things out even more, while adding at most constant overhead to each operation.) This string representation was chosen by the C language implementors back in the 70s, when those three bytes were important (and when optimizing compilers might have not gotten the same or better performance out of a loop over array indices as a loop while characters are non-zero). It's ancient and barbaric and really should be forgotten.

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
Original post by antiquechrono
Quote:
Original post by rip-off
antiquechrono be aware that in your first code example you used a std::auto_ptr instance to hold the address of something allocated with new []. This is incorrect, as the std::auto_ptr destructor will call delete on this, not delete [] which is required.

Moral: never use new[]/delete[] Always use std::vector or boost::array.


Ugh, that is what I get for trying to be creative lol. Thanks for the heads up though.


By the way, a rough paraphrase from interviews with Bjarne Stroustrup:

Q. Why is there no std::auto_ptr equivalent for arrays?
A. That is what std::vector is for.

Although, std::vector allows some extra things that you don't always want. If saving a couple words of memory (by not remembering a size and capacity) is more important to you, consider boost::scoped_array. (The boost::array is different; it's not dynamic, and requires a compile-time size as a template argument. It exists for the purpose of getting around C++'s legacy rules for passing arrays between functions etc., letting you treat arrays like actual objects.)

Share this post


Link to post
Share on other sites
brandonman    102
antiquechrono, it doesn't seem to read it. I run that code, but i just get system("pause")'s thing: Press any key to continue... Nothing is printing.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this