370 likes | 442 Views
Client/Server Distributed Systems. 240-322, Semester 1, 2005-2006. Objectives look at low-level operations for handling files. 4. Low-level File I/O. Overview. 1. Basic Operations 2. Why use Low-level Operations? 3. A Simple Example 4. File Descriptors 5. File Permissions Again
E N D
Client/Server Distributed Systems 240-322, Semester 1, 2005-2006 • Objectives • look at low-level operations for handling files 4. Low-level File I/O
Overview 1. Basic Operations 2. Why use Low-level Operations? 3. A Simple Example 4. File Descriptors 5. File Permissions Again 6. open() 7. creat() continued
8. close() 9. read() 10. write() 11. copyfile.c 12. lseek() 13. File Pointers
1. Basic Operations • Name Meaningopen() Opens a file for reading or writing.creat() Creates an empty file for writing.close() Closes an open file.read() Reads data from a file.write() Writes data to a file.lseek() Moves to a specified byte in the file.unlink() Removes a file.
Information on Operations • apropos <name>man -k <name> • e.g. apropos open • man <name>man <section number> <name> • e.g. man 2 open • Look in /usr/include
2. Why use Low-level Operations? • No buffering of I/O • useful for network programming and reading/writing to certain peripherals (e.g. tape drives) • No conversion of I/O • no transformation of input to integers, floats, etc.;output can be any byte sequence • Can be used as building blocks for more complex I/O.
3. A Simple Example (oprd.c) #include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>int main(){ int fd, nread; char buf[1024]; if ((fd = open("data-file", O_RDONLY)) == -1) { perror("open"); exit(-1); } :
nread = read(fd, buf, 1024);close(fd); buf[nread-1] = '\0'; /* so can print */ printf("buf: %s\nnread: %d\n", buf, nread); return 0;}
4. File Descriptors • A file descriptor is a small, non-negative integer. • A file descriptor identifies an open file to the low-level operations. • Standard descriptors: 0 represents stdin1 stdout2 stderr
5. File Permissions • One way of using chmod is with letters to represent permissions: e.g. chmod a+r file • Most low-level operations (and chmod) represent permissions as octal values:e.g. chmod 0644 file
File Permissions as Octals Octal Symbolic Meaning of Permission0400 r-- --- ---0200 -w- --- ---0100 --x --- ---0040 --- r-- ---0020 --- -w- ---0010 --- --x ---0004 --- --- r--0002 --- --- -w-0001 --- --- --x
Example • Add octal values together to get the complete file permission:Octal Meaning0400 r-- --- --- 0200 -w- --- --- 0040 + + --- r-- --- 0004 --- --- r-- ==== =========== 0644 rw- r-- r-- • Use in chmod: chmod 0644 file
6. open() • #include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>int open(char *pathname, int flag /*, mode_t mode */ ); • Return file descriptor if ok, -1 for error
Some open() Flags O_RDONLY Open file for reading only.O_WRONLY Open file for writing only.O_RDWR Open file for both reading & writing.Possibly combined with:O_APPEND Append to file when writing.O_CREAT Create file if is does not exist (requires the 3rd modeargument).O_EXCL Return -1 error if file is to be created and already exists.
Using Bitwise OR • open() flags can be combined with the bitwise OR operator ‘|”: fd = open(file, O_WRONLY | O_APPEND); • Now each write(fd, buf, BUFSIZE)means append to the end of the file.
7. creat() • #include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>int creat(char *pathname, mode_t mode); • Creates a new file, or truncates an old one. • Return file descriptor if ok, -1 on error.
mode gives access permission of resulting new file:0644 (rw- r-- r--) • mode only has meaning if the file is new.
Create a new file #include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>void main(){ int fd; if ((fd = creat(“new-file”,0644))== -1){ printf(“cannot create new-file\n”); exit(1); } /* rest of program */}
Replacing creat() with open() • creat() only opens a file for writing; to read it the file must be closed and opened for reading. • creat() can be replaced by open():open(“new-file”, O_WRONLY | O_CREAT | O_TRUNC, 0644)
Other Versions • creat() version which can read and write:open(“new-file”, O_RDWR | O_CREAT | O_TRUNC, 0644) • Avoid truncation of old file (append instead): open(“new-file”, O_WRONLY|O_CREAT|O_APPEND, 0644)
One User at a Time • Create lock if it doesn’t already exist, otherwise fail (and return -1): fd = open(“lock”, O_WRONLY|O_CREAT|O_EXCL, 0644); • Use lock to protect access to another file • open “accounts” only if lock can be opened • after processing “accounts”, delete lock
8. close() • #include <unistd.h>int close(int fd); • Close a file: return 0 if ok, -1 on error. • Useful since the number of open files is limited (~20)
9. read() • #include <sys/types.h>#include <unistd.h>int read(int fd, void *buffer, unsigned int nbytes); • Tries to read nbytes into the buffer array • no conversion of bytes (characters) • may read less than specified amount (e.g. at end) • Returns the no. of bytes read, 0 if end of file, -1 on error.
The Read-Write Pointer • The R-W Pointer records the position of the next byte in the file to be read (or written). • It is implicit (hidden) in each use of read() and write()
Count Characters (countchars.c) #include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#define SIZE 512int main(){ char buffer[SIZE]; int fd, j; long total = 0; : continued
if ((fd = open(“data-file”, O_RDONLY)) == -1){ perror("open"); exit(1); } while((j = read(fd, buffer, SIZE)) > 0) { putchar('.'); total += j; } putchar('\n'); printf(“total chars: %ld\n”, total); close(fd); return 0;}
UNIX systems are often configured to read/write in blocks of 512 or 1024 bytes (the diskblocking factor). • Can use BUFSIZ from stdio.h which contains a default disk blocking factor.
10. write() • #include <unistd.h>int write(int fd, void *buffer, unsigned int nbytes); • Returns number of bytes written if ok, -1 on error. • write() starts at the current R-W pointer position, and pointer is moved as file is written.
Example :int fd;char header1[512], header2[512]; :if ((fd = creat(“foo”, 0644)) != -1) : write(fd, header1, 512); write(fd, header2, 512); :
11. copyfile.c #include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>int copyfile(char *nm1, char *nm2);void main(){ printf("result: %d\n", copyfile(“test.in”, “test.out”) );} continued
int copyfile(char *nm1, char *nm2){ int infd, outfd, nread; char buffer[BUFSIZ]; if ((infd = open(nm1,O_RDONLY))== -1) return -1; if ((outfd = creat(nm2,0644)) == -1){ close(infd); return -2; } : continued
while ((nread = read(infd, buffer, BUFSIZ)) > 0) { if (write(outfd, buffer, nread) < nread) { close(infd); close(outfd); return -3; /* write error */ } } close(infd); close(outfd); return 0;}
copyfile() & BUFSIZ • BUFSIZ Real time User time System time1 3:42.8 4.1 3:24.864 0:27.3 0.0 0:05.1511 0:24.0 0.0 0:01.9512 0:22.3 0.0 0:01.0513 0:25.1 0.0 0:02.44096 0:13.3 0.0 0:00.98192 0:12.9 0.0 0:01.1 • Most saving is made by reducing no. of system calls.
12. lseek() • #include <sys/types.h>#include <unistd.h>long int lseek(int fd, long int offset, int start); • Change position of R-W pointer: return new file offset if ok, -1 on error. • Start names (and numbers): • SEEK_SET 0 start of file • SEEK_CUR 1 current R-W pointer position • SEEK_END 2 end of file
Code Fragments • :fd = open(filename, O_RDWR);lseek(fd, 0L, SEEK_END);write(fd, buffer, BUFSIZ);: • /* get filesize in bytes */long int filesize;filesize = lseek(fd, 0L, SEEK_END);
13. File Pointers • Connect a file pointer to fd’s file with:#include <stdio.h>FILE *fdopen(int fd, char *mode); • mode is usual thing: “r”, “w”, “rb”, etc. • Useful for doing formatted I/O on top of pipes and network comunication.
Code Fragment • int fd = open("data", O_RDONLY);FILE *fp = fopen(fd, "r");int num;fscanf(fp, "%d", &num);