I was asked to find the size of the file usjng lseek command (without using stat) and i wrote the following code
int main()
{
char buf[100], fn[10];
int fd, i;
printf("Enter file name\n");
scanf("%s", fn);
fd = open(fn, O_RDONLY);
int size = lseek(fd, 0, SEEK_END);
printf("Size is %d", size);
close(fd);
}
But i am getting -1 as file size, where am i going wrong
From lseek documentation available online:
RETURN VALUE
Upon successful completion, lseek() returns the resulting offset
location as measured in bytes from the beginning of the file. On
error, the value (off_t) -1 is returned and errno is set to indicate
the error.
So you have to check the errno (print it if lseek returns -1):
The list of possible errors from the same link:
ERRORS
EBADF fd is not an open file descriptor.
EINVAL whence is not valid. Or: the resulting file offset would be
negative, or beyond the end of a seekable device.
ENXIO whence is SEEK_DATA or SEEK_HOLE, and the file offset is
beyond the end of the file.
EOVERFLOW The resulting file offset cannot be represented in an off_t.
ESPIPE fd is associated with a pipe, socket, or FIFO.
In your case, it is most likely EBADF.
the following proposed code:
cleanly compiles
properly checks for errors
performs the desired functionality
uses proper variable typing
and now the proposed code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main( void )
{
char fn[10];
int fd;
printf("Enter file name\n");
if( scanf("%9s", fn) != 1 )
{
fprintf( stderr, "scanf for file name failed\n" );
exit( EXIT_FAILURE );
}
if( (fd = open(fn, O_RDONLY) ) < 0 )
{
perror( "open failed" );
exit( EXIT_FAILURE );
}
off_t size = lseek(fd, 0, SEEK_END);
printf("Size is %ld", size);
close(fd);
}
Related
I am trying to read the last n-amount of digits from a text file without using the stdio.h function calls. I am unsure on how to do this as I am unable to use fseek without using stdio.h and I am not familiar with system calls. Any help would be appreciated.
#include <unistd.h>
#include <sys/types.h>
#include<sys/stat.h>
#include <fcntl.h>
int main() {
int fd;
char buf[200];
fd = open("logfile.txt", O_RDONLY);
if (fd == -1){
fprintf(stderr, "Couldn't open the file.\n");
exit(1); }
read(fd, buf, 200);
close(fd);
}
You can use lseek. Here's the prototype:
off_t lseek(int fd, off_t offset, int whence);
Here's how you can integrate it into your code:
lseek(fd, -200, SEEK_END);
read(fd, buf, 200);
Just for variety:
struct stat sb;
int fd = open( filename, O_RDONLY );
fstat( fd, &sb );
pread( fd, buf, 200, sb.st_size - 200 );
Note that lseek() then read() is not atomic, so if more than one thread is accessing the file descriptor, you'll have a race condition. pread() is atomic.
I tried to use the system call lseek() to get back the beginning of a file or reach the end of the file.
The exact code I used is:
int location = lseek(fd, 0, SEEK_SET) //get back to the beginning
int location = lseek(fd, 0, SEEK_END) //reach to the end
However, after the file location has been reset, whenever I tried to use read(), the return value of read() is always set to -1, which means something was wrong. Furthermore, the errno message I got was Bad file descriptor. Does anyone know what should I do?
PS: I tried to close and reopen the file to help me get back to the beginning of the file and it worked. But I have no ideas on how should I get to the end of the file and read the entire file in the reverse order without using lseek().
Plus: a reproducible example would be:
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
int main(void)
{
int fd;
char buffer[1000];
fd = creat("newFile", 0777);
memset(buffer, 'a', 500);
write(fd, buffer, 500); // fill up
int location = lseek(fd, 0, SEEK_SET); //get back to the beginning
int read_bytes = read(fd, buffer, 500);
// this should return the bytes it reads but it actually returns -1
printf("%d\n", read_bytes);
return 0;
}
The creat function does not allow you to read from the file. It only allows you to write to it.
From creat(2):
creat()
A call to creat() is equivalent to calling open() with flags equal to O_CREAT|O_WRONLY|O_TRUNC.
The important part here is O_WRONLY. That means "write only".
If you want to open the file (and create it) for reading and writing, then you can use open like so:
int fd = open("newFile", O_CREAT|O_RDWR|O_TRUNC, 0777);
The important part here is O_RDWR. That means "read and write".
If you want to have open give an error if the file already exists, add the O_EXCL flag; this causes -1 to be returned and errno to be set to EEXIST if the file already exists when you try to create it.
The following proposed code:
cleanly compiles
properly declares the variable types
properly creates the file
properly includes the needed header files
properly checks for error indications from C library functions (and properly handles any error)
And now, the proposed code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
int main(void)
{
int fd;
char buffer[1000];
// fd = creat("newFile", 0777);
fd = open("newFile", O_CREAT|O_RDWR|O_TRUNC, 0777);
if( fd < 0 )
{
perror( "open failed" );
exit( EXIT_FAILURE );
}
memset(buffer, 'a', 500);
write(fd, buffer, 500); // fill up
off_t location = lseek(fd, 0, SEEK_SET); //get back to the beginning
printf( "%ld\n", location );
ssize_t read_bytes = read(fd, buffer, 500);
if( read_bytes < 0 )
{
perror( "read failed" );
exit( EXIT_FAILURE );
}
// this should return the bytes it reads but it actually returns -1
printf("%ld\n", read_bytes);
return 0;
}
A run of the program results in:
0
500
Suggest reading/understanding the MAN pages for any C library functions your code uses
I try to create file using open(), then move 1MB with lseek() and finally need to write 1 byte into that file.
There is my code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int f_open(const char *name);
int f_open(const char *name){
int dskr;
dskr = open( name, O_CREAT );
if( dskr == -1 ){
perror( name );
exit(1);
}
printf( "dskr = %d\n", dskr );
return dskr;
}
int main( int argc, char *argv[] ){
int d;
int f;
char buf[20];
if( argc != 2 ){
printf( "Naudojimas:\n %s failas_ar_katalogas\n", argv[0] );
exit( 255 );
}
d = f_open( argv[1] );
lseek( d, 1, SEEK_SET );
f = write( d, buf, 1);
return 0;
}
File created correctly, but I am not sure if move 1MB works good and also write not working. I am not sure because program runs correctly but the size of it is 0.
What am I doing wrong?
A few bugs:
dskr = open( name, O_CREAT );
The flags to open() must include one of O_RDONLY, O_WRONLY or O_RDWR. So you probably want O_WRONLY | O_CREAT.
lseek( d, 1, SEEK_SET );
The offset to lseek is in bytes. If you want to seek 1 megabyte, you have to convert that into bytes. A convenient and readable way is to write 1024*1024.
Also, you ought to check the return value of lseek and report any errors appropriately.
f = write( d, buf, 1);
You never initialized buf[0], so you are writing one byte of garbage. (Anyway, there is no point in having buf be 20 bytes if you are never going to use the other 19.)
Also, you ought to check the return value of write and handle errors or short writes appropriately.
I have seen device file can be accessed directly in Linux and I want to have a try. I have a free disk partition without any file system. My test code is below.
I expect to get output read data: 199 when I run the program at the second time. But actually, I get output read data: 0 twice. No errors emerge during the program. I have no idea where is wrong.
Thanks for your time.
Test Code:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int main(){
int num = 0;
int fd = open("/dev/sda6", O_RDWR);
if(fd == -1){
fprintf(stderr, "open device failed, errno : %s(%d) \n",
strerror(errno), errno);
return 1;
}
ssize_t ret = read(fd, &num, sizeof(int));
if(ret != sizeof(int)){
fprintf(stderr, "read fails, errno : %s(%d) \n",
strerror(errno), errno);
return 1;
}
printf("read data: %d\n", num);
num = 199;
ret = write(fd, &num, sizeof(int));
if(ret != sizeof(int)){
fprintf(stderr, "write fails, errno : %s(%d) \n",
strerror(errno), errno);
return 1;
}
close(fd);
return 0;
}
The read and write start reading/writing at the implicit file offset stored in the descriptor, and increment it by the number of bytes read/written. Therefore, you would now read bytes 0 .. 3, and then write bytes 4 .. 7.
Instead of read and write and messing with lseek et al, use the POSIX standard pread and pwrite that do not use the implicit file offset in the descriptor but take explicit file offsets from the beginning of a file in the call.
#include <unistd.h>
ssize_t pread(int fd, void *buf, size_t count, off_t offset);
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
...
ssize_t ret = pread(fd, &num, sizeof(int), 0);
ssize_t ret = pwrite(fd, &num, sizeof(int), 0);
You do not seek in your program, so what it does:
Read the first 4 bytes of the device, then write the second 4 bytes.
Try
lseek(fd,0,SEEK_SET);
before write if you want to write at the beginning of fole.
#include<stdio.h>
#include<string.h>
int main()
{
long int count;
FILE *file=NULL;
file=fopen("sample.txt","r+");
if(file==NULL)
{
printf("file open fail\n");
return;
}
printf("file open succesfull\n");
if(0!=fseek(file,1,SEEK_END))
{
printf("seek failed\n");
return;
}
printf("seek successful\n");
count=ftell(file);
printf("%lu", count);
return 0;
}
Output
file open succesfull
seek successful
3
My smaple.txt file has only one char and that is q. Why it is showing 3 here ?
Also when I am having the file empty, then ftell() is returning 1, what is that?
Working on ubuntu 12.04
Your fseek(file, 1, SEEK_END) places the position one character beyond the end of the file. That explains why you observe count as one for the empty file. I guess that your file, that contains just a q, also contains a carriage return consisting of actually two characters. On character behind the end is 3, what you observed.
You use fseek() incorrectly to determine the file's size via ftell().
From man fseek() (italics by me):
int fseek(FILE *stream, long offset, int whence);
[...] The new position, measured in bytes, is
obtained by adding offset bytes to the position specified by whence.
This line:
if(0!=fseek(file,1,SEEK_END))
positions the file pointer 1 byte after the end of the file.
To fix this do:
if (0 != fseek(file, 0, SEEK_END))
You have misinterpreted the ftell & fseek functions. Less coffee more rest :p
ftell manpage
long ftell(FILE *stream);
The ftell() function obtains the current value of the file position
indicator for the stream pointed to by stream.
fseek manpage
int fseek(FILE *stream, long offset, int whence);
The fseek() function sets the file position indicator for the stream
pointed to by stream. The new position, measured in bytes, is
obtained by adding offset bytes to the position spec‐
ified by whence. If whence is set to SEEK_SET, SEEK_CUR, or SEEK_END, the offset is relative to the start of the file, the current
position indicator, or end-of-file, respectively. A
successful call to the fseek() function clears the end-of-file indicator for the stream and undoes any effects of the ungetc(3)
function on the same stream.
Create sample.txt
echo -n 'q' > sample.txt
File Seek Example
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char** argv )
{
FILE* file = fopen( "sample.txt", "r" );
if( NULL == file )
{
perror("Failed to open file");
return EXIT_FAILURE;
}
printf("File successfully opened\n");
long position = ftell( file );
printf( "Position before seek: %lu\n", position );
int status = fseek( file, 1L, SEEK_SET );
if( 0 != status )
{
perror("Failed to seek");
return EXIT_FAILURE;
}
printf("File seek successful\n");
position = ftell( file );
printf( "Position after seek: %lu\n", position );
return EXIT_SUCCESS;
}
File Size Example
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
int main( int argc, char** argv )
{
struct stat file_status = { 0 };
int status = stat( "sample.txt", &file_status );
if ( 0 != status )
{
perror("Failed to read file status");
return EXIT_FAILURE;
}
printf( "File size: %li\n", file_status.st_size );
return EXIT_SUCCESS;
}
Build
gcc -o example example.c