Reading in image files without specifying name - c++

Are there any facilities in SDL or C++ that allow you to read image files in from a folder without specifying their name, like reading them in sequential order, etc.? If not are there any techniques you use to accomplish something along the same lines?
Doing something like this:
foo_ani[0] = LoadImage("Animations/foo1.png");
foo_ani[1] = LoadImage("Animations/foo2.png");
foo_ani[2] = LoadImage("Animations/foo3.png");
can become quite tedious, and a loop can't be used because the file name is specific each time.
The only way I could really think of is maybe having a string that you modify through each loop iterator and insert the loop number into the specific part of the string assuming that's how your files are labeled, and using that string as the LoadImage parameter. That seems like more work though than just doing the above.

Use boost::filesystem.
The tiny program shown here lists all files in the directory files/, matching the pattern fileN.type, where N is from 0 and upwards, unspecified.
#include <iostream>
#include <sstream>
#include <string>
#include <boost/filesystem.hpp>
using namespace std;
namespace fs = boost::filesystem;
int main(int argc, char** argv)
{
fs::path dir ("./files");
string prefix = "file";
string suffix = "type";
int i = 0;
fs::path file;
do {
stringstream ss;
ss << prefix << i++ << "." << suffix;
file = fs::path(dir / fs::path(ss.str()));
if(fs::exists(file)) {
cout << file.leaf() << " exists." << endl;
}
} while(fs::exists(file));
return 0;
}
Link with -lboost_filesystem.
boost::filesystem also provides a simple directory iterator.

For this type of situation, you would typically get a list of the filenames in the directory (with opendir/readdir or FindFirstFile/FindNextFile as appropriate), and loop on each filename in the directory. Given each filename, you can call LoadImage() and append the result to your array.
This technique doesn't require that you know the filenames ahead of time.

How about loading all files in that directory automatically?
foo_ani = LoadImages("Animations/");
Just traverse the directory given and load all files inside that fit.
Another solution, if you have several animations with different prefix is to use regular expressions. I suggest you use boost for that or std::tr1::regex, like this:
foo_ani = LoadImageSet("Animations/", std::tr1::regex("foo*.png"));

Given that you are are currently hard coding the name of the frames, I'm going to assume you know / have control over the naming scheme of the files. I'm also assuming you want them sequentially since it seems to be frames in an animation. Finally I'm assuming you know how many frames there are since you seem to have an array big enough to accommodate them all ready and waiting.
Given the names of the files presented in the question, you can't just do FindFirst / FindNext because once you get past 10 frames, they're almost certainly going to come in out of order (given the naming scheme presented).
So I think that you're right that the best way to do it is in a loop, but wrong that it's more effort than doing it by hand.
char* fname = new char[50]; // buffer big enough to hold filenames
int numFrames = 8; // or however many, you seem to know what this value should be
for(int i = 0; i < numFrames; ++i)
{
sprint(fname, "Animations/foo%d.png",(i+1));
foo_ani[i] = LoadImage(fname);
}
delete[] fname;
That's about 6 lines of code. So for animations of more than 6 frames, I'd say that was easier.

Related

Save the variables of an object to then be able to initialise another object with those variables

What I am trying to achieve is this:
Let's say I have a class Score. This class has an int variable and a char* variable.
Now when I have an object Score score, I would like to be able to save the value of those variables (I guess to a file). So now this file has an int variable and a char* variable that I can then access later to create a new Score object.
So I create Score score(10, "Bert");. I either do something like score.SaveScore(); or the score gets saved when the game is over or the program exits, it doesn't matter.
Basically I am looking for the equivalent/correct way of doing this:
score.SaveScore(FILE file)
{
file.var1 = score.score;
file.var2 = score.name;
}
I realize this is probably very stupid and not done this way whatsoever! This is just me trying to explain what I am trying to achieve in the simplest way possible.
Anyway, when I run the program again, that original Score score(10, "Bert") does not exist any more. But I would like to be able to access the saved score(from file or wherever it may be) and create another Score object.
So it may look something like:
LoadScore(FILE file)
{
Score newScore(file.var1, file.var2);
}
Again, just trying to show what I am trying to achieve.
The reason why I want to be able to access the variables again is to eventually have a Scoreboard, the Scoreboard would load a bunch of scores from the file.
Then when a new score is created, it is added to the scoreboard, compared to the other scores currently in the scoreboard and inserted in the right position (like a score of 6 would go in between 9 and 4).
I feel like this was a bit long winded but I was trying to really explain myself well! Which I hope I did!
Anyway, I am not looking for someone to tell me how to do all of that.
All I am after is how to do the initial save to a file.
Thank you for any suggestions.
I would use the <fstream> library, like this;
//example values
int x=10;
float y=10.5;
const char* chars = "some random value";
string str(chars); //make string buffer for sizing
str.resize(20); //make sure its fixed size
//open a test.txt file, in the same dir for output
std::ofstream os("test.txt", std::ios::out | std::ios::binary); //make it output binary
//(char*) cast &x, sizeof(type) for values/write to file chars for x and y
os.write((char*)&x, sizeof(int)); //only sizeof(int) starting at &x
os.write((char*)&y, sizeof(float)); //cast as a char pointer
os.write(str.data(), sizeof(char)*str.size()); //write str data
os.close();
//the file test.txt will now have binary data in it
//to read it back in, just ifstream, and put that info in new containers, like this;
int in_x = 0; //new containters set to 0 for debug
float in_y = 0;
char inchar[20]; //buffer to write 20 chars to
ifstream is("test.txt", std::ios::in | std::ios::binary); //read in binary
is.read((char*)&in_x, sizeof(int)); //write to new containers
is.read((char*)&in_y, sizeof(float));
is.read((char*)&inchar, sizeof(char)*20); //write char assuming 20 size
is.close();
//outputting will show the values are correctly read into the new containers
cout << in_x << endl;
cout << in_y << endl;
cout << inchar << endl;
I realize this is probably very stupid and not done this way whatsoever!
The entire software industry was stupid enough to have it done so many times that even a special term was invented for this operation - serialization and nearly all C++ frameworks and libraries have implemented this in a various ways.
Since question is tagged with C++ I would suggest you to look at boost serialization but there are many other implementations.
Do you need that file to be readable by a human? If yes than consider, for example, XML or JSON formats.
You don't need it be readable but want it be as compact as possible? Consider google protobuf
Just start doing it and come with a more specific question(s).
As it was mentioned before, keep strings as std:string objects rather then char*
About writing/reading to/from files in C++ read about fstream

C++ Read file into Array / List / Vector

I am currently working on a small program to join two text files (similar to a database join). One file might look like:
269ED3
86356D
818858
5C8ABB
531810
38066C
7485C5
948FD4
The second one is similar:
hsdf87347
7485C5
rhdff
23487
948FD4
Both files have over 1.000.000 lines and are not limited to a specific number of characters. What I would like to do is find all matching lines in both files.
I have tried a few things, Arrays, Vectors, Lists - but I am currently struggling with deciding what the best (fastest and memory easy) way.
My code currently looks like:
#include iostream>
#include fstream>
#include string>
#include ctime>
#include list>
#include algorithm>
#include iterator>
using namespace std;
int main()
{
string line;
clock_t startTime = clock();
list data;
//read first file
ifstream myfile ("test.txt");
if (myfile.is_open())
{
for(line; getline(myfile, line);/**/){
data.push_back(line);
}
myfile.close();
}
list data2;
//read second file
ifstream myfile2 ("test2.txt");
if (myfile2.is_open())
{
for(line; getline(myfile2, line);/**/){
data2.push_back(line);
}
myfile2.close();
}
else cout data2[k], k++
//if data[j] > a;
return 0;
}
My thinking is: With a vector, random access on elements is very difficult and jumping to the next element is not optimal (not in the code, but I hope you get the point). It also takes a long time to read the file into a vector by using push_back and adding the lines one by one. With arrays the random access is easier, but reading >1.000.000 records into an array will be very memory intense and takes a long time as well. Lists can read the files faster, random access is expensive again.
Eventually I will not only look for exact matches, but also for the first 4 characters of each line.
Can you please help me deciding, what the most efficient way is? I have tried arrays, vectors and lists, but am not satisfied with the speed so far. Is there any other way to find matches, that I have not considered? I am very happy to change the code completely, looking forward to any suggestion!
Thanks a lot!
EDIT: The output should list the matching values / lines. In this example the output is supposed to look like:
7485C5
948FD4
Reading a 2 millions lines won't be too much slow, what might be slowing down is your comparison logic :
Use : std::intersection
data1.sort(data1.begin(), data1.end()); // N1log(N1)
data2.sort(data2.begin(), data2.end()); // N2log(N2)
std::vector<int> v; //Gives the matching elements
std::set_intersection(data1.begin(), data1.end(),
data2.begin(), data2.end(),
std::back_inserter(v));
// Does 2(N1+N2-1) comparisons (worst case)
You can also try using std::set and insert lines into it from both files, the resultant set will have only unique elements.
If the values for this are unique in the first file, this becomes trivial when exploiting the O(nlogn) characteristics of a set. The following stores all lines in the first file passed as a command-line argument to a set, then performs a O(logn) search for each line in the second file.
EDIT: Added 4-char-only preamble searching. To do this, the set contains only the first four chars of each line, and the search from the second looks for only the first four chars of each search-line. The second-file line is printed in its entirety if there is a match. Printing the first file full-line in entirety would be a bit more challenging.
#include <iostream>
#include <fstream>
#include <string>
#include <set>
int main(int argc, char *argv[])
{
if (argc < 3)
return EXIT_FAILURE;
// load set with first file
std::ifstream inf(argv[1]);
std::set<std::string> lines;
std::string line;
for (unsigned int i=1; std::getline(inf,line); ++i)
lines.insert(line.substr(0,4));
// load second file, identifying all entries.
std::ifstream inf2(argv[2]);
while (std::getline(inf2, line))
{
if (lines.find(line.substr(0,4)) != lines.end())
std::cout << line << std::endl;
}
return 0;
}
One solution is to read the entire file at once.
Use istream::seekg and istream::tellg to figure the size of the two files. Allocate a character array large enough to store them both. Read both files into the array, at appropriate location, using istream::read.
Here is an example of the above functions.

searching for hundreds of patterns in huge Logfiles

I have to get lots of filenames from inside a webserver's htdocs directory and then take this list of filenames to search a huge amount of archived logfiles for last access on these files.
I plan to do this in C++ with Boost. I would take newest log first and read it backwards checking every single line for all of the filenames I got.
If a filename matches, I read the Time from Logstring and save it's last access. Now I don't need to look for this file any more as I only want to know last access.
The vector of filenames to search for should rapidly decrease.
I wonder how I can handle this kind of problem with multiple threads most effective.
Do I partition the Logfiles and let every thread search a part of the logs from memory and if a thread has a match it removes this filename from the filenames vector or is there a more effective way to do this?
Try using mmap, it will save you considerable hair loss. I was feeling expeditious and in some odd mood to recall my mmap knowledge, so I wrote a simple thing to get you started. Hope this helps!
The beauty of mmap is that it can be easily parallelized with OpenMP. It's also a really good way to prevent an I/O bottleneck. Let me first define the Logfile class and then I'll go over implementation.
Here's the header file (logfile.h)
#ifndef _LOGFILE_H_
#define _LOGFILE_H_
#include <iostream>
#include <fcntl.h>
#include <stdio.h>
#include <string>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
using std::string;
class Logfile {
public:
Logfile(string title);
char* open();
unsigned int get_size() const;
string get_name() const;
bool close();
private:
string name;
char* start;
unsigned int size;
int file_descriptor;
};
#endif
And here's the .cpp file.
#include <iostream>
#include "logfile.h"
using namespace std;
Logfile::Logfile(string name){
this->name = name;
start = NULL;
size = 0;
file_descriptor = -1;
}
char* Logfile::open(){
// get file size
struct stat st;
stat(title.c_str(), &st);
size = st.st_size;
// get file descriptor
file_descriptor = open(title.c_str(), O_RDONLY);
if(file_descriptor < 0){
cerr << "Error obtaining file descriptor for: " << title.c_str() << endl;
return NULL;
}
// memory map part
start = (char*) mmap(NULL, size, PROT_READ, MAP_SHARED, file_descriptor, 0);
if(start == NULL){
cerr << "Error memory-mapping the file\n";
close(file_descriptor);
return NULL;
}
return start;
}
unsigned int Logfile::get_size() const {
return size;
}
string Logfile::get_title() const {
return title;
}
bool Logfile::close(){
if( start == NULL){
cerr << "Error closing file. Was closetext() called without a matching opentext() ?\n";
return false;
}
// unmap memory and close file
bool ret = munmap(start, size) != -1 && close(file_descriptor) != -1;
start = NULL;
return ret;
}
Now, using this code, you can use OpenMP to work-share the parsing of these logfiles, i.e.
Logfile lf ("yourfile");
char * log = lf.open();
int size = (int) lf.get_size();
#pragma omp parallel shared(log, size) private(i)
{
#pragma omp for
for (i = 0 ; i < size ; i++) {
// do your routine
}
#pragma omp critical
// some methods that combine the thread results
}
Parsing the logfile into a database table (SQLite ftw). One of the fields will be the path.
In another table, add the files you are looking for.
Now it is a simple join on a derived table. Something like this.
SELECT l.file, l.last_access FROM toFind f
LEFT JOIN (
SELECT file, max(last_access) as last_access from logs group by file
) as l ON f.file = l.file
All the files in toFind will be there, and will have last_access NULL for those not found in the logs.
Ok this is some days ago already but I spent some time writing code and working with SQLite in other projects.
I still wanted to compare the DB-Approach with the MMAP Solution just for the performance aspect.
Of course it saves you a lot of work if you can use SQL-Queries to handle all the data you parsed. But I really didn't care about the work amount because I'm still learning a lot and what I learned from this is:
This MMAP-Approach - if you implement it correctly - is absolutely superior in performance. It's unbelievable fast which you will notice if you implement the "word-count" example which can be seen as the "hello world" for MapReduce Algo.
Now if you further want to benefit from SQL-Language the correct approach would be implementing your own SQL-Wrapper that uses kind of Map-Reduce too by the means of sharing queries amongst threads.
You could perhaps share Objects by ID amongst threads, where every thread handles it's own DB-Connection. It then queries Objects in it's own part of the dataset.
This would be much faster than just writing things to SQLite DB the usual Way.
After all you can say:
MMAP is the fastest way to handle string processing
SQL provides great functionality for parser-applications but it slows down things if you don't implement a wrapper for processing SQL-Queries

C++ search a string

I am having a really hard time with this problem...
Write a program that reads two strings (that do not contain blanks)
called searchPattern and longSequence.
The program will display in the screen the positions where
searchPattern appears in longSequence.
For example, when
seachPattern is asd
and longSewuence is asdfasdfasdfasdf
(the positions are 0123456789012345)
the program will display 0, 4, 8, 12.
Another example, when
seachPattern is jj
and longSewuence is kjlkjjlkjjjlkjjjkl
(the positions are 012345678901234567)
the program will display 4, 8, 9, 13, 14.
can anyone help?
Some hints:
Read in the two strings. Look up "std::cin" for how to read and "std::string" for how to store the strings.
Look at the std::string class's find() method to search for the substring in the long string.
Have a go and then post what you have done on here. You will find plenty of people happy to help you, but you have to make some effort yourself. :-)
As a starting point, maybe just write the part that reads in the strings. When that is working well, you can add features.
Good luck.
To start thinking about the solution of problems like this, the best way is to think how you would solve it using a pen and paper in as much detail as possible and then try to translate that to code.
I would use Test Driven Development and start out small and build up.
For example, forget about user I/O, and stick with hard-coded data:
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;
int main(void) // For now, can be modified later.
{
const char pattern[] = "asd";
const char sequence[] = "asdfasdfasdfasdf";
std::string::size_type position = 0;
const std::string longSequence(sequence);
position = longSequence.find(pattern, position);
while (position != std::string::npos)
{
cout << "pattern found at position: " << position << endl;
position = longSequence.find(pattern, position);
}
cout << "Paused. Press ENTER to continue." << endl;
cin.ignore(100000, '\n');
return 0;
}
You may want to convert the above into using a state machine rather than using std::string::find(). Again, this is just a foundation to build upon.
It's a recursive backtracking problem. Just like getting the mouse out of the maze. Define your base cases and your paths through the data. In the end all you need is a single function of maybe 15 - 20 lines.

C++ external file read: I know how to find and read a string, findMe. But how do I deal with findMei (finding any number, i, of the string)?

Apologies in advance, because I suspect this may be a silly question.
I have written a function for reading in data from an external file. I then use the data to perform calculations using other code I have written.
The function works by finding a data label that looks like this:
const std::string findMe = "<dataLabel>";
Each time I want to find data, I replace dataLabel with the label of whichever data I need from the file.
Here's what I want to do.
I don't want to have to write in the label of the data I want each time. I want to be able to do this:
for (int i = 0; i < anyNumberOfDataSets; i++)
{
findMe = "<dataLabeli>";
// Then run function for reading in data, put data into a vector.
}
I could then add any number of data sets to my external file, give each one the title
, and have each data set read into a vector.
The problem is, I simply can't figure out how to write findMe = "<dataLabeli>". Is this even possible?
I have tried things like, findMe = "<dataLabel" << i <<, but no luck!
Any suggestions would be much appreciated.
It is very hard to understand what you mean, but I guess you want this
#include <sstream>
#include <string>
for (int i = 0; i < anyNumberOfDataSets; i++)
{
std::ostringstream strm;
strm << "<dataLabel" << i << ">";
const std::string findMe = strm.str();
//...
//proceed with searching findMe
}
You can read more about string streams, for instance, here
you've already got the right answer, so this is just trying to help you with solving such problems in the future:
Your core problem here is to convert the integer i into a string s (if you've done this, than you just do findMe = "<datalabel"; findMe += s; findMe += ">";.
Googling for c++ convert integer into string will give you this as the first result. Problem solved.
This is not saying "use google before/instead of asking", it's rather "try to identify the core problem".
Another solution:
using namespace boost;
findMe = str(format("<dataLabel%d>") % i);
This will substitute %d with the value of i, formatted like printf() does.