1.文件IO

2.文件与目录

3.进程

4.多线程编程

5.信号

6.进程间通信

学习linux编程,首先要学会使用shell,这里一些基础命令就不介绍了。这里唯一要提的一个shell命令就是man。man是任何一个开发者都应该学会经常使用的工具,使用man比去查看任何一本教材都要来的快速准确。man可以查看一下内容:

1.一般命令(shell命令)
2.系统调用(open
write等直接陷入内核的函数)
3.子函数(C函数库等不直接陷入内核的函数)
4.特殊文件(/dev/zero等linux系统中有特殊用途的文件)
5.文件格式(linux系统的配置文件格式
host.conf)
6.游戏
7.宏和地方传统定义(本地配置)
8.维护命令(tcpdump等用来观察linux系统运行情况的命令)

IO分为有缓冲IO和无缓冲IO两种,具体的区别可以见下图。不带缓冲的I/O,直接调用系统调用,速度快,如函数open(), read(),
write()等。而带缓冲的I/O,在系统调用前采用一定的策略,速度慢,比不带缓冲的I/O安全,如fopen(), fread() fwrite()等。

      

下面介绍文件IO中的基础函数。

1.open函数

open函数:调用它可以打开或者创建一个文件。

#include <fcntl.h>

int open(const char *pathname, int flags)

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

如果失败,返回值为-1
参数解析: pathname是要打开或者创建的文件名。flags  文件打开时候的选项,
O_RDONLY以只读方式打开文件。O_WRONLY以只写方式打开文件。 O_RDWR以读、写方式打开文件。
这三个选项是必选的!

flags
可选选项:
O_APPEND 以追加方式打开文件,每次写时都写在文件末尾。
O_CREAT   
如果文件不存在,则创建一个,存在则打开它。
O_EXCL      与O_CREAT一起使用时,如果文件已经存在则返回出错。
O_TRUNC  
以只写或读写方式打开时,把文件截断为0
O_DSYNC   每次write时,等待数据写到磁盘上。
O_RSYNC   
每次读时,等待相同部分先写到磁盘上。
O_SYNC     
每次write时,等到数据写到磁盘上并接更新文件属性。
SYNC选项都会影响降低性能,有时候也取决于文件系统的实现。

mode 
只有创建文件时才使用此参数,指定文件的访问权限。模式有:
   S_IRWX[UGO]    可读 可写 可执行
   S_IR[USR GRP
OTH]   可读
   S_IW[USR GRP OTH]   可写
   S_IX[USR GRP OTH]    可执行
  
S_ISUID   设置用户ID
   S_ISGID   设置组ID

U->user
G->group  O->others

2.creat函数

creat 
以只写方式创建一个文件,若文件已经存在,则把它截断为0

#include <fcntl.h>

int creat(const char *pathname, mode_t mode)

参数解析:
pathname  要创建的文件名称mode   跟open的第三个参数相同,可读,可写,可执行 。如果失败
,返回值为-1
creat函数等同于  open (pathname, O_WRONLY | O_CREAT | O_TRUNC, mode)

3.close函数

close
关闭已经打开的文件,并释放文件描述符

#include <unistd.h>

int close(int filedes)

参数解析:filedes 文件描述符,有open或者creat返回的非负整数。

如果失败,返回值为-1
当一个进程结束时,操作系统会自动释放该进程打开的所有文件。但还是推荐用close来关闭文件。
lsof命令可以查看进程打开了那些文件。

4.lseek函数

lseek
用来定位当前文件偏移量,既你对文件操作从文件的那一部分开始。

#include <unistd.h>

off_t lseek(int filedes, off_t offset, int whence);

如果失败,返回值为-1,成功返回移动后的文件偏移量。
参数解析:filedes 文件描述符。offset
必须与whence一同解析
    whence为   SEEK_SET, 则offset从文件的开头算起。
    whence为  
SEEK_CUR, 则offset从当前位置算起,既新偏移量为当前偏移量加上offset
    whence为   SEEK_END,
则offset从文件末尾算起。
可以通过lseek、write来快速创建一个大文件。

5.read函数

read
从当前文件偏移量处读入指定大小的文件内容

#include <unistd.h>

ssize_t read(int filedes, void *buf, size_t nbytes)

失败返回-1, 成功返回读入的字节数,到文件末尾返回0
参数解析 filedes 文件描述符 ,有open返回。buf 
读入文件内容存放的内存首地址。nbytes
要读取的字节数。
实际读入的字节数可能会小于要求读入的字节数。比如文件只有所剩的字节数小于你要读入的字节数,读取fifo文件和网络套接字时都可能出现这种情况。

6.write函数

write向一个文件写入一定字节的内容。

#include <unistd.h>

ssize_t write(int filedes, const void * buff, size_t nbytes)

失败返回-1,成功返回实际写入的字节数。当磁盘满或者文件到达上限时可能写入失败。
一般从当前文件偏移量出写入,但如果打开时使用了O_APPEND,那么无论当前文件偏移量在哪里,都会移动到文件末尾写入。

以上都是文件IO最基本的几个函数,那么linux的IO是怎么实现的呢?内核使用了三种数据结构,来实现I/O 
    1.
每个进程在进程表中都有一个记录项,每个记录项中有一张打开文件描述符表,可将其视为一个矢量,每个描述符占用一项。与每个 文 
件描述符相关联的是:
         (a) 文件描述符标志。
         (b) 指向一个文件表项的指针。
    2.
内核为所有打开文件维持一张文件表。每个文件表项包含:
          (a) 文件状态标志(读、写、增写、同步等)。
          (b)
当前文件位移量。
          (c) 指向该文件v节点表项的指针。
    3.
每个打开文件(或设备)都有一个v节点结构。v节点包含了文件类型和对此文件进行各种操作的函数的指针信息。对于大多数文件,
v节点还包含了该文件的i节点(索引节点)。例如, i节点包含了文件的所有者、文件长度、文件所在的设备、指向文件在盘上所使用的实际数据块的指针等等

如下图所示,内核中的数据结构

两个文件各自打开同一个文件,它们拥有各自的文件表项,但共享v节点表。见下图所示

什么是原子操作?

A B两个进程以O_APPEND方式打开同一个文件。A
进程去写该文件,假设此时文件偏移量为1000,B进程同时去写该文件,此时由于A进程未写完,则B进程得到的文件偏移量仍为1000。最后B进程的内容可能会覆盖掉A进程写的内容。pread
, pwrite是原子读写操作。相当于先把文件偏移量定位到offset,然后在进行读写。这都是一步完成,不存在竞争问题。

#include <unistd.h>

ssize_t pread(int filedes, void *buf, size_t nbytes, off_t offset)

ssize_t pwrite(int filedes, const void *buf, size_t nbytes, off_t offset)

返回值跟read和write一样。offset为文件偏移量。

下面介绍一些文件IO中比较高级的函数。dup(),fcntl(),sync()等。

1.dup函数

dup/dup2用来复制一个已经存在的文件描述

#include <unistd.h>

int dup(int filedes) ;

int dup2(int filedes, int filedes2) ;

失败返回-1,成功返回新文件描述符。filedes2是新文件描述符,如果已经打开则先关闭它。
ssize_t pread(int
filedes, void *buf, size_t nbytes, off_t offset);
共享文件表项。

2.fcntl函数

fcntl
可以改变已经打开的描述符。

#include <unistd.h>

#include <fcntl.h>

int fcntl(int fd, int cmd)

int fcntl(int fd, int cmd, long arg)

参数解析:
       第一个为已经打开的文件描述符
       第二个为要对文件描述采取的动作 
      
F_DUPFD   复制一个文件描述,返回值为新描述符。
       F_GETFD/F_SETFD  
目前只有FD_CLOEXEC一个,set时候会用到第三个参数。 
       F_GETFL / F_SETFL 
得到或者设置目前的文件描述符属性,返回值为当前属性。设置时使用第三个参数。

3.sync函数

#include <unistd.h>

int fsync(int filedes) //把指定文件的数据和属性写入到磁盘。

int fdatasync(int filedes) //把指定文件的数据部分写到磁盘。

void sync(void) //把修改部分排入磁盘写队列,但并不意味着已经写入磁盘。

最后些一个测试程序,希望可以用到里面大多数函数,用于测试其功能。这个程序功能是打开一个文件,在里面写入hello
world,然后调用dup函数复制一个文件描述符,随后调用lseek将偏移量设置到hello之后,最后读出文件内容world打印到终端显示。代码如下所示

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <fcntl.h>

#include <string.h>

int main(void)

{

int fd, fdd, ret;

char str[]="hello world!";

char buf[10];

fd = open("file", O_RDWR|O_CREAT|O_TRUNC, 755);

if(fd < 0){

perror("open error");

exit(1);

}

ret = write(fd, str, sizeof(str));

if(ret != sizeof(str)){

perror("write error");

exit(1);

}

fdd = dup(fd);

if(ret == -1){

perror("dup error");

exit(1);

}

lseek(fdd, 6, SEEK_SET);

memset(buf,0,sizeof(buf));

ret = read(fdd, buf, sizeof(buf));

if(ret < 0){

perror("read error");

exit(1);

}

printf("%s/n",buf);

return 0;

}

Unix环境编程之文件IO的更多相关文章

  1. 高级UNIX环境编程5 标准IO库

    标准IO库都围绕流进进行的 <stdio.h><wchar.h> memccpy 一般用汇编写的 ftell/fseek/ftello/fseeko/fgetpos/fsetp ...

  2. UNIX系统编程:文件IO(I)

    1.标准C库中访问文件用的是文件指针FILE *(stdin,stdout,stderr):对于linux系统编程而言,所有对设备或文件的操作都是通过文件描述符进行的 2.当打开或者创建一个文件的时候 ...

  3. 高级UNIX环境编程4 文件和目录

    #include<sys/stat.h> stat fstat lstat fchmod 对已打开的文件操作

  4. 高级UNIX环境编程3 FILE IO

    POSIX中,STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO 对应0,1,2 每个打开的文件都有一个与其想关联的 "current file offset& ...

  5. UNIX环境编程学习——反思认识

     学习情况: 有关UNIX系统环境编程的学习时间用来非常长的时间.可是感觉效果还是不是太好,在中间经过了期末考试.用来非常长的时间用来学习专业课.就将该过程的学习放到了一边上,放假以后又回家造成了 ...

  6. Unix环境高级编程:文件 IO 原子性 与 状态 共享

    参考 UnixUnix环境高级编程 第三章 文件IO 偏移共享 单进程单文件描述符 在只有一个进程时,打开一个文件,对该文件描述符进行写入操作后,后续的写入操作会在原来偏移的基础上进行,这样就可以实现 ...

  7. UNIX环境编程学习笔记(2)——文件I/O之不带缓冲的 I/O

    lienhua342014-08-25 1 文件描述符 对于内核而言,所有打开的文件都通过文件描述符引用.文件描述符是一个非负整数.当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符. ...

  8. Unix环境编程基础下

    Unix出错处理 当UNIX系统的函数出错时,通常会返回一个负值.我们判断函数的返回值小于0表示出错了,注意我们并不知道为什么出错.例如我们open一个文件,返回值-1表示打开失败,但是为什么打开失败 ...

  9. UNIX,基础知识,文件IO,文件和目录

    2015.1.27星期二,早晨阴天,中午下雪了今天上午老师不上课,程序语句,记一下:main(void){ int c; while((c = getc(stdin)) != EOF) if(putc ...

随机推荐

  1. VueJS绑定缩写:可省略v-on、v-bind

    v-bind 缩写 Vue.js 为两个最为常用的指令提供了特别的缩写: <!-- 完整语法 --> <a v-bind:href="url"></a ...

  2. Android利用reative_layout生成梅花界面

    XML代码: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:and ...

  3. HTML5 2D平台游戏开发#4状态机

    在实现了<HTML5 2D平台游戏开发——角色动作篇之冲刺>之后,我发现随着角色动作的增加,代码中的逻辑判断越来越多,铺天盖地的if() else()语句实在让我捉襟见肘: 这还仅仅是角色 ...

  4. 在一个JS文件中引用另一个JS文件

    方法一,在调用文件的顶部加入下例代码: document.write(”<script language=javascript src=’/js/import.js’></scrip ...

  5. Eclipse工程前面有个红色的感叹号的解决办法

    今天从SVN下载下工程之后,编译完,发现有两个工程有个红色的感叹号,一直没找到什么原因,问百度老师,发现问题的解决办法了. 1.先在控制台上点击Problems 如果控制台没有Problems,点击工 ...

  6. Win7获取管理权限修改Host文件以其他权限问题

    ——win7管理员权限修改Host文件——百度经验 win7管理员权限获取办法: win7管理员权限 获取办法——经验——百度 win7最高权限获取: win7最高权限 获取——百度经验

  7. easyUI中 datagrid 格式化日期

    $('#List').datagrid({ url: '@Url.Action("GetList")', width:SetGridWidthSub(10), methord: ' ...

  8. java 单例模式(转载)

    http://www.cnblogs.com/whgw/archive/2011/10/05/2199535.html Java中单例模式是一种常见的设计模式,可分为三种:懒汉式单例.饿汉式单例.登记 ...

  9. sql 时间转换格式

    convert(varchar(10),字段名,转换格式) CONVERT(nvarchar(10),count_time,121)CONVERT为日期转换函数,一般就是在时间类型(datetime, ...

  10. Objective-C 内存管理之dealloc方法中变量释放处理

    本文转载至 http://blog.sina.com.cn/s/blog_a843a8850101ds8j.html   (一).关于nil http://cocoadevcentral.com/d/ ...