0

I used the code below to read one .dat file and find the execution time, it worked very well. I tried to build a loop to read multiple files as I have more than 20 files with different names (I need to keep their names), but it did not work. How can I develop this code to read all files located in a certain folder no matter how many they are? (based on following code)

#include <Windows.h>
#include <ctime>
#include <stdint.h>
#include <iostream>
using std::cout;
using std::endl;
#include <fstream>
using std::ifstream;

#include <cstring>

/* Returns the amount of milliseconds elapsed since the UNIX epoch. Works on both
 * windows and linux. */

uint64_t GetTimeMs64()
{


 FILETIME ft;
 LARGE_INTEGER li;

 /* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
  * to a LARGE_INTEGER structure. */
 GetSystemTimeAsFileTime(&ft);
 li.LowPart = ft.dwLowDateTime;
 li.HighPart = ft.dwHighDateTime;

 uint64_t ret;
 ret = li.QuadPart;
 ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
 ret /= 10000; /* From 100 nano seconds (10^-7) to 1 millisecond (10^-3) intervals */

 return ret;

}




const int MAX_CHARS_PER_LINE = 512;
const int MAX_TOKENS_PER_LINE = 20;
const char* const DELIMITER = "|";

int main()
{
  // create a file-reading object
  ifstream fin;
  fin.open("promotion.txt"); // open a file
  if (!fin.good()) 
    return 1; // exit if file not found

  // read each line of the file
  while (!fin.eof())
  {
    // read an entire line into memory
    char buf[MAX_CHARS_PER_LINE];
    fin.getline(buf, MAX_CHARS_PER_LINE);

    // parse the line into blank-delimited tokens
    int n = 0; // a for-loop index

    // array to store memory addresses of the tokens in buf
    const char* token[MAX_TOKENS_PER_LINE] = {}; // initialize to 0

    // parse the line
    token[0] = strtok(buf, DELIMITER); // first token
    if (token[0]) // zero if line is blank
    {
      for (n = 1; n < MAX_TOKENS_PER_LINE; n++)
      {
    token[n] = strtok(0, DELIMITER); // subsequent tokens
        if (!token[n]) break; // no more tokens
  }
}

    // process (print) the tokens
    for (int i = 0; i < n; i++) // n = #of tokens
      cout << "Token[" << i << "] = " << token[i] << endl;
    cout << endl;
  }
  uint64_t z = GetTimeMs64();
  cout << z << endl;
  system("pause");
}
Hawk
  • 5,060
  • 12
  • 49
  • 74

3 Answers3

1

For listing files in a directory on Windows, refer to this link:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa365200(v=vs.85).aspx

Notes about your code:

  1. don't use fin.eof() to test the end of input, see why: eof of istream in C++

  2. to read multiple files, remember fin.clear() before fin.close if you use the same fin to read multiple files.

UPDATE:

The following code prints out the files name in a directory D:\\Test. If you need absolute path for every file or files in subfolders, change GetFiles to do that. This is pretty straightforward according to the link I provided. The code is test on VS2012 Win7 Pro.

#include <windows.h>
#include <Shlwapi.h>

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

#pragma comment(lib, "Shlwapi.lib")

int GetFiles(const string &path, vector<string> &files, const string &wildcard = "\\*")
{
    wstring basepath(path.begin(), path.end());
    wstring wpath = basepath + wstring(wildcard.begin(), wildcard.end());

    WIN32_FIND_DATA ffd;
    HANDLE hFind = INVALID_HANDLE_VALUE;
    DWORD dwError = 0;

    hFind = FindFirstFile(wpath.c_str(), &ffd);

    if (INVALID_HANDLE_VALUE == hFind) {
        // display error messages
        return dwError;
    }

    TCHAR buf[MAX_PATH];
    do {
        if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            // directory
        } else {
            PathCombine(buf, basepath.c_str(), ffd.cFileName);
            wstring tmp(buf);
            files.push_back(string(tmp.begin(), tmp.end()));
        }
    } while (FindNextFile(hFind, &ffd));

    dwError = GetLastError();
    if (ERROR_NO_MORE_FILES != dwError) {
        // some errors
    }
    FindClose(hFind);
    return dwError;
}

int main()
{
    string path("D:\\Documents\\Visual Studio 2012\\Projects\\SigSpatial2013");
    vector<string> files;
    GetFiles(path, files);
    string line;
    ifstream fin;
    for (int i = 0; i < files.size(); ++i) {
        cout << files[i] << endl;

        fin.open(files[i].c_str());
        if (!fin.is_open()) {
            // error occurs!!
            // break or exit according to your needs
        }

        while (getline(fin, line)) {
            // now process every line
        }

        fin.clear();
        fin.close();
    }
}
Community
  • 1
  • 1
gongzhitaao
  • 6,566
  • 3
  • 36
  • 44
  • 1. I understand from the link that while(!fin.eof( )) is a wrong way to read a file, but I what I can I use instead? I could not find out 2. should I list files in a directory before I read them, As I'm trying to read these files' contents – Hawk Mar 24 '13 at 05:25
  • @HaythamAlzeini 1. How would you get your file names? If you will hard code, then you don't have to. What I provided is a way to get files' name in a directory. 2. for ``fin``, you could use the following code skeleton: ``int a; while (fin >> a) { // do something }``. – gongzhitaao Mar 24 '13 at 14:42
  • when I execute the listing code it displays this: 'Usage: Users\Alzeini\Desktop\New folder\untitled3.exe ' that is the path of the project file, is that correct?, if so where should I place my code? to make use of this output. – Hawk Mar 27 '13 at 02:08
  • @HaythamAlzeini See the example code I provided. ``vector files`` contains all the files in a folder, iterate through it. – gongzhitaao Mar 27 '13 at 15:10
  • The code works very well and lists the files in the vector files, but I could not merge my code with it, I should modify following part right? `..... ifstream fin; fin.open("promotion.txt"); // open a file if (!fin.good()) return 1; // exit if file not found // read each line of the file while (!fin.eof()) { .....` , but how? – Hawk Mar 30 '13 at 06:47
  • 1
    @HaythamAlzeini Please see my updated code framework. I think it's pretty clear :) btw, Are you new to C++? :P – gongzhitaao Mar 30 '13 at 22:14
1

I think it's easier:

1- if you factor out the code that reads a file and process its content into its own function:
void process_file( char* filename );
2- add a new function to list a directory's content: char** list_dir( char* dir );
3- combine the 2 functions in your main()

this makes for cleaner and more testable code

b2Wc0EKKOvLPn
  • 2,054
  • 13
  • 15
1

I agree with the suggestions to encapsulate this. On Windows the code looks like this

HANDLE h;
WIN32_FIND_DATA find_data;
h = FindFirstFile( "*.dat", & find_data );
if( h == INVALID_HANDLE_VALUE ) {
    // Error
    return;
}
do {
    char * s = find_data.cFileName;
            // Your code here
} while( FindNextFile( h, & find_data ) );
FindClose( h );
brian beuning
  • 2,836
  • 18
  • 22
  • I did rewrite the code using your suggestion, but it did not work, I think there's something wrong with my code, I've just inserted the code of reading files (without time stamp part) into your code after char *s = ...; would you tell me what might be wrong please? – Hawk Mar 26 '13 at 16:01
  • here is the piece of code i'm asking about, how to merge my code with yours ? `do { char * s = find_data.cFileName; // My code ifstream fin; fin.open("promotion.txt"); // open a file if (!fin.good()) return 1; // exit if file not found // read each line of the file while (!fin.eof()) { ...// rest of my code .. } while( FindNextFile( h, & find_data ) ); FindClose( h );` – Hawk Mar 30 '13 at 07:21
  • Great! the code works very well. However still one last thing, and this is happening whether the code reads single file or multiple files, it suppose to display all records of the file(s) but what happen is; it displays part of it, in particular, the last records, for example if the file contains 60 records it displays the last 20, if multiple files, it displays the complete last files and omits the few first files and could display part of one of them. could you help me at this, (this problem happens with my original code above and with the code after I added your part)? – Hawk Mar 30 '13 at 14:18
  • Step through the execution with a debugger and see where it does something you do not expect. – brian beuning Mar 30 '13 at 14:28
  • I did and it is working well, displaying all records of the file(s), I posted this as another question, please take a look [link](http://stackoverflow.com/questions/15727738/the-code-does-not-display-the-output-from-the-beginning-with-timestamp-function) – Hawk Apr 02 '13 at 09:54