[go: up one dir, main page]

0% found this document useful (0 votes)
10 views29 pages

09.1 FileIO Calls C

The document discusses file input/output operations in programming, focusing on system calls like open, read, write, close, and lseek, as well as standard library functions like fprintf. It explains the differences between low-level syscalls and higher-level buffered I/O functions, emphasizing how buffered functions improve performance by reducing the number of syscalls. Additionally, it includes examples and activities to illustrate file manipulation and the use of file descriptors.

Uploaded by

akaaljot.mathoda
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views29 pages

09.1 FileIO Calls C

The document discusses file input/output operations in programming, focusing on system calls like open, read, write, close, and lseek, as well as standard library functions like fprintf. It explains the differences between low-level syscalls and higher-level buffered I/O functions, emphasizing how buffered functions improve performance by reducing the number of syscalls. Additionally, it includes examples and activities to illustrate file manipulation and the use of file descriptors.

Uploaded by

akaaljot.mathoda
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 29

File I/O

Syscalls & StdLib

25-03-10 CMPT 201 Slides 9.1 © Dr. B. Fraser 1


Topics


What syscalls can we use to access files (like write())?

Why are there stdio functions, like fprintf(), in addition to
write()?

Why do writes sometimes not happen right away?

25-03-10 2
Basic I/O
System Calls

25-03-10 3
File Offset This means the offset is a number (like 42) that tells the OS:
“Start reading/writing from byte 42 in the file.”


File offset X
.. points
a points to
that let in the fils who e a

– Offset is where both read() and write() occur (one pointer). n

6
– Move it to an arbitrary position using lseek()

continu
– read() and write() automatically increments the offset:
.. subsequent calls um zet
i
i
next deta

lseek(fd, 0, SEEK_SET); // go to beginning of file


lseek(fd, 100, SEEK_CUR); // move 100 bytes ahead from current
So if you read 10 bytes, the offset moves forward 10 bytes.
lseek(fd, -10, SEEK_END); // go 10 bytes back from end
• Same for writing — it continues from where the last write ended.

25-03-10 4
IO Syscalls

5 basic system calls for file I/O
– open
-
– read -

– write -

-
– close
– fcntl - File control
-

25-03-10 5
open()
mode sits


open() receives 2 or 3 parameters: file permission
– int open(const char *pathname, int flags);
/ 0043 Cow-rof
to

– int open(const char *pathname, int flags, mode_t mode);

flags: ..

– Must be one of: O_RDONLY, O_WRONLY, or O_RDWR


open for Read only, write only, read/write
Flags can also be bitwise-or'd with others such as: to specifyaddition

our

– O_RDWR | O_APPEND: All write actions happen at end of file


-
- – O_WRONLF | O_CREAT: If file does not exist, then create it.

- – O_RDWR | O_TMPFILE: Create an unnamed temporary file


~ – O_WRONLY | O_TRUNC: Truncate file when opened for writing

Bitwise-or sets individual bits in a bit vector,
e.g., O_RDWR | O_CREAT
25-03-10 ↓ 6

00000001 (O_WRONLY) rumpe


| 00000100 (O_CREAT)
----------- int fd = open("data.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
00000101 (Combined flags)
empe
open() cont int fd = open("data.txt", O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);


Recall:

– int open(const char *pathname, int flags);

– int open(const char *pathname, int flags, mode_t mode);


mode
– .. Sets the file permission when creating file
(flags O_CREAT or O_TMPFILE)

S_IRWXU: User can read/write/execute

S_IRUSR | S_IWUSR: .. User can read/write

Return Value a hanelle is just an

– .. File descriptor
:
abstraction or
reference
a handle for the file to read and write: to a resource him a

it’s a small non-negative integer (int) fete or window

– It could change every time you open the file.


Think of It Like This:

25-03-10 Imagine going to a cloakroom and giving them your jacket. They give you a token (handle). 7
That token doesn’t hold the jacket — it’s just a reference that lets you ask for your jacket later.
Common reserved FDs:

Similarly: • 0: Standard input (stdin)

• File = actual resource (like your jacket) • 1: Standard output (stdout)

• Handle (FD) = token that lets you access and manipulate it • 2: Standard error (stderr)
descripts
filte
to an
file
write()
M
ofn to a buffer
comp array
- to store

ssize_t write(int fd, const void *buf, size_t count); - data)


b

write() writes buf to a file descriptor and no
of
.. returns the no- of bytes written bytes you
wit

man 2 write important points: wart to

– .. no be bes than count because


of bytes written may
insufficient space on disk
-


call interrupted by a signal handler
– Writing takes place at the file offset, and
offset is incremented by the number of bytes actually written.

&
So will It sends the data from memory (buf) to the file/device identified by fd.

25-03-10 8

write(fd, buf, 10); // writes 10 bytes at offset 0


write(fd, buf2, 5); // writes 5 bytes starting at offset 10
read() Muffer
detta
pers
will Ne Stor
-
ssize_t read(int fd, void *buf, size_t count);

read() reads from a file descriptor and
.. returns the no-of bytes each

`man 2 read` important points:
– read operation commences
-
at the file offset,
which is incremented
- by the number of bytes read.
=
– If file offset is at or past the end of file,
.. no bytesarnotread & read() returns O
– Not an error if # bytes read < # bytes requested
-

- fewer bytes available right now (near end-of-file or


reading pipe/terminal)

-
-or read() was interrupted by a signal

25-03-10 9

read 1) -
It fills your buffer (buf) with data from the file/device linked to fd.
close()
it can be
releases it so
int close(int fd); - resed
- closes the file descriptor.

- Writes any remaining buffered data to file.


25-03-10 10
lseek() How many
lyte
to move
From where

to move

- -
off_t lseek(int fd, off_t offset, int whence);

Manually adjust the file offset.
– man lseek

whence to adjust the
which location he was
– .. from
fil offset

SEEK_SET: Start of file

SEEK_CUR: Current offset

SEEK_END: End of file (1st byte after end of file)
– offset is always added.
– Can seek past end of file:
next write will extend file with 0’s.

25-03-10 11
ABCD: lseek

Suppose a file has 6 bytes (i.e., EOF is at 6) and
the current file offset is 4: in ~
CEOF]
Index 0 1 2 3 4 5 6 7 ...
Hello !
Content H e l l o ! <EOF> --


-
1
SEEKEND
SEEK -
SET

– Note: <EOF> does not actually appear in the file.



What character is read when doing a read() of 1 byte after
the following calls (in isolation)?
HI
a) l
1) lseek(fd, SEEK_SET,0
4)
A

b) o
2) lseek(fd,-ISEEK_CUR,1)
-1)
-
c) !
3) lseek(fd, SEEK_END, -1)
() d) none

25-03-10 12
fcntl() file descriptor operation
code optional
argument
M - -
int fcntl(int fd, int op, ... /* arg */ );

File control
– man fcntl
– It can do many things, such as

modify flags and mode used when file was opened:
op = F_SETFL (set flag)

open() sets flags only once.


• fcntl() gives you flexibility at runtime.

25-03-10 13
Activity: Files

Write a program that:
– Creates a new file named “tmp” in current folder
– Writes X bytes to a file

Write a string like “Hello World!”; your choice!
– Moves the file offset backward by X/2 bytes
– Reads and prints out from the offset to EOF
– Closes the file

25-03-10 Solution: lseek_half.c 14


#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
int main() {
// O_TRUNC If the file already exists, this flag will: Erase all existing
// content (truncate it to size 0) So the file becomes an empty file, as if it
// was just created.
int fd = open("tmp", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd == -1) {
perror("open");
;
return 1;
}
char *msg = "Hello World!";

if (write(fd, msg, strlen(msg)) != strlen(msg)) {


output
perror("write");
close(fd); ./write_half
return 1; World!%
}

// 3. Move file offset backward by X/2


off_t offset = lseek(fd, (-1 * (strlen(msg) / 2)), SEEK_END);
if (offset == -1) {
perror("lseek");
close(fd);
return 1;
}

// 4. Read from the offset to EOF


const int MAX_SIZE = 1024;
char buffer[MAX_SIZE]; // Should be enough for this example
int size = read(fd, buffer, MAX_SIZE - 1);
if (size == -1) {
perror("read");
close(fd);
return 1;
}
buffer[size] = '\0'; // Null-terminate the string
write(STDOUT_FILENO, buffer, size);

// 6. Close the file


close(fd);
return 0;
}
Buffered I/O

25-03-10 15
Categories of File Functions
functions directly
communicies
-low level

Syscalls with the OS Kernel
– I/O functions that are system calls:
write(), read(), etc. (previous slides)

.. standard library (stdio) functions but
Y – All I/O functions that start with f: -not syscall
-

but on
night fprintf(), fscanf(), fputs(), fgets(), fput(), fget(), etc. them
wee – The same functions without f:
functions printf(), scanf(), puts(), gets(), etc.


What’s the difference?
– Let's look at write(), fprintf(), and printf()

25-03-10 16
write() vs fprintf()

write() directly sends data to the kernel,
fprintf() .. manages luffer in memory
a
to
& writes to the lupfer & occasionally fluchs write)
fels using
-

actual
– Uses write() under the hood. The

– Because of this,.. bbrintf is called buffred I o


– fprintf() generates fewer syscalls, which gives better
performance (less overhead).

File Descriptor vs FILE stream
– Syscalls like write() take..
ssize_t write(int fd, const void *buf, size_t count);
– Library functions like fprintf() take..
Y int fprintf(FILE *stream, const char *format, ...);
Zahl
FILE
Stream
25-03-10 17
Stream vs File Descriptor

What is a Stream
FILE *stream
– Convenient wrapper around a file descriptor.
Used by the stdio functions.
– Think of this as
.. a fils description plus Muffer
a
teaching it
up

Converting Stream <==> File Descriptor
– You can get the file stream from a file descriptor with:
.. fdopen()
– You can get the file descriptor from a file stream with:
..
filno()

25-03-10 18
Relationship

-(in
User program has data

User Program
memory) to write.

-It calls library function.



fprintf() fscanf() ...
stdlib
functions

User Space
Data written into

stdio buffer
-library’s buffer. (memory)

Later executes syscall



I/O
to write
-
Kernel
Space
write() read() ... system
to kernel. calls

Kernel will
-

write to disk. Disk

25-03-10 19
Activity: Kernel Write

Write a program that will:
– open() a file named tmp,
– write() a string (your choice) to tmp,
– infinite loop that calls sleep() for 30 seconds each loop.

Experiment
– Run it in the background
– Did it write to the file tmp. Check with cat.
(It should.)


When done, delete tmp from the command line.
Even though the process is still running in the background, the file was written immediately because write() is
unbuffered (it goes directly to the disk).

25-03-10 20

/
cat kernel_write.c
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
int main() {
int fd = open("tmp", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);

char *msg = "Hello World!";


int res = write(fd, msg, strlen(msg));

while (1) {
sleep(30);
}
}
~/units/05-lectures/09› cat tmp
Hello World!%

~/units/05-lectures/09› ./lib_print&
[2] 31449
~/units/05-lectures/09› cat lib_print.c
#include <stdio.h>
#include <unistd.h>

int main() {
FILE *fp = fopen("tmp", "w");

fprintf(fp, "Hello from stdio!\n"); then


>
-

// fclose(fp); I rnabled

Y
see
while (1) { we can

sleep(30);
} meg on
return 0; imp
}
~/units/05-lectures/09› cat tmp
~/units/05-lectures/09›
Activity: Library print

Write another program that will
– fopen() a file named tmp,
– fprintf() a string to tmp,
– infinite loop that calls sleep() for 30 seconds each iteration.

Run It
– Run it in the background
– Did it write to the file tmp. Check with cat.
(It should not!)
Even though the process is still running in the background, the file
was written immediately because write() is unbuffered (it goes
directly to the disk).

Experiment
– Change to close file after writing. Repeat running it.
It should write to file.
ver
ffluch) or fulose 1)
25-03-10 21

Standard library I/O is buffered. Always flush or close to ensure data is saved.
Buffering

Explain Behaviour
– Why did fprintf() not write to the file when the file is left open?
– Why did it write when we closed?
– Answer:.. Changes were differed

fflush() immediately sends the buffered data to the kernel.
– Calling setbuf() with NULL as the buffer automatically does
flushing.--
Y
-

– Read `man setbuf` for more details. vicl of


get
uuffering

25-03-10 22
Activity: fflush()

Change Previous Program with fprintf():
– Add fflush() call after printing

Run it and see if it writes to tmp. (It should.)

25-03-10 23
Kernel Buffering
User Program

Kernel has
read/write buffers
-

-
fprintf() fscanf() ... stdlib
too.

User Space
functions
-

[

Even kernel does stdio buffer
not immediately (memory)
write to disk.

Kernel Space I/O


write() read() ...
system
calls
Kernel buffer
(memory)

Disk
25-03-10 24
Kernel Buffering

Can force kernel to flush buffer with*
fsync()

-
-
Using O_SYNC when with open() automatically does fsync().

Parallel between user buffering and kernel buffering

-
fflush() and fsync(): both flush their buffer.
– setbuf() with a NULL buffer and O_SYNC:
.. both
automatically perform
buffering
no
.

25-03-10 25
Blocking vs Non-Blocking I/O

Blocking call
.. doesn't return until the operation can be done .
– E.g., a blocking read() call doesn't return until there's
something to read.

Non-blocking call
– O_NONBLOCK flag
(either with open() or with fcntl() & F_SETFL)
– If an operation can't be done immediately, then
.. the all returns error an , typically
EAGAIN .

25-03-10 26

Imagine calling someone and waiting for them to answer — you’re blocked until they pick up. >
-

Blocking
Non-Blocking
You knock once and walk away if there’s no answer — no waiting.
>
-
Summary

5 Syscalls for File Access
– int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
– ssize_t write(int fd, const void *buf, size_t count);
– ssize_t read(int fd, void *buf, size_t count);
– int close();
– off_t lseek(int fd, off_t offset, int whence);

Syscalls vs Library functions
– write() vs fprintf()
– Non-buffered vs buffered IO
– File descriptor (int) vs stream (FILE*)

25-03-10 27

You might also like