Re: fgets() equivalent?
- From: Harish <Harish@xxxxxxxxxxxxxxxxxxxxxxxxx>
- Date: Wed, 28 Nov 2007 20:46:02 -0800
Thank you.
-Harish
"Pops" wrote:
Harish wrote:.
(1) Is there a fgets() equivalent function in Win32
that retrieves one line of data from a file
(till a newline is found)?
(2) I can use fgets() itself, but I cannot specify
share mode options as in CreateFile().
Please suggest a workaround.
(1)
fgets() is standard in C file I/O.
The only issue you need to pay attention too, is RAW (binary) vs COOK
mode. It will relate t he EOL (end of line) definitions of MS-DOS
(<CRL><LR>) vs Unix (<LF>). Depending on your application that may or
may no pertain.
In RAW, you see everthing, nothing is hidden. In COOK, it related to
how \r and \n is intepreted.
For example, in MSDOS cook mode, using "\n" transfer to <CR><LF>. I
in raw mode, it is <LF>
Reminder this as a TIP:
\r -----> Return the PRINTER HEAD back to column 1
\n -----> Move the PRINTER HEAD back to the next line.
In COOK mode, the \n is does both for you, so that is why there are two
bytes <CR><LF>
In Unix, the proper way of controling the printer (or display, which is
a emulation of the printer), is to use \r\n because Unix is using binary
mode.
Here is an example of a line reader:
#include <stdio.h>
#include <windows.h>
int main(char argc, char *argv[])
{
char *szFileName = argv[1];
FILE *fv = fopen(szFileName,"rt");
if (fv) {
char szLine[1024];
while (fgets(szLine,sizeof(szLine)-1,fv)) {
printf("%s",szLine);
}
fclose(fv);
}
return 1;
}
Note the printf is not using any printer controls, that is because it is
expected the szLine will have them. fgets() does not trim it off.
Now, change that the fopen mode to "rb" for read binary, and now, the
printf will put more control chracters. That is because printf itself is
working in COOK mode.
So when it comes to Windows, you need to keep in mind RAW vs COOK mode.
More examples:
// opens the file in text mode, cooked.
FILE *fvt = fopen("crap1.txt","wt");
fprintf(fvt,"%s\n",string); <-- note \n
fclose(fvt);
// opens the file in binary mode, raw
FILE *fvb = fopen("crap2.txt","wb");
fprintf(fvb,"%s\r\n",string); <-- note \r\n
fclose(fvb);
Now, you can also change the default MODE using the _setmode() function.
Here is an example of changing standard I/O into binary (raw) mode:
_setmode( _fileno( stdin ), _O_BINARY );
_setmode( _fileno( stdout ), _O_BINARY );
This is good when dealing with the Unix world, and also internet
protocols that use <cr><lf> and/or <LF> as delimiters.
You can also use _fmode to set the default that WIN32 uses for the process.
(2)
In regards to CreateFile(), this is what all file I/O higher level APIs
eventually use. They all have translations for the modes you want.
It depends on what are sharing need as to what you want to do. In
general fopen() is not what you want if you must have complete control
of SHARE READ/WRITE options. You can _open or _sopen and few other ways.
See the MSDN help for fopen and _open
Essentially, you are now talking about STREAM vs HANDLE mode. fgets()
is a streaming I/O function which windows handling the caching, the EOF
and the EOL for you, etc.
In HANDLE mode, you don't have a stream and its a RAW type of operation,
meaning you are dealing in binary mode and you can take it all into
accounts.
For example, this is an function that acts like fgets for a file handle.
BOOL ReadLine(HANDLE fh, char *buffer, DWORD buflen)
{
DWORD i, readamt;
if (buffer == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!ReadFile(fh,buffer,buflen,&readamt,NULL) || (readamt==0)) {
SetLastError(ERROR_HANDLE_EOF);
return FALSE;
}
for (i = 0; i < readamt; i++) {
BYTE c = ((BYTE *)buffer)[i];
if (c == '\r') {
((BYTE *)buffer)[i] = 0;
if (i+1 < readamt && ((BYTE *)buffer)[i+1] == '\n') {
i++;
}
break;
} else if (c == '\n') {
((BYTE *)buffer)[i] = 0;
break;
}
}
if (i >= readamt) {
((BYTE *)buffer)[i] = 0;
} else {
i++;
}
SetFilePointer(fh,i - readamt, NULL, FILE_CURRENT);
return TRUE;
}
The above will work for both <lf> and <cr><lf> and it will remove it
from the line. This is a fast reader, since it reads blocks of bytes
and parses it, so the logic includes file position resetting. I
illustrated this just to point of buffer handling as oppose to reading 1
byte at a time.
You can use this function like so:
HANDLE h;
char *szFileName;
szFileName = argv[1];
h = CreateFile(szFileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL );
if ( h != INVALID_HANDLE_VALUE ) {
char szLine[1024];
int nTotal = 0;
while (ReadLine(h,szLine,sizeof(szLine)-1)) {
nTotal++;
printf("%s\n",szLine); <-- note the \n
}
CloseHandle(h);
printf("-- Total Lines: %d\n",nTotal);
} else {
printf("oops error %d opening file\n",GetLastError());
}
Hope this provides insight to explore it. File Sharing can be very
complex and there are quite a few ways, it all depends on your needs how
you the standard I/O and the WIN32 blends.
--
HLS
- References:
- Re: fgets() equivalent?
- From: Pops
- Re: fgets() equivalent?
- Prev by Date: Re: fgets() equivalent?
- Next by Date: Re: Efficient memory allocation
- Previous by thread: Re: fgets() equivalent?
- Next by thread: Re: fgets() equivalent?
- Index(es):
Relevant Pages
|