APUE笔记二

1. 文件的基本操作及空洞文件

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main( void )
{
        int     fd;
        int     n;
        char    buf[ 10 ] = "abcdefghij";
        char    buf1[ 10 ] = "ABCDEFGHIJ";
        if ( ( fd = open( "test", O_RDWR | O_CREAT ) ) < 0 )
                printf( "open test file error\n" );
        if ( write( fd, buf, 10 ) != 10 )
                printf( "write error\n" );
        if ( ( n = lseek( fd, 40, SEEK_SET ) ) == -1 )
                printf( "lseek error\n" );
        if ( write( fd, buf1, 10 ) != 10 )
                printf( "write error\n" );
        if ( lseek( fd, 0, SEEK_SET ) == -1 )
                printf( "lseek error\n" );

        return 0;
}

程序输出:



2. 原子操作

    考虑多个进程对同一个文件进行读取的时候,会造成以下后果:进程A在索引lseek到100,然后进程B也lseek到100,接着写入数据。然后进程A继续写入文件,则会覆盖掉进程B写入的数据。我们通过父进程,子进程进行模拟操作。

但是父进程和子进程是共享资源的,所以无法很好的解释。

#include <stdio.h>
#include <fcntl.h>

int main( void )
{
        int     fd;
        int     n;
        pid_t   pid;
        char    buf1[] = "abcdefghi\n";
        char    buf2[] = "ABCDEFGHI\n";

        if ( ( fd = open( "test", O_RDWR ) ) == -1 ){
                printf("open file error\n");
        }
        if ( write( fd, buf1, 10 ) != 10 ){
                printf( "parent write error\n" );
        }
        if ( ( pid = fork() ) < 0 ){
                printf("fork error\n");
        } else if ( pid == 0 ){
                if ( ( fd = open( "test", O_RDWR ) ) == -1 ){
                        printf("open file error\n");
                }
                lseek( fd, 5, SEEK_SET );
                if ( write( fd, buf2, 10 ) != 10 ){
                        printf("child write error\n");
                }
        }
        if ( write( fd, buf1, 10 ) != 10 ){
                printf( "parent write error\n" );
        }

        return 0;
}

程序输出:


    父进程第一次写入abcdefghi,然后子进程从第五字节开始覆盖写入,由于父进程和子进程共享资源,所以父进程继续在文件的末尾写入。

    如果是两个不同的进程,则程序输入应该是:abcdeABCDEacbdefghi。两个进程会对文件进行互相的覆盖。


3. dup和dup2的操作

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main( void )
{
        int     fd1;
        int     fd2;
        char    buf[ 1024 ];
        int     n;
        if ( ( fd1 = dup( 0 ) ) == -1 ){
                printf("dup error\n");
        }
        printf("%d\n", fd1 );
        if ( ( fd2 = open( "test.out", O_RDWR ) ) == -1 ){
                printf("open file error");
        }
        if (  dup2( 1, fd2 ) < 0 ){
                printf("dup2 error\n");
        }

        while ( ( n = read( fd1, buf, 1024 ) ) > 0 ){
                if ( write( fd2, buf, n ) != n ){
                        printf( "write error\n" );
                }
        }
        if ( n < 0 ){
                printf("read error\n");
        }

        return 0;
}

1) 将标准输入流0定位到fd1中,将文件fd2定位到标准输出流1中(这里并不是重定向,因为数据不仅写入fd2中,还显示在界面上)

2) 将数据从fd1中读取,写入fd2中,则相当于从标准输入流中读取数据,写入到标准输出流中。

程序输出:



4. fcntl函数

    fcntl用于改变已打开的文件的性质。

#include <stdio.h>
#include <fcntl.h>

int main( int argc, char *argv[] )
{
        int     fd;
        int     val;
        if ( argc != 2 )
                printf("usage:a.out <descriptor#>");
        if ( ( val = fcntl( atoi( argv[ 1 ] ) , F_GETFL, 0 ) ) < 0 )
                printf("fcntl error for fd %d", atoi( argv[ 1 ] ) );

        switch( val & O_ACCMODE ){
                case O_RDONLY:
                        printf("read only");
                        break;
                case O_WRONLY:
                        printf("write only");
                        break;
                case O_RDWR:
                        printf("read write");
                        break;
                default:
                        printf("unknown access mode");
                        break;
        }

        if ( val & O_APPEND )
                printf(",append");
        if ( val & O_NONBLOCK )
                printf(",nonblocking");
#if defined( O_SYNC )
        if ( val & O_SYNC )
                printf( ", synchronous writes");
#endif
#if !defined(_POSIX_C_SOURCE ) && defined( O_FDYNC )
        if ( val & O_FSYNC )
                printf(",synchronous writes" );
#endif
        putchar('\n');
        return 0;
}

程序输出:


     修改文件描述符标志或文件状态标志时候要小心,先要取得现有的标志值,然后根据需要修改它,最后设置新标志值。不能只是执行F_SETFD或F_SETFL命令,这样会关闭以前设置的标志位的。

void set_fl( int fd, int flags )
{
        int     val;
        if ( ( val = fcntl( fd, F_GETFL, 0 ) ) < 0 )
                printf("fcntl F_GETFL error");
        val |= flags;
        if ( fcntl(fd, F_SETFL, val ) < 0 )
                printf("fcntl F_SETFL error");
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值