Reputation: 1518
friends! Programming language is C++. I have a byte matrix
unsigned char Map[Height][Width];
I initialize it with zeros. Then I read byte matrix from text file. Of course, text file can be larger, than my matrix is. In this case I must read information from file in such way:
Text file has extra information. I don't need it. In another case Matrix can be larger then information within text file:
In this case program must read all the information from file. The part of matrix that didn't get information from file is already initialized. It's OK.
What is the best way to read information from file to the matrix in my case?
I tried to use fgets
, but it reads all information from file in consecutive way - byte after byte. But I don't need to read extra bytes. Of course, I can read file byte after byte and check counter. But I am sure that this is'nt best solution. Does a better solution exist?
The formatting of my text file is'nt relevant here. I read information from file like bytes field.
Upvotes: 1
Views: 3468
Reputation: 4237
Read the entire file into a buffer:
FILE *fp;
long len;
char *buf;
fp=fopen("thefileyouwanttoread.txt","rb");
fseek(fp,0,SEEK_END); //go to end
len=ftell(fp); //get position at end (length)
fseek(fp,0,SEEK_SET); //go to beg.
buf=(char *)malloc(len); //malloc buffer
fread(buf,len,1,fp); //read into buffer
fclose(fp);
Copy the file into your byte array, check to see which is bigger to determine how to copy:
char *startByteArr;
unsigned char Map[Height][Width];
startByteArr = &Map[0][0];
if (len > Height*Width){
memcpy(startByteArr,buf,Height*Width);
else {
memcpy(startByteArr,buf,len);
}
This assumes that the first dimension is the same though. To account for varying width in the file, you could change the memcpy like:
char *startByteArr;
char *EndLineFile;
int lineLengthFile;
EndLineFile = strstr (buf,"\r\n");
lineLenghtFile = (int)(EndLineFile-buf);
unsigned char Map[Height][Width];
startByteArr = &Map[0][0];
int i;
if (lineLengthFile > Width){
for(i = 0; i < Height;i++){
memcpy(startByteArr+i*Width,buf+i*lineLengthFile,Width);
}
else {
for(i = 0; i < Height;i++){
memcpy(startByteArr+i*Width,buf+i*lineLengthFile,lineLengthFile);
}
}
I believe that would be the fastest way, just grab the whole file into memory in one read, then memcpy the segments you need to a byte array.
Upvotes: 1
Reputation: 55395
Assuming your text files look something like this:
3254352
6536543
8875687
4315254
5345435
1212122
the solution with standard library streams would be something like this:
#include <fstream>
#include <string>
int main()
{
std::ifstream matrix_file("matrix.txt");
const size_t Width = 5;
const size_t Height = 5;
unsigned char Map[Width][Height];
size_t line_count = 0;
std::string line;
while (std::getline(matrix_file, line) && line_count < Height) {
line.resize(Width);
for (size_t i = 0; i < line.length(); ++i)
Map[i][line_count] = line[i];
++line_count;
}
if (line_count < Height) {
// the file didn't have enough lines to fill our matrix,
// so we'll need to fill the rest with zeroes here
}
}
The line.resize(Width);
line above will automatically put null characters in the string when Width is greater than the length of the line in the file. Also, don't forget to check if stream was opened succesfully before you try to read from it (fstream::is_open()
, for example). I skipped that check for brevity.
Upvotes: 1
Reputation: 5173
If you can read all the lines with fgets(), you can copy the i-th line character by character to the i-th row of your table. Stop when you encounter the end of the line or when you have copied Width characters. Be careful that fgets() might leave a NL character at the end of the line that you might want to remove (NL + CR on Windows).
Repeat the above procedure until you have read Height lines or reached the end of the file.
My solution is basically C (because you say you are not familiar with the C++ functions). You should use standard C++ libraries (fstream, string) if you want a real C++ implementation.
#include <cstdio>
#include <cstring>
#define Height (...)
#define Width (...)
// I assume that each input line in the file can contain at most width * 3 characters.
// Three extra characters for NL, CR, 0.
// Change this if you expect the file to contain longer lines.
#define BUFFER_WIDTH (Width * 3 + 3)
unsigned char Map[Height][Width];
unsigned char line[BUFFER_WIDTH];
// Remove CR, NL at the end of the line.
void clean_line(char *line)
{
int len = strlen(line);
while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r'))
{
line[len - 1] = '\0';
len--;
}
}
void read_table(const char *filename)
{
FILE *fp = fopen(filename, "r");
int row = 0;
while (!feof(fp) && row < Height)
{
fgets(line, BUFFER_WIDTH, fp);
clean_line(line);
int len = strlen(line);
int rowLen = len > Width ? Width : len;
for (int col = 0; col < rowLen; col++)
{
Map[row][col] = line[col];
}
row++;
}
fclose(fp);
}
Upvotes: 1