C++ ifstream tries to open file while being written - c++

I am polling a directory constantly for files and every time I see a file that meets some certain criteria for reading, I open the file and parse it.
string newLine;
ifstream fileReader;
fileReader.open(filename.c_str());
while(!fileReader.eof())
{
getline(fileReader, newLine);
// do some stuff with the line...
}
filereader.close();
The above code is in a loop that runs every 1 second checking a directory for new files. My issue is that as I am transferring files into the folder for processing, my loop finds the file and passes the name of the file to ifstream who then opens it and tries to parse an incomplete file. How do I make ifstream wait until the file is done being written before it tries to parse the file?
EDIT:
Wanted to better word the issue here since a replier seems to have misunderstood my issue. I have 2 directories
mydirectory/
mydirectoryParsed/
THe way my code works is that my program checks for files in mydirectory/ and when it finds them, parses them and uses the information in the files. No writing to the files are done. Once I am done parsing the file, the file is moved to mydirectoryparsed/
The issue is that when I transfer files over the network into mydirectory/ the ifstream sees these files midtransfer and starts reading them before they finish writing to the directory. How do I make ifstream wait until the file is completely written before parsing it?

Don't transfer the files directly into the directory that your program is watching; instead, transfer them into a different directory on the same drive, and then when the transfer is done, move them into the watched directory. That way, the complete file appears in the watched directory in a single atomic operation.
Alternatively, you could use a naming convention in the watched directory — append a suffix like ".partial" to files that are being transferred, and then rename the file to remove the suffix when the transfer is done. Have your program ignore files whose names end with the suffix.

You're not supposed to open the file every time you write in it. Open it once!
Some pseudo-code for this would be :
1- Open file
2- Get the data you want to write, treat that data
3- Call the write to file function
4- Loop until you have nothing left to write
5- Close de file

Related

How to delete data/content from a txt file

I am trying to learn how to handle and work on files, now I know how to open them, write on them and read. What I would like to do is, how can I delete data/content from the file, when I have finished to use the program?
I use the a txt file to save some informations that I used them, when I need during the execution of the program, but when I finish, I would like to delete the data saved, which are simply numbers. I was thinking to remove the file each time, and to create, but I think it's not the ideal. Any suggestions?
Using std::filesystem::resize_file:
std::filesystem::resize_file(your_file, 0);
In such a case, you usually just re-write the file as a whole. If it is a small file, you can read in the entire content, modify the content and write the file back.
With large files, if you fear that you are consuming too much memory, you can read in the file in chunks of appropriate size, but you'd write these chunks to another, temporary file. When being finished, you delete the old file and move the temporary file to the location of the old file.
You can combine both aproaches, too: Read the entire file, write it to temporary at once, then delete and move; if anything goes wrong while writing the temporary, you'd still have the old file as backup...
You can open the file in writing mode (w) and then close it . It will truncate all previous data.
It's generally a good idea to clean up temporary files once your program ends. I certainly wouldn't leave an empty temporary file hanging around. You can easily remove file (e.g. with boost::filesystem::remove or std::filesystem::remove). If you really just want to 'clear' a file then:
void clear_file(const std::string& filename)
{
std::ofstream file {filename};
}
Will do the job.

Open multiple files for reading using the file naming format in Fortran

I need help opening multiple files for reading one by one in Fortran. The code below has the right names for the files but overwrites the contents of the file before opening.
How can I stop this from happening
WRITE(FN,10)lam, zeta, (array(k)%str)!,k=1,N)
WRITE(6,*)FN!filename
OPEN(1,FILE=FN, status='replace')
CLOSE(1)
10 FORMAT('4e3_2048_',(I3.0),'_',(I2.2),'_',(A3),'.ksz_cl.txt') !
When you use status='replace' when opening the files you cause them to be deleted and recreated (Fortran 2018 12.5.6.18):
If REPLACE is specified and the file does exist, the file is deleted, a new file is created with the same name, and the status is changed to OLD.
That's not good when you want to read from the files. Instead, use something like
open(1, file=FN, action='read', status='old', position='rewind')
to ensure: the file exists; it's opened for reading; is positioned at the start of the file.
I have seen status='replace' intended to mean that the connection is replaced, allowing the unit number to be reused. As can be seen, that's not correct. On that note: unit numbers can be happily reused once a connection is closed. Indeed, if an open statement refers to a unit already connected to a different file, there's an implied close on that first connection.

preferred c++ i/o stream method: fstream or ifstream/ofstream or something else entirely?

I have created a roster program that accepts user input to create/write/delete information into and out of a specified text file. My issue now becomes wanting to create a lasting text file that isn't overwritten every time I re-run the program and am not sure if using fstream or a combination of of/ifstream is better practice, or if there is maybe a third option I missed when checking the reference docs.
Right now I am simply using: std::ofstream outfile("roster.txt"); which works, until I kill and re-run the program to which my text file is now wiped clean.
check out the append flag. it writes to the end of an existing file.
http://www.cplusplus.com/doc/tutorial/files/
example here.
std::ofstream outfile("roster.txt" , ios::app)

C++ fstream open

I am able to create the files such as
f.open("file")
f.open("./path/file")
f.open("../path/file")
but not
f.open("~/path...)
f.open("/path...)
How do I get the absolute paths to work?
By default, std::fstream::open(filename)
opens filename for both input and output. Hence that file must exist and you must
have write permission to it.
In your cases:
f.open("file")
f.open("./path/file")
f.open("../path/file")
you were lucky.
In your case:
f.open("~/path...")
you used the path-element ~, which means $HOME in the shell but just
means ~ in C++.
In the case:
f.open("/path...")
you were unlucky: either the file didn't exist or you didn't have write permission.
If you want to open a file simply for input then either:
use std::ifstream
use std::fstream f; f.open(filename,std::ios_base::in);
If you want to open a file simply for output then either:
use std::ofstream
use std::fstream f; f.open(filename,std::ios_base::out);
With f.open("~/path/....") it is necessary for you to expand the ~ in code. This is typically done by calling getenv("HOME") to retrieve the home directory, and replacing every occurence of '~' in the path with the home directory.
When working with absolute paths, like "/path/whatever", you need to check that f.open() succeeds. There are various reasons that f.open() might fail, including access control (protections that prevent opening a file), the file already being opened by another process, the directory does not exist, etc.
Notably, f.open(), when attempting to open a file within a directory, requires that all directories in the path already exist. It won't exercise some magic to make them exist. If you want that, you need to code it. Bear in mind that each phase (creating directories, etc) might fail.

Loading files merged with executable

I'm trying to merge a file with my executable, and read the merged file. I merge them with the Windows command;
copy /b Game.exe+Image.jpg TheGame.exe
Here's what I've tried:
std::ifstream f("Image.jpg");
if (f.good()) {
std::cout << "Found Image.jpg" << std::endl;
}
Image.jpg is in the same directory as the resulting executable file, and it works. However when I use the command to merge them and then delete the Image.jpg file it is not found (although it is merged with the executable.)
Any suggestions?
ifstream only works with external files. You deleted the file it is trying to open, so of course it will not find the file. What you are attempting cannot (easily) be done using binary merges. If you want to store a file inside of an executable, the correct approach is to store it in a resource instead. Read the following chapter on MSDN for more information.
Introduction to Resources
In particular, the following example shows how go create a new resource in an .exe file and write data into it. The example copies a resource from another .exe file, but you can write whatever you want. In tbis case, replace RT_DIALOG with RT_RCDATA, and write your image data.
Using Resources