-2

I've search the MSDN but did not find any information about sharing a same HANDLE with both WriteFile and ReadFile. NOTE:I did not use create_always flag, so there's no chance for the file being replaced with null file. The reason I tried to use the same HANDLE was based on performance concerns. My code basically downloads some data(writes to a file) ,reads it immediately then delete it. In my opinion, A file HANDLE is just an address of memory which is also an entrance to do a I/O job. This is how the error occurs:

CreateFile(OK) --> WriteFile(OK) --> GetFileSize(OK) --> ReadFile(Failed) --> CloseHandle(OK)

If the WriteFile was called synchronized, there should be no problem on this ReadFile action, even the GetFileSize after WriteFile returns the correct value!!(new modified file size), but the fact is, ReadFile reads the value before modified (lpNumberOfBytesRead is always old value). A thought just came to my mind,caching!

Then I tried to learn more about Windows File Caching which I have no knowledge with. I even tried Flag FILE_FLAG_NO_BUFFERING, and FlushFileBuffers function but no luck. Of course I know I can do CloseHandle and CreateFile again between WriteFile and ReadFile, I just wonder if there's some possible way to achieve this without calling CreateFile again?

Above is the minimum about my question, down is the demo code I made for this concept:

int main()
{

    HANDLE hFile = CreateFile(L"C://temp//TEST.txt", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL| FILE_FLAG_WRITE_THROUGH, NULL);

    //step one write 12345 to file
    std::string test = "12345";
    char * pszOutBuffer;
    pszOutBuffer = (char*)malloc(strlen(test.c_str()) + 1); //create buffer for 12345 plus a null ternimator
    ZeroMemory(pszOutBuffer, strlen(test.c_str()) + 1); //replace null ternimator with 0
    memcpy(pszOutBuffer, test.c_str(), strlen(test.c_str())); //copy 12345 to buffer



    DWORD wmWritten;
    WriteFile(hFile, pszOutBuffer, strlen(test.c_str()), &wmWritten, NULL); //write 12345 to file

    //according to msdn this refresh the buffer
    FlushFileBuffers(hFile);

    std::cout << "bytes writen to file(num):"<< wmWritten << std::endl; //got output 5 here as expected, 5 bytes has bebn wrtten to file.

    //step two getfilesize and read file

    //get file size of C://temp//TEST.txt
    DWORD dwFileSize = 0;
    dwFileSize = GetFileSize(hFile, NULL);
    if (dwFileSize == INVALID_FILE_SIZE)
    {
        return -1; //unable to get filesize
    }
    std::cout << "GetFileSize result is:" << dwFileSize << std::endl; //got output 5 here as expected

    char * bufFstream;

    bufFstream = (char*)malloc(sizeof(char)*(dwFileSize + 1)); //create buffer with filesize & a null terminator
    memset(bufFstream, 0, sizeof(char)*(dwFileSize + 1));
    std::cout << "created a buffer for ReadFile with size:" << dwFileSize + 1 << std::endl; //got output 6 as expected here
    if (bufFstream == NULL) {
        return -1;//ERROR_MEMORY;
    }
    DWORD nRead = 0;
    bool bBufResult = ReadFile(hFile, bufFstream, dwFileSize, &nRead, NULL); //dwFileSize is 5 here

    if (!bBufResult) {
        free(bufFstream);
        return -1; //copy file into buffer failed
    }


    std::cout << "nRead is:" << nRead << std::endl; //!!!got nRead 0 here!!!? why?


    CloseHandle(hFile);
    free(pszOutBuffer);
    free(bufFstream);
    return 0;
}

then the output is:

bytes writen to file(num):5
GetFileSize result is:5
created a buffer for ReadFile with size:6
nRead is:0

nRead should be 5 not 0.

Lynch Chen
  • 178
  • 2
  • 16
  • What is the error? End of file. Why you don't check the error code before asking here. – i486 Oct 11 '17 at 08:12
  • @i486, I checked, and I have no idea there's an end of file problem. That file pointer concept didn't exist in my mind before. I put a lot of effort in this, even wrote a testing code and review it almost two days again and again but still don't understand, that made me extremely upset. Whatever you say, I still take all the criticism because I'm a beginner. You have no idea how a beginner feels when they encounter their bottleneck, no one wants to post stupid questions here to get criticized. As a beginner , I don't think it's stupid, I tried a lot, so I ask. – Lynch Chen Oct 12 '17 at 11:33
  • OK, but in MSDN you can read about `ReadFile` and its Return Value "If the function fails, the return value is zero (0). To get extended error information, call GetLastError". Then check value of `GetLastError` and see what is wrong. – i486 Oct 12 '17 at 11:45

3 Answers3

3

Win32 files have a single file pointer, both for read and write; after the WriteFile it is at the end of the file, so if you try to read from it it will fail. To read what you just wrote you have to reposition the file pointer at the start of the file, using the SetFilePointer function.

Also, the FlushFileBuffer isn't needed - the operating system ensures that reads and writes on the file handle see the same state, regardless of the status of the buffers.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
  • `SetFilePointer` also not need. simply need use explicit offset for `ReadFile` use – RbMm Jul 15 '17 at 15:39
  • 3
    I generally avoid exposing a novice immediately to the `lpOverlapped` stuff; its documentation (and the name, really) mixes synchronous and asynchronous IO, and it's easy to get confused; as a starting point it's generally easier to use the "classical" file pointer model, which is shared with virtually any other IO API (C stdio, C++ iostream, "classic" UNIX files). Also, if you seek so frequently that `SetFilePointer` calls (and not actual IO) start to be an issue probably you should just dump "regular" IO altogether and just map the file in memory (or do better user-mode caching). – Matteo Italia Jul 15 '17 at 15:46
  • `OVERLAPPED` containing additional parameters for `ReadFile`. it not direct related to asynchronous io. it used for both. simply for synchronous io it optional and for asynchronous mandatory. however - what is more easy and effective - use single api call or 2 api calls with same effect ? – RbMm Jul 15 '17 at 15:50
  • *I* know it, but go to read the documentation - `OVERLAPPED` is all about asynchronous IO, and you have to dig around to understand how it is employed with synchronous IO (and when you are allowed to use it). If I'm talking about reading the file with the classic file pointer model, which most programmers already have in mind, it's way simpler to explain that one call seeks, the other reads, exactly as `fseek`/`fread` (C), `istream::seek`/`istream::read` (C++), `lseek`/`read` (UNIX). – Matteo Italia Jul 15 '17 at 15:57
  • again `OVERLAPPED` used for any io . for synchronous as well. it always allowed to use. look like you also not good enough know this – RbMm Jul 15 '17 at 16:00
  • Also, given that the confusion probably stems from the fact that OP thinks that there's a read pointer and a write pointer, it's important to show that a Win32 file does not make a distinction, and how to move the single file pointer around. Using directly `ReadFile` *is fine*, but is using the file interface at a different level than OP is using, and in this case in my opinion it's more instructive to teach about what his mistakes about the file pointer are, given that it is *that one* interface he is using. – Matteo Italia Jul 15 '17 at 16:00
  • `you have to dig around to understand how it is employed with synchronous IO (and when you are allowed to use it)` - this is great mistake. `OVERLAPPED` used the same for any file handles. and it always allowed to use. absolute no matter synchronous or asynchronous file handle. difference only that for asynchronous io this is mandatory parameter, while for synchronous is optional. and how i view most programmers dont know this – RbMm Jul 15 '17 at 16:03
  • Thank you guys, before I thought the error was caused by file system caching and I was totally on the wrong path. [SetFilePointer] did make things very easy, Overlapped for me is much more advanced because I'm just on the start point making new programs with Windows API which I did not have many experience with. However overlapped still worth learning since I might use async in future.:) – Lynch Chen Jul 16 '17 at 18:01
1

After first write file cursor points at file end. There is nothing to read. You can rewind it back to the beginning using SetFilePointer:

::DWORD const result(::SetFilePointer(hFile, 0, nullptr, FILE_BEGIN));
if(INVALID_SET_FILE_POINTER == result)
{
    ::DWORD const last_error(::GetLastError());
    if(NO_ERROR != last_error)
    {
        // TODO do error handling...
    }
}
user7860670
  • 35,849
  • 4
  • 58
  • 84
  • for what absolute useless `SetFilePointer` when much better direct set offset in call to `ReadFile`. as result we will be have 1 api call instead 2 – RbMm Jul 15 '17 at 15:28
  • i mean that much more better use explicit offset in call `ReadFile` and have only one api call, instead use `SetFilePointer` – RbMm Jul 15 '17 at 15:33
  • you absolute wrong. accept - look at last parameter - pOverlapped - here and offset – RbMm Jul 15 '17 at 15:35
1

when you try read file - from what position you try read it ?

FILE_OBJECT maintain "current" position (CurrentByteOffset member) which can be used as default position (for synchronous files only - opened without FILE_FLAG_OVERLAPPED !!) when you read or write file. and this position updated (moved on n bytes forward) after every read or write n bytes.

the best solution always use explicit file offset in ReadFile (or WriteFile). this offset in the last parameter OVERLAPPED lpOverlapped - look for Offset[High] member - the read operation starts at the offset that is specified in the OVERLAPPED structure

use this more effective and simply compare use special api call SetFilePointer which adjust CurrentByteOffset member in FILE_OBJECT (and this not worked for asynchronous file handles (created with FILE_FLAG_OVERLAPPED flag)

despite very common confusion - OVERLAPPED used not for asynchronous io only - this is simply additional parameter to ReadFile (or WriteFile) and can be used always - for any file handles

RbMm
  • 31,280
  • 3
  • 35
  • 56
  • thanks for the clear statement for Overlapped thing. I did really think Overlapped thing are all for async. Looks like it worth for implementation. :0 – Lynch Chen Jul 16 '17 at 17:57
  • 1
    @LynchChen - this is very common mistake. even for experience windows programmers. read [*Considerations for working with synchronous file handles:*](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365467(v=vs.85).aspx) `if lpOverlapped is NULL, the read operation starts at the current file position.. If lpOverlapped is not NULL, the read operation starts at the offset that is specified in the OVERLAPPED structure` – RbMm Jul 16 '17 at 18:18
  • need understand that `SetFilePointer` - this is additional api cal to kernel mode with great overhead. for what when we can done all with single call ? and even on source code level we have win - try for test write both codes (with ovelpapped and with SetFilePointer) and with error checks. which code will be smaller and more simply ? – RbMm Jul 16 '17 at 18:21
  • Yeah, the sync info would be something I'll never notice if I did not read your post. Most of the documents about overlapped were all about async , and i think thats why it became a common mistake. I did try to figure out what overlapped was going on before but never notice the sync part. I appreciate the great lesson and your kindness. – Lynch Chen Jul 16 '17 at 18:29