Detect change in text file using C++ i without Infinite Loop? - c++

I am reading a text file using C++. I am using the first line to indicate if the file has changed or not. For example, text file will look like :
0
9
After the text file has been changed I am flipping the first line. So, the new text file will look like:
1
5
C++ code will perform its functions after reading the new input from the text file. Currently, I am using infinite loop to detect changes in the text file. Is there any alternative implementation of detecting changes in the text file using C++? This is my solution so far:
do{
std::ifstream reader;
reader.open(READFILE);
if (!reader){
printf("Error opening the reader file!!");
exit(1);
}
reader >> status >> variable;
if(status != reader_file_status){
reader_file_status = status;
return true
}
} while(true);

filesystem change events are platform specific, so you'll need different solutions for different platforms.
osx: file system events api doc
freebsd/osx: kqueue doc
linux: inotify doc
windows: windows api doc
It seems some cross platform wrappers are around. A quick googling revealed:
https://github.com/emcrisostomo/fswatch (gpl3, osx/freebsd/linux/windows/solaris)
http://doc.qt.io/archives/qt-4.8/qfilesystemwatcher.html (lgpl, osx/freebsd/windows)

Related

How to check if any files are open in a directory?

I am trying to delete all files in a folder, but if a file is left open, it will not delete. I need to check the folder for any open files, write their names to a text document, and then close the open files. As I don't have much experience, I am first trying to check one file in the same folder, then all in the same folder, then all in a different folder. I don't want to be to needy or demanding, so just some help with the first step would be nice.
I don't have a ton of experience coding, but I have tried using fstream and (name.is_open). I may be using them wrong, so I have not yet ruled them out.
// ifstream::is_open
#include <iostream> // std::cout
#include <fstream> // std::ifstream
void checkFiles() {
int done = 0;
while(done != 1){
std::cout << "Enter 0 for continue or 1 for done: ";
std::cin >> done;
std::ifstream ifs ("test.txt");
if (ifs.is_open()) {
// Print that file is open, then close
std::cout << "File is open\n";
std::ifstream.close():
}
else {
std::cout << "File not open\n";
}
}
For this bit of code, if the file is open, it should say "File is open."
If not, it should say "File not open"
Even if I force quit the .txt file, it still says that it is open.
Eventually, I want to have a new file that displays what files were open, as well as closing all the open files.
Standard C++ offers us the filesystem library to handle files and directories (standardized in C++17). However, checking which files are open is not - as far as I can tell - a feature of that library.
The is_open() method for std::fstream's is something completely different than what you're trying to check for: It tells you whether the particular stream object is in an open state (which would mean association with an open file) - and it doesn't use the OS to check which files are open. Typically, it's just a way to check whether you've closed it someplace else in your own program; at most, it might ensure that the OS has not unilaterally closed the OS-side file access handle. So, you won't get anywhere in that direction.
I also believe, though I'm not 100% certain, that Boost doesn't have a library which offers this capability, either. Boost's filesystem library is almost identical to std::filesystem, as the latter was based on it.
So, to the best of my knowledge, you either need to directly use operating-system-specific calls to do this, or look for a library offering this functionality, elsewhere.
If you haven't found anything else, you could track how this is currently done with what's available in userspace. There's a utility called lsof. It's available on some operating systems based on Linux, Darwin, FreeBSD and Solaris (e.g. available on MacOS). It's maintained here. The source code seems to be rather atrocious C. An intrepid developer could parse that mess, figure out what it does, extract the parts relevant for your specific use case, and refactor it into a reasonable, readable and short(ish) C++ function. I realize you (OP) might not be up for it at this point, but - maybe someone else reading this answer will get inspired to do it.
The pfiles command shows the open files for a process. You can run it for all or some processes.
However, Solaris (and UNIX) in general allows you to delete open files. The file can still be read and written while it is open (but deleted), but nobody else can open the same file and the file will be deleted when all processes have the file closed.

Under Linux boost::interprocess::create_or_open_file change the file type

I'm porting a source code to open/read/write a file shared between several process. It works well under windows and as it was mainly using boost::interprocess (1.44) I didn't expecting too many issue but I found something weird:
//pseudo code
namespace bip = boost::interprocess;
namespace bipd = boost::interprocess::detail;
loop
bip::file_handle_t pFile = bipd::create_or_open_file(filename, bip::read_write);
bipd::acquire_file_lock(pFile);
// try to read bytes from pFile with 'read'
bipd::truncate_file(pFile, 0);
bipd::write_file(pFile, (const void*)(textBuffer)), bufLen);
When the code run the first time it create the file and write a text. The file mode is ASCII (ASCII text, with very long lines) and I can read the text.
But when the loop run for the second times, the file type change to
data and the textBuffer is in the file but as binary data !
I inspected boost/interprocess/details/os_file_functions.hpp but I didn't find a reason for that behavior.
Have you an idea ?
Finally, I found a solution....
It ssems that if you are at the end of the file (file pointer position after the ::read), the ::ftruncate function used in the implementation of `boost::interprocess::detail::truncate_file' lead to the incorrect behavior.
to keep the same behavior under Linux and Windows (keep my file type as ASCII Text), I used a simple ::seek(id,0,SEEK_SET).
I didn't find that trick in all the page I read !

Stream (pointer to a file structure) in File handling giving strange values

i am trying to output a buffer to a file using visual c++.
my code for doing it is-
FILE *stream;
stream=fopen("C:\\Users\\sshekha\\Desktop\\z.txt","r");
//I also tried with "w" mode
//the differencein behavious on executing these two is that when it is in read mode it
//executes the else condition in the code below whereas in "w" mode it executes the "if"
// condition,
//moreover even if i change the path it don't execute the "else" condition-that means this path
//is effective to the code. and the another surprising thing is when i open the file manually
// and then run the code with "r" mode it still executes the "else" part (which it shouldn't
// because the file is already open.)
if( stream == 0 )
{
MessageBox(m_hwndPreview,L" the file is not opened ",L"BTN WND",MB_ICONINFORMATION);
}
else
{
MessageBox(m_hwndPreview,L" the file is opened ",L"BTN WND",MB_ICONINFORMATION);
int check=fputs (HtmlFileContents,stream);
fclose(stream);
return 0;
}
I tried to check the results using different mode in order to understand whats teh probem going on . when i debug it , i get the value of (in Read mode) :
stream = 0x000000005c5c76f0 { _ptr=0x0000000000000000 _cnt=0 _base=0x0000000000000000 ...}
I don't know it gib=ves bad pointer and even then it go to else part of the loop. Why ?
and in write mode
stream = 0x0000000000000000 {_ptr=??? _cnt=??? _base=??? ...}
So go to the if part of the loop.
Moreover my path is correct and i have enough permission to do the task I wish. But why does it give bad pointer ? Why have I these strange values of stream and what should I do to copy the content of my buffer HtmlFileContents in to z.txt ? Any ideas ?
You're opening the file in read-only mode: fopen("C:\\Users\\sshekha\\Desktop\\z.txt","r");. Here "r" says you only intend to read from file. To be able to write contents (i.e. fputs(...)), open the file in write mode like so: fopen("C:\Users\sshekha\Desktop\z.txt","w")(or"a"` if you want to append). For more information, read fopen documentation.
EDIT: I see that you've tried both read and write modes. You're code only shows read-mode and hence my assumption on the read-only problem. Let me do a bit more research and get back.
Please write the following code in your if statement:
perror("The following error occurred:");
if you don't have a console, use this to store the error string:
char* errorCause = strerror(errno); MessageBoxA(m_hwndPreview, errorCause, "BTN WND", MB_ICONINFORMATION);
and let us know what you see as the cause.
EDIT 2: Since you've mentioned that you're using Visual Studio 2010, are you running it as yourself? This stackoverflow answer shows that VS2010 has different options when debugging applications; https://stackoverflow.com/a/3704942/210634
NOTE: That feature is only available on 'Pro' versions.
Here's a working example: https://ideone.com/hVLgc4
If the file is "read only", opening with it with write permissions should fail.
to see if that is the case,under windows:
right click the file
press properties
at the bottom, see if "Read-only" attribute i marked with "v"
(uncheck it if you desire writing to the file)
refer to :
http://msdn.microsoft.com/en-us/library/aa365535(v=vs.85).aspx
on how to change file permissions from your code

Delay in ofstream::open, possibly due to mixing with _iobuf?

I have a C++ program that creates an output file "A" with ofstream. This file is then read by some legacy C code that opens the file with _iobuf. The legacy code then creates its own output file "B" using _iobuf, and this file is then read by the C++ program using ifstream. This sequence is iterated many times, with the same file names for A and B in each iteration.
Occasionally, the C++ program cannot open the output file A for writing, and I must try several times before it succeeds. This occurs nondeterministically, and maybe once in a thousand iterations. Note that the C program never has to wait to open its input or output file, nor does the C++ program ever have to wait to open its input file. This informal observation is based on hundreds of thousands of iterations.
I'm wondering if this has something to do with mixing ofstream and _iobuf in the same program? Both the C++ code and the C code are linked into the same program. And the legacy C code is technically C++ code, but was written in a very C-like style. Is there anything I can do to eliminate this waiting to open the ofstream file? I do not want to change the legacy code if I can possibly avoid it.
Pseudo code (not compiled):
void someObject::someMethod()
{
for (int count = 0; count < someLimit; ++count)
{
newerObject::firstMethod();
olderObject::secondMethod();
newerObject::thirdMethod();
}
}
void newerObject::firstMethod()
{
// do some processing first
// then write the results of the processing to a file
ofstream A;
A.open("A", ofstream::out); // this sometimes must be tried multiple times
// write data to file A
A.close();
}
void olderObject::secondMethod()
{
FILE* f;
f = fopen("A", "rt"); // this always works the first time
// read data from file A
fclose(f);
// do some processing
f = fopen("B", "w");
// write data to file B
fclose(f);
}
void newerObject::thirdMethod()
{
ifstream B;
B.open("B"); // this always works the first time
// read data from file B
B.close();
// do some processing
}
Currently, as a work around, I put the ofstream::open in a do-while loop. I would love to get rid of this awkwardness. Thanks in advance for any advice you can give.
First off, the problem is almost certainly not the use of different methods to access the files: under the hood, the C and C++ I/O functions use the same system I/O facilities. You seem to be using Windows (on other systems files typically can be open multiple times simultaneously) and I don't know much about the system but I would suspect that the file system hasn't been updated to reflect that the file is closed when you try to open it. This may have to do with the "t" open flag: I don't know what this is about.
On UNIXes you can force the I/O operations to wait until the actual change on disk completed. Something like this could help avoiding the problem but has the significant cost that operations become hideously slow. On UNIXes one approach would be to blow away the file system entry the moment the file was opened successfully (after all, at this point its name isn't used anymore):
if (FILE* fp = fopen("file", "r")) {
remove("file");
// do processing
}
However, if I recall correctly on Windows you can neither remove the file nor rename it. Personally, in solving the problem I would proceed as follows:
Determine under which situations the file can't be opened, e.g. by keeping the file open and trying to open it. This is mainly intended to create a setup where the problem is reproducible so you can verify later that you indeed found a solution.
Once I found a way to reproduce the problem I would probably a better idea of the actual root cause and possibly googling would help. In any case this is the point where researching the root cause comes in.
Once the cause is understood it is hopefully easy to devise a solution. If not, opening the file multiple times under it is successful may very well be the right solution.

How check if file have been changed via other process?

I have two processes (firsts source in perl, seconds source in c++) and both of them use same file. One of them writes to the file line by line, and another reads from file if new line is appended to it. For second process to know that file is modified the first proces flush - es after each apendence. But second process checks only modification time to be increased to start read, but actualy after adding new line and flushing the file doesn't change its "last modification time". So there is another aporache is needed to do this. So the question is here, how detect if new line is appended to the file, to start its processing?
here are fragments from source codes of this proceses:
1.
open FILE, ">>", $file or die $!;
for($i = 0; $i <= $#ticks; ++$i)
{
print FILE $ticks[$i]."\n";
FILE->flush();
sleep(10);
}
close FILE;
2.
struct stat64 file_info;
if(fstat64(fileno(this->auto_file_ptr.get_file()), &file_info)!=0)
{
//throw error that file have been changed
}
data_file_new_modification_time = 1000LL * file_info.st_mtime;
if(this->data_file_last_modification_time!=data_file_new_modification_time)
{
//processs the file
}
Use IPC mechanisms to synchronize you C++ and Perl application. You can use semaphores or mutexes for this purpose.
Welcome to event-based programming.
Employ select - you do not want to know when the file is changed, but when new data is available. This system call does exactly that.
See the implementation in File::Tail for a real-world example with all the edge cases nicely grated off. Downporting this to C should be easy for you, or use libev with the select backend.
It seems that stat64 doesn't change it's st_mtime member when file is flushed. Instead the st_size changes. So I can use st_size to detect if file was changed.