Check if file is present in some directory in c++ - c++

I am reading a file from some directory using visual c++. How do i check if that file exists or not.
If i use:
file.open("file.txt", ios::in);
where file is a member of fstream. This creates a file ifthat file is not present.
How can i check if that file is present or not.
Thank you

Your code creates no file if that file isn’t already present (on most systems, assuming file is a std::ifstream).
Due to inherent concurrency in file system access, there is no reliable way to check whether a file exists. The best way is simply to open the file for read access and test whether that was successful:
if (file.good()) …
// or simply
if (file) …

ifstream my_file("file.txt");
if (my_file.good())
{
// read away
}

If you are working on Windows, you can use Windows API to do the job for you. Here is a brief code snippet for you... You have to pass the complete path of file.txt in order for this to succeed. For E.g. D:\MyFolder\file.txt.
WIN32_FIND_DATA FindFileData;
HANDLE hFind = INVALID_HANDLE_VALUE;
hFind = FindFirstFile("D:\MyFolder\file.txt", &FindFileData);
GetLastError();
if (hFind == INVALID_HANDLE_VALUE)
// File not found

just calling file like that should not create a file if it is missing. It should fail and succeeding calls to file.is_open() would return false.

Your code could implement the following:
ifstream file("text.text");
if(!file){
//handle error / throw exception here
}

Related

How to share file delete privilege when I opening a file by ifstream

I want to make the file that can be delete when it was opened by ifstream.
I know it is easy when using Windows API: CreateFile
CreateFile(...,FILE_SHARE_DELETE,...)
But when I test with opening a file by ifstream.
It can't be deleted when I opening it.
I didn't find any document about setting attribute such like FILE_SHARE_DELETE on ifstream.
How should I do to solve this problem?
Visual Studio's version of std::ifstream has a non-standard constructor and a non-standard open() overload that both have an extra optional _Prot parameter for specifying "file protection/sharing flags" (see _fsopen() for the list of available flags). However, delete sharing is not one of supported flags.
There is an alternative, though. Visual Studio's version of both std::ifstream and std::ofstream have non-standard constructors that accept a FILE* for the file access. You can wrap a HANDLE from CreateFile() into a FILE* using Microsoft's _open_osfhandle() and _fdopen() functions, for example (error handling removed for brevity):
Can I use CreateFile, but force the handle into a std::ofstream?
HANDLE file_handle = CreateFile(...,FILE_SHARE_DELETE,...);
int file_descriptor = _open_osfhandle((intptr_t)file_handle, _O_RDONLY);
FILE* file = _fdopen(file_descriptor, "r");
std::ifstream stream(file);
...
// Closes stream, file, file_descriptor, and file_handle.
stream.close();
If you need something more portable to non-Microsoft compilers, you will likely have to resort to writing a custom std::basic_streambuf class (or maybe derived from std::filebuf) to wrap your HANDLE, and then pass an object of that class to the std::basic_istream constructor directly.
File permissions differ by operating system:
Windows has:
Whole-file access-sharing for read, write, or delete
*nix systems provide read, write, and execute permissions, but as far as delete permissions, all that is needed is:
write+execute permission on the parent directory. The permissions of the file itself are irrelevant
Since Windows is really the only system with delete access, and it already provides it's own accessor in the form of CreateFile with FILE_SHARE_DELETE, there really isn't a motivation to standardize this functionality.
If this functionality is pivotal to your program you could implement this cross-platform function (note that depending upon file size this could be very expensive):
Open file for read and write with an fstream; if this fails something else has a lock on the file and it would not be possible to open it for delete
Slurp the file
close the file
remove the file; if this fails you do not have delete permissions on the file
Reopen the file for writing with an ofstream
"Unslurp" the file into the ofstream
Return the ofstream
As long as the returned ofstream is open the operating system is responsible for preventing changes to the permissions on the file or it's containing directories. So by virtue of the fact that you have already deleted the file you know that you can still delete the file upon closing the ofstream.

Why must the file exist when using the 'r+' mode in fopen?

Why add this constraint when your intentions are to both read and write data to the file?
My application wants to open the file in both reading an writing mode. If I use w+ it will destroy the previous contests of the file, but at the same time it will create the file if it doesn't exist.
However if I use the r+ mode, my application will work properly, but if the file doesn't exist it will throw an exception about the nonexistence of the file.
Try something like this. If the first fopen fails because the file does not exist, the second fopen will try to create it. If the second fopen fails there are serious problems.
if((fp = fopen("filename","r+")) == NULL) {
if((fp = fopen("filename","w+")) == NULL) {
return 1;
}
}

How to avoid CFileFind false positive with file extension longer than three characters?

When I try to call CFileFind.FindFile(_T("D://Folder//*.txt")), the method returns true when the only file is "foobar.txta".
However, I don't want the file foobar.txta to be included the find result. How do I make it that way? Probably by using other method or another if ? I'm a newbie in C++ :))
Note: This issue does not seem to happen if the exension is less than 3, for example if filter is "*.tx" and file is "foobar.txt" the method still (correctly) return false.
Also, the issue seems to be reported here but seems like I need to pay to see the solution
It seems to be a bug in CFindFile (or in the Win32 API FindFirstFile). But you can determine the real extension later by calling CFindFile::GetFileName:
CFindFile finder;
BOOL bWorking = finder.FindFile(L"*.txt");
while (bWorking)
{
bWorking = finder.FindNextFile();
if (finder.GetFileName().Right(finder.GetFileName().ReverseFind(L'.')) != L".txt")
// the file extension is not .txt
}
This is a common Windows behavior for backwards compatibility. Files without an "8.3" name may have an short synonym. I.e. "foobar.txta" is also called "foobar.txt". If you indeed meant just *.txt, you'll have to manually check the results. Those results will use the long name, so you can discard the *.txt? files
You can do the manual check afterwards with PathMatchSpec("foobar.txta", "*.txt"). Note that despite the name, this function is really only suited for extension matching. Don't expect anything but *.ext to work.
See also Is there an alternative to the Windows FindFirstFile/FindNextFile API that doesn't search short file names?
I hope this would work.
WIN32_FIND_DATA ffd;
CStringList strFileNameList;
CStringList strFileMask;
int iCntFiles = 0;
HANDLE hFind = INVALID_HANDLE_VALUE;
CONST CHAR cszFileName[] = "test.txt";
strFileMask = strFileName.Left(strFileName.Find(cszFileName)) + "*.txt";
hFind = FindFirstFile(strFileMask.GetBufferSetLength(strFileMask.GetLength()), &ffd);
if (INVALID_HANDLE_VALUE == hFind)
{
return;
}
else
{
// List all the other files in the directory.
strFileNameList.AddTail(ffd.cFileName);
iCntFiles++;
while (FindNextFile(hFind, &ffd) != 0)
{
strFileNameList.AddTail(ffd.cFileName);
iCntFiles++;
}
}
Now from all the text file save in CStringList Now it can be extract.
As the other answerers have noted, the apparent bug is because a Windows file have a 8.3 alias, causing "foobar.txta" to be detected as "foobar.txt". To make sure that a file found by CFileFind indeed match the wildcard pattern, use 'PathMatchSpec' to validate the file returned by finder.GetNextFile(). PathMatchSpec seems not to be affected by the 8.3 alias.

c++ overwrite already opened file

I am opening a file with ifstream to check if it exists. Then I close it and open it with ofstream to write to it, and I think setting ios::trunc flag allows me to overwrite it.
However I'd like the ability to keep the file open if it exists, but I used an ifstream to open it so does that mean I can't write to the file till I close and re-open using fstream or ofstream? I didn't use fstream to begin with because that wouldn't tell me if the file was already there or not.
Just open a read-write fstream on the file. You can test if the file previously existed (and was non-empty) by seeking to the end and seeing if you're at a non-zero offset. If so, the file existed, and you can do whatever with it. If not, the file didn't exist or was empty. Assuming you don't need to distinguish between those two cases, you can then proceed as if it did not exist.
For example:
// Error checking omitted for expository purposes
std::fstream f("file.txt", std::ios::in | std::ios::out);
f.seekg(0, std::ios::end)
bool didFileExist = (f.tellg() > 0);
f.seekg(0, std::ios::beg);
// Now use the file in read-write mode. If didFileExist is true, then the
// file previously existed (and has not yet been modified)
The setting ios::trunc erases previous contents of the file.
Try opening the file without this setting; with only the 'write' setting.
this is touching very serios problem - race conditions - what if somebody manages to do something with this file between closing and reopening? unfortunately iostream does not provide any means of resolving that issue - you can use cstdio FILE. If you want to turncate file if exists or create new one if not use fopen(name, "w"). If you want to turncate file if it exists or fail otherwise, then it seems standard library has nothing to offer, and you should go to other libraries or platform specific functions like OpenFile in windows.h

ifstream: how to tell if specified file doesn't exist

I want to open a file for reading. However, in the context of this program, it's OK if the file doesn't exist, I just move on. I want to be able to identify when the error is "file not found" and when the error is otherwise. Otherwise means I need to quit and error.
I don't see an obvious way to do this with fstream.
I can do this with C's open() and perror(). I presumed that there was a fstream way to do this as well.
EDIT: I've been notified that this does not necessarily indicate a file does not exist, as it may be flagged due to access permissions or other issues as well.
I know I'm extremely late in answering this, but I figured I'd leave a comment anyway for anyone browsing. You can use ifstream's fail indicator to tell if a file exists.
ifstream myFile("filename.txt");
if(myFile.fail()){
//File does not exist code here
}
//otherwise, file exists
I don't think you can know if "the file doesn't exist". You could use is_open() for generic checking:
ofstream file(....);
if(!file.is_open())
{
// error! maybe the file doesn't exist.
}
If you are using boost you could use boost::filesystem:
#include <boost/filesystem.hpp>
int main()
{
boost::filesystem::path myfile("test.dat");
if( !boost::filesystem::exists(myfile) )
{
// what do you want to do if the file doesn't exist
}
}
Since the result of opening a file is OS-specific, I don't think standard C++ has any way to differentiate the various types of errors. The file either opens or it doesn't.
You can try opening the file for reading, and if it doesn't open (ifstream::is_open() returns false), you know it either doesn't exist or some other error happened. Then again, if you try to open it for writing afterwards and it fails, that might fall under the "something else" category.
A simple way from http://www.cplusplus.com/forum/general/1796/
ifstream ifile(filename);
if (ifile) {
// The file exists, and is open for input
}
You can use stat, which should be portable across platforms and is in the standard C library:
#include <sys/stat.h>
bool FileExists(string filename) {
struct stat fileInfo;
return stat(filename.c_str(), &fileInfo) == 0;
}
If stat returns 0, the file (or directory) exists, otherwise it doesn't. I assume that you'll have to have access permissions on all directories in the file's path. I haven't tested portability, but this page suggests it shouldn't be an issue.
A better way:
std::ifstream stream;
stream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
stream.open(fileName, std::ios::binary);
With C++17 you can use std::filesystem::exists.
Let's me give example with real running:
file does't exist:
file exist:
see http://www.cplusplus.com/reference/fstream/ifstream/ for more information about its public function.
Straight way without creating ifstream object.
if (!std::ifstream(filename))
{
// error! file doesn't exist.
}