I/O 编程技术

前言

IO是计算机中的输入/输出(Input/Output)的简称,指的是计算机系统外部设备之间进行数据交换的过程。输入是指将外部数据传输到计算机系统中,输出是指将计算机系统中的数据传输到外部设备中。

在计算机中,输入可以来自多种来源,如键盘、鼠标、触摸屏、传感器等。输出可以发送到显示器、打印机、扬声器、存储设备等。

IO操作是计算机系统中的重要组成部分,它使计算机能够与用户交互,接收用户的输入,并将计算结果输出给用户。通过IO操作,计算机可以读取外部数据、存储数据、显示信息、传输数据等。
(原文链接:https://blog.youkuaiyun.com/m0_56844552/article/details/130856985)

文件IO和标准IO

区别:

目标:标准IO操作是与标准输入(stdin)、标准输出(stdout)和标准错误(stderr)相关联,涉及与终端或控制台的交互。文件IO操作是与文件相关联,涉及对文件的读取和写入。
设备关联:标准IO操作与终端或控制台设备关联,允许与用户进行交互。文件IO操作与文件相关联,允许对文件进行读写操作。
接口:标准IO操作使用标准IO函数,如printf()和scanf(),这些函数提供了简单的接口和格式化功能。文件IO操作使用文件IO函数,如open()和close(),这些函数提供了文件的打开、读写和关闭功能。


相同点:

输入输出:标准IO文件IO都是用于处理输入和输出的操作方式。它们都提供了读取输入数据和写入输出数据的功能。
函数库:标准IO文件IO都是由编程语言提供的函数库来支持。它们提供了一组函数和方法,用于处理输入输出操作。??
数据传输:无论是标准IO还是文件IO,都涉及数据在不同设备或存储介质之间的传输。标准IO通过终端设备与用户进行交互,文件IO通过文件进行数据的读写操作。

文件IO和标准IO的概念

  •         文件I/O 

什么是文件IO?

posix(可移植操作系统接口)定义的一组函数

不提供缓冲机制, 每次读写操作都引起系统调用

没有流指针不能用刷新流和定位流的函数        核心概念是文件描述符

访问各种类型文件        Linux下, 标准IO基于文件IO实现

文件I/O是操作系统封装了一系列open、close、write、read等API函数构成的一套用来读、写文件的接口供应用程序使用,通过这些接口可以实现对文件的读写操作,但是效率并不是最高的。

文件I/O是采用系统直接调用的方式,因此当使用这些接口对文件进行操作时,就会立刻触发系统调用过程,即向系统内核发出请求之后,系统内核会收到执行相关代码处理的请求,决定是否将操作硬件资源或返回结果给应用程序。

  •           标准I/O

标准IO:应用层C语言库函数提供了一些用来做文件读写的函数列表,叫标准IO。标准IO有一系列的C库函数构成(fopen,fclose,fwrite,fread),这些标准IO函数其实是由文件IO封装而来的(fopen内部还是调用了open);,我们通过fwrite写入的内容不是直接进入内核中的buf,而是先进入应用层标准IO库自己维护的buf中,然后标准IO库自己根据操作系统单次write的最佳count来选择好的时机来完成write到内核中的buf中。因此,标准I/O封装了底层系统调用更多的调用函数接口。

文件IO和标准IO的本质区别

  • **缓冲区:**标准I/O函数接口在对文件进行操作时,首先操作缓存区,等待缓存区满足一定的条件时,然后再去执行系统调用,真正实现对文件的操作。 而文件I/O不操作任何缓存区,直接执行系统调用。

  • **系统开销:**使用标准I/O可以减少系统调用的次数,提高系统效率。例如,将数据写入文件中,每次写入一个字符。采用文件I/O的函数接口,每调用一次函数写入字符就会产生一次系统调用。而执行系统调用时,Linux必须从用户态切换到内核态,处理相应的请求,然后再返回到用户态,如果频繁地执行系统调用会增加系统的开销。

  • **执行效率:**采用标准I/O的函数接口,每调用一次函数写入字符,并不着急将字符写入文件,而是放到缓存区保存,之后每一次写入字符都放到缓存区保存。直到缓存区满足刷新的条件(如写满)时,再一并将缓存区中的数据写入文件,执行一次系统调用完成此过程,这样便很大程度地减少了系统的调用次数,提高了执行效率。

文件IO 

文件IO,又称系统IO系统调用。是操作系统提供的API接口函数
POSIX(可移植操作系统接口)定义的一组函数
文件IO不提供缓冲机制
标准IO和文件IO不能混用

文件描述符    

  • 每个打开的文件都对应着一个文件描述符
  • 文件描述符是一个非负整数,linux为每一个打开的文件分配一个文件描述符
  • 文件描述符从0开始分配,依次递增
  • 文件IO操作通过文件描述符来完成
  • fd(fail descriptor)
  • 0-1023,表示文件
  • 0,1,2的含义 标准输入、标准数出、标准错误

 0,1,2的含义?

0标准输入 1标准输出 2标准错误

打开的磁盘文件从3开始

 open函数

open函数用来创建或打开一个文件

#include <fcntl.h>
int open(const char *pathname, int flags); 不创建文件
int open(const char *pathname, int flags, mode_t mode); 创建文件,不能创建设备文件
  • 成功时返回文件描述符;出错时返回EOF
  • 打开文件时使用两个参数
  • 创建文件时第三个参数指定新文件的权限,(只有在建立新文件时有效)此外真正建文件时的权限会受到umask 值影响,实际权限是mode-umaks(umaks普通用户为0002)
  • 可以打开设备文件,但是不能创建设备文件(创建设备mknode 属于驱动部分)

 标准IO和文件IO的模式对应关系

注意:

  • umask :用来设定文件或目录的初始权限
  • 文件和目录的真正初始权限
  • 文件或目录的初始权限 = 文件或目录的最大默认权限 - umask权限

示例1:

以只写方式打开文件1.txt。如果文件不存在则创建,如果文件存在则清空: 

int fd;

if ((fd = open(“1.txt”, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) {
  perror(“open”);
  return -1;
}

 示例2:

以读写方式打开文件1.txt。如果文件不存在则创建,如果文件存在则报错:

int fd;

if ((fd = open(“1.txt”, O_RDWR|O_CREAT|O_EXCL, 0666)) < 0) {
  if (errno == EEXIST) { 
    perror(“exist error”);
  } else {
    perror(“other error”);
  }
}

 close函数

close函数用来关闭一个打开的文件

#include <unistd.h>
int close(int fd);
  • 成功时返回0;出错时返回EOF
  • 程序结束时自动关闭所有打开的文件
  • 文件关闭后,文件描述符不再代表文件

 read函数

read函数用来从文件中读取数据 

 #include <unistd.h>
 ssize_t read(int fd, void *buf, size_t count);
  • 成功时返回实际读取的字节数;出错时返回EOF
  • 读到文件末尾时返回0
  • fd是读取的文件
  • buf是接收数据的缓冲区
  • count是读取的长度,不应超过buf大小

示例: 

从指定的文件(文本文件)中读取内容并统计大小 

int main(int argc, char *argv[]) {
{
  int fd, n, total = 0;
  char buf[64];
  if (argc < 2) {
    printf(“Usage : %s <file>\n”, argv[0]); return -1;
  }
  if ((fd = open(argv[1], O_RDONLY)) < 0) {
      perror(“open”); return -1;
  }
  while ((n = read(fd, buf, 64)) > 0) {
    total += n;
}

 write函数

write函数用来向文件写入数据

 #include <unistd.h>
 ssize_t write(int fd, void *buf, size_t count);
  • 成功时返回实际写入的字节数;出错时返回EOF
  • buf是发送数据的缓冲区
  • count不应超过buf大小

示例:

将键盘输入的内容写入文件,直到输入quit 

  int fd;
  char buf[20];

  if ((fd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) {
      perror(“open”); return -1;
  }

  while (fgets(buf, 20, stdin) != NULL) {
    if (strcmp(buf, “quit\n”) == 0) break;
    write(fd, buf, strlen(buf));
  }

 lseek函数(用来定位文件)

#include <unistd.h>
off_t lseek(int fd, off_t offset, intt whence);
  • 成功时返回当前的文件读写位置;出错时返回EOF

  • 参数offset和参数whence同标准IO的fseek完全一样

  • whence参数:SEEK_SET/SEEK_CUR/SEEK_END

SEEK_SET:从距文件开头 offset 位移量为新的读写位置

SEEK_CUR:以目前的读写位置往后增加 offset 个位移量

SEEK_END:将读写位置指向文件尾后再增加 offset 个位移量

  • offset参数:偏移量,可正可负

练习题 

题目

使用文件IO实现“每隔1秒向文件1.txt写入当前系统时间,行号递增”

代码 

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

int main(int argc,char *argv[]){
     int fp,ret;
     time_t ctime;
     struct tm *ctimestr;
     int linecount = 0; 
     char buf[32];
     fp=open("1.txt",O_RDWR | O_CREAT | O_APPEND, 0664);
     if(fp < 0){
         perror("fopen");
         return 0;

 }
 //calculate test.txt  line    

 while((ret = read(fp,buf,22)) != 0){  //22为每行的字符数
           linecount++;
      }

 while(1){
     ctime = time(NULL);
     //printf("ctime=%d\n",(int)ctime);
     ctimestr = localtime(&ctime);
     printf("%04d-%02d-%02d %02d:%02d:%02d\n",ctimestr->tm_year+1900,ctimestr->tm_mon+1,ctimestr->tm_mday,
                                 ctimestr->tm_hour,ctimestr->tm_min,ctimestr->tm_sec);
     sprintf(buf,"%d,%04d-%02d-%02d %02d:%02d:%02d\n",linecount,ctimestr->tm_year+1900,ctimestr->tm_mon+1,ctimestr->tm_mday,
                                 ctimestr->tm_hour,ctimestr->tm_min,ctimestr->tm_sec);
 if ((ret = write(fp,buf,strlen(buf))) < 0){
 	perror("write");
	close(fp);
 }
     //fflush(fp);
     linecount++;
     sleep(1);
 }

 close(fp);
}

->tm_mday,
ctimestr->tm_hour,ctimestr->tm_min,ctimestr->tm_sec);
if ((ret = write(fp,buf,strlen(buf))) < 0){
perror(“write”);
close(fp);
}
//fflush(fp);
linecount++;
sleep(1);
}

close(fp);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值