Re: fgets() equivalent?
- From: Pops <dude@xxxxxxxxxxxxxxxxxxxxxx>
- Date: Wed, 28 Nov 2007 05:04:01 -0500
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
.
- Follow-Ups:
- Re: fgets() equivalent?
- From: Tim Roberts
- Re: fgets() equivalent?
- From: Harish
- Re: fgets() equivalent?
- Prev by Date: Re: Efficient memory allocation
- Next by Date: Re: Efficient memory allocation
- Previous by thread: Re: fgets() equivalent?
- Next by thread: Re: fgets() equivalent?
- Index(es):
Relevant Pages
|