I am trying to open a file for writing and reading simultaneously, in windows.
I have one program which writes (every one second) to the file and one that reads from it. In unix it works prefectly but it doesn't work in windows (I can't open an already opened file).
I open the file with fopen().
How can I solve this problem?
EDIT2:
check out _fsopen it uses FILE *, and set the share flag accordingly.
EDIT:
First of all, some code: this is how I used to open the file
FILE* f = NULL;
int res = fopen_s(&f, "c:\\temp\\File1.txt", "w");
if (res != 0) return;
while (true) {
Sleep(1000);
fprintf_s(f , "Some data");
}
fclose(f);
The read was in other applicaiton, but it did fscanf instead.
The fixed code:
char d[] = "data";
HANDLE h = CreateFile("c:\\temp\\f.txt", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, CREATE_ALWAYS, /*FILE_ATTRIBUTE_NORMAL*/ FILE_FLAG_WRITE_THROUGH, NULL);
if (h == INVALID_HANDLE_VALUE) return 0;
DWORD bytesW;
while(true) {
Sleep(100);
WriteFile(h, d, strlen(d), &bytesW, NULL);
}
CloseHandle(h);
return 0;
Both Windows and Linux have a default way of opening a file, which fopen uses by default.
In Windows, that means blocking (only one process can open a file at a time).
In Linux, it means non-blocking.
fopen is a high-level API. To choose yourself the blocking policy on the file, for Windows you should use OpenFile from WinAPI. In particular, have a look at the OF_SHARE_* flags.
Related
Given one normal file, it could be read and written. Then I change this file attribute to Read-only through
However, this file still could be written through file handler. Here are my codes
#define CREATE_FILE_OPT FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_RANDOM_ACCESS
std::string name("test.txt");
HANDLE hfile = ::CreateFile(name.c_str(),
GENERIC_READ | GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, CREATE_FILE_OPT, NULL);
if (hfile == INVALID_HANDLE_VALUE) {
hfile = ::CreateFile(name.c_str(),
GENERIC_READ | GENERIC_WRITE, NULL, NULL, CREATE_NEW, CREATE_FILE_OPT, NULL);
if (hfile == INVALID_HANDLE_VALUE) {
printf("so sad, invalid file handler....");
return -1;
}
}
int i = 0;
char rbuf[] = "you are";
DWORD bytesWritten;
do {
Sleep(5000);
++i;
bytesWritten = 0;
BOOL bret = ::WriteFile(hfile, rbuf, strlen(rbuf), &bytesWritten, NULL);
if (bret == FALSE) {
printf("Cannot write bytes into file.....");
DWORD err = GetLastError();
printf("The error code is %d\n", err);
}
else
printf("write %d bytes to file\n", bytesWritten);
DWORD ret = GetFileAttributes(name.c_str());
printf("The file attribute is %d\n", ret);
} while (i < 10000);
The file attribute is 32 before I change it to Read-only, but it will be 33 after this file is Read-only.
I want to know why the file could be written after change it to Read-only? Is there any issue in my test codes?
PS: test it in VS2015 under windows 7.
Sorry, I get your meaning finally. I guess you are talking about creating a file first, setting it readonly without closing the program. The READONLY attribute check only happens in CreateFile routine.
In Windows kernel, every object is assigned a temporary access right list once created, unless explicitly refreshed, a thing seldom happens on actual files on fixed disks. So even if you deny all rights after CreateFile using NTFS access control, your program will behave just as when CreateFile is called.
In conclusion, it is natural your program can still write to the file, after your hot-changing it into READONLY, which only writes information onto disk, not changing kernel access table.
Is there any way to take advantage of the file creation flags in the Win32 API such as FILE_FLAG_DELETE_ON_CLOSE or FILE_FLAG_WRITE_THROUGH as described here http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx , but then force that handle into a std::ofstream?
The interface to ofstream is obviously platform independent; I'd like to force some platform dependent settings in 'under the hood' as it were.
It is possible to attach a C++ std::ofstream to a Windows file handle. The following code works in VS2008:
HANDLE file_handle = CreateFile(
file_name, GENERIC_WRITE,
0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (file_handle != INVALID_HANDLE_VALUE) {
int file_descriptor = _open_osfhandle((intptr_t)file_handle, 0);
if (file_descriptor != -1) {
FILE* file = _fdopen(file_descriptor, "w");
if (file != NULL) {
std::ofstream stream(file);
stream << "Hello World\n";
// Closes stream, file, file_descriptor, and file_handle.
stream.close();
file = NULL;
file_descriptor = -1;
file_handle = INVALID_HANDLE_VALUE;
}
}
This works with FILE_FLAG_DELETE_ON_CLOSE, but FILE_FLAG_WRITE_THROUGH may not have the desired effect, as data will be buffered by the std::ofstream object, and not be written directly to disk. Any data in the buffer will be flushed to the OS when stream.close() is called, however.
Some of these flags are also available when using _fsopen / fopen:
FILE* pLockFile = _fsopen(tmpfilename.c_str(), "w", _SH_DENYWR );
if (pLockFile!=NULL
{
// Write lock aquired
ofstream fs(pLockFile);
}
Here we open the file so when doing a flush, then it writes through (And it is deleted when closed):
FILE* pCommitFile = fopen(tmpfilename.c_str(), "wcD");
if (pCommitFile!=NULL)
{
// Commits when doing flush
ofstream fs(pCommitFile);
}
is there a way to serialize a HANDLE in a file?
This is my Handle:
hPipeReadOrWrite = CreateFileA(
TEXT(PIPEPATH), //Pipepath
GENERIC_WRITE, //Access Mode
0, //ShareMode
NULL, //Security Attributes
OPEN_EXISTING, //Action on a File
0, //Type of File
NULL);
I ask this, because I can only open the pipe once. If I could write the Handle in a file (and dont close the Handle) and deserialize it later, then maybe I´m able to write multiple times in the pipe.
My question before was the following: Writing mulitple times in a special (given) pipe C++
I already tried the following, but here I have a file_descriptor instead of a File:
if (hPipeWrite != INVALID_HANDLE_VALUE) {
int file_descriptor = _open_osfhandle((intptr_t)hPipeWrite, 0);
if (file_descriptor != -1) {
FILE* file = _fdopen(file_descriptor, "w");
if (file != NULL) {
std::ofstream stream(file);
stream << "Hello World\n";
// Closes stream, file, file_descriptor, and file_handle.
stream.close();
file = NULL;
file_descriptor = -1;
hPipeWrite = INVALID_HANDLE_VALUE;
}
}
Thanks for your help...
Is there easy way to create FILE* from WinApi HANDLE which points to one end of pipe?
Something like we do in unix: fdopen(fd,<mode>);
You can do this but you have to do it in two steps. First, call _open_osfhandle() to get a C run-time file descriptor from a Win32 HANDLE value, then call _fdopen() to get a FILE* object from the file descriptor.
FILE* getReadBinaryFile(LPCWSTR path) {
HANDLE hFile = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
return nullptr;
}
int nHandle = _open_osfhandle((long)hFile, _O_RDONLY);
if (nHandle == -1) {
::CloseHandle(hFile); //case 1
return nullptr;
}
FILE* fp = _fdopen(nHandle, "rb");
if (!fp) {
::CloseHandle(hFile); //case 2
}
return fp;
}
my code for get an open read binary file descriptor.
you should use fclose to close FILE* if you don't need it .
i didn't test for case 1 and 2, so use it at your own risk.
you can't exchange(convert) them.. if you need to have a file with FILE* and HANDLE you need to open it twice
Is there any way to take advantage of the file creation flags in the Win32 API such as FILE_FLAG_DELETE_ON_CLOSE or FILE_FLAG_WRITE_THROUGH as described here http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx , but then force that handle into a std::ofstream?
The interface to ofstream is obviously platform independent; I'd like to force some platform dependent settings in 'under the hood' as it were.
It is possible to attach a C++ std::ofstream to a Windows file handle. The following code works in VS2008:
HANDLE file_handle = CreateFile(
file_name, GENERIC_WRITE,
0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (file_handle != INVALID_HANDLE_VALUE) {
int file_descriptor = _open_osfhandle((intptr_t)file_handle, 0);
if (file_descriptor != -1) {
FILE* file = _fdopen(file_descriptor, "w");
if (file != NULL) {
std::ofstream stream(file);
stream << "Hello World\n";
// Closes stream, file, file_descriptor, and file_handle.
stream.close();
file = NULL;
file_descriptor = -1;
file_handle = INVALID_HANDLE_VALUE;
}
}
This works with FILE_FLAG_DELETE_ON_CLOSE, but FILE_FLAG_WRITE_THROUGH may not have the desired effect, as data will be buffered by the std::ofstream object, and not be written directly to disk. Any data in the buffer will be flushed to the OS when stream.close() is called, however.
Some of these flags are also available when using _fsopen / fopen:
FILE* pLockFile = _fsopen(tmpfilename.c_str(), "w", _SH_DENYWR );
if (pLockFile!=NULL
{
// Write lock aquired
ofstream fs(pLockFile);
}
Here we open the file so when doing a flush, then it writes through (And it is deleted when closed):
FILE* pCommitFile = fopen(tmpfilename.c_str(), "wcD");
if (pCommitFile!=NULL)
{
// Commits when doing flush
ofstream fs(pCommitFile);
}