Linux系统编程:简单文件IO操作
使用Linux的文件API,经常看见一个东西,叫做文件描述符.
什么是文件描述符?
(1)文件描述符其实实质是一个数字,这个数字在一个进程中表示一个特定的含义,当我们open打开一个文件时,操作系统在内存中构建了一些数据结构来表示这个动态文件,然后返回给应用程序一个数字作为文件描述符,这个数字就和我们内存中维护这个动态文件的这些数据结构挂钩绑定上了,以后我们应用程序如果要操作这一个动态文件,只需要用这个文件描述符进行区分。
(2)文件描述符就是用来区分一个程序打开的多个文件的。
(3)文件描述符的作用域就是当前进程,出了当前进程这个文件描述符就没有意义了
(4)文件描述符fd的合法范围是0或者一个正数,不可能是一个负数
(5)open返回的fd必须记录好,以后向这个文件的所有操作都要靠这个fd去对应这个文件,最后关闭文件时也需要fd去指定关闭这个文件。如果在我们关闭文件前fd丢了,那么这个文件就没法关闭了也没法读写了
1)打开与读取文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h> int main(int argc, char const *argv[]) { int fd = -; //文件描述符 //打开文件
fd = open( "ghostwu.txt", O_RDWR ); if ( - == fd ) {
printf("文件打开失败\n");
}else {
printf("文件打开成功,fd=%d\n", fd );
} //读取文件
int count = ;
char buf[];
count = read( fd, buf, );
if ( - == count ) {
printf("文件读取失败\n");
}else {
printf("文件读取成功,实际读取的字节数目为:%d\n内容为%s\n", count, buf );
} //关闭文件
close( fd ); return ;
}
需要在当前目录下存在ghostwu.txt这个文件,否则打开的时候失败,这里涉及2个api
int open(const char *pathname, int flags);
open非常简单,第一个参数就是文件路径, 第二个是文件模式,在man手册中还提供了其他几种方式。
ssize_t read(int fd, void *buf, size_t count);
第一个参数为文件描述符,就是open返回的那个值
第二个参数buf用来存储从文件中读取的内容
第三个参数,表示希望从文件中读取的内容( 注:这个count数字可以随便给,最终以返回的实际数目(read的返回值)为准
2)打开与写入文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h> int main(int argc, char const *argv[]) { int fd = -; //文件描述符 //打开文件
fd = open( "ghostwu.txt", O_RDWR ); if ( - == fd ) {
printf("文件打开失败\n");
}else {
printf("文件打开成功,fd=%d\n", fd );
} //写文件
char buf[] = "I love Linux, Linux is very very good!!!";
int count = ;
count = write( fd, buf, strlen( buf ) );
if ( - == count ) {
printf("文件写入失败\n");
}else {
printf("文件写入成功,实际写入的字节数目为:%d\n", count);
} //关闭文件
close( fd ); return ;
}
ssize_t write(int fd, const void *buf, size_t count);
第一个参数为文件描述符,就是open返回的那个值
第二个参数buf用来存储写入的内容
第三个参数,表示希望写入的文件大小
3)open的一些flag参数
1,只读与只写权限
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h> int main(int argc, char const *argv[]) { int fd = -; //文件描述符 //打开文件, O_RDONLY:只读权限,打开之后的文件只能读取,不能写入
//打开文件, O_WRONLY:只写权限,打开之后的文件只能写入,不能读取
// fd = open( "ghostwu.txt", O_RDONLY );
fd = open( "ghostwu.txt", O_WRONLY ); if ( - == fd ) {
printf("文件打开失败\n");
}else {
printf("文件打开成功,fd=%d\n", fd );
} //读取文件
int count = ;
char buf[];
count = read( fd, buf, );
if ( - == count ) {
printf("文件读取失败\n");
}else {
printf("文件读取成功,实际读取的字节数目为:%d\n内容为%s\n", count, buf );
} //关闭文件
close( fd ); return ;
}
2,清空与追加
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h> int main(int argc, char const *argv[]) { int fd = -; //文件描述符 //打开文件
//在O_RDWR模式下,对于一个已经存在的文件,且有内容,那么写入文件会覆盖对应大小的源文件内容【不是完全覆盖】
// fd = open( "ghostwu.txt", O_RDWR );
//在具有写入权限的文件中,使用O_TRUNC 会先把原来的内容清除,再写入新的内容
// fd = open( "ghostwu.txt", O_RDWR | O_TRUNC );
//在具有写入权限的文件中,使用O_APPEND 会把新内容追加到原来内容的后面
// fd = open( "ghostwu.txt", O_RDWR | O_APPEND ); //在具有写入权限的文件中,使用O_APPEND和O_TRUNC O_TRUNC起作用,会把原来的内容清除,再写入新的内容
fd = open( "ghostwu.txt", O_RDWR | O_APPEND | O_TRUNC ); if ( - == fd ) {
printf("文件打开失败\n");
return -;
}else {
printf("文件打开成功,fd=%d\n", fd );
} //写文件
char buf[] = "new content";
int count = ;
count = write( fd, buf, strlen( buf ) );
if ( - == count ) {
printf("文件写入失败\n");
return -;
}else {
printf("文件写入成功,实际写入的字节数目为:%d\n", count);
} //关闭文件
close( fd ); return ;
}
3,文件存在已否,创建文件与设置权限
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h> int main(int argc, char const *argv[]) { int fd = -; // fd = open( "ghostwu.txt", O_RDWR | O_CREAT | O_EXCL ); /*
文件不存在:
创建这个文件 并打开成功
文件存在:
再次运行时(文件已经创建成功,存在了), 这时打开失败
*/
// fd = open( "ghostwu.txt", O_RDWR | O_CREAT ); fd = open( "ghostwu.txt", O_RDWR | O_CREAT | O_EXCL, ); if( - == fd ) {
printf("文件打开失败,错误号:%d\n", errno );
perror( "open" );
return -;
}else {
printf("文件打开成功\n");
} close( fd ); return ;
}
上面用到了一个函数perror,errno和perror:
1)errno就是error number,意思就是错误号码。linux系统中对各种常见错误做了个编号,当函数执行错误时,函数会返回一个特定的errno编号来告诉我们这个函数到底哪里错了
2)errno是由操作系统来维护的一个全局变量,操作系统内部函数都可以通过设置errno来告诉上层调用者究竟刚才发生了一个什么错误
3)errno本身实质是一个int类型的数字,每个数字编号对应一种错误。当我们只看errno时只能得到一个错误编号数字,并不知道具体错在哪里,所以:linux系统提供了一个函数perror(意思print error),perror函数内部会读取errno并且将这个不好认的数字直接给转成对应的错误信息字符串,然后打印出来
4,lseek用来移动文件内部指针
简单应用:统计文件大小
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h> int main(int argc, char const *argv[]) { if ( argc != ) {
printf("usage:%s %s\n", argv[], "filename");
return -;
} int fd = -; fd = open( argv[], O_RDWR ); if( - == fd ) {
printf("文件打开失败,错误号:%d\n", errno );
perror( "open" );
return -;
}else {
printf("文件打开成功\n");
} //把指针移动到文件末尾,就是文件的大小
int count = lseek( fd, , SEEK_END ); printf("文件大小为%d\n", count); close( fd );
return ;
}
------------------------------------------分割线------------------------------------------
一、同一个进程,多次打开同一个文件,然后读出内容的结果是: 分别读【我们使用open两次打开同一个文件时,fd1和fd2所对应的文件指针是不同的2个独立的指针】
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h> int main(int argc, char const *argv[]) { int fd1 = -;
int fd2 = -;
char buf1[] = {};
char buf2[] = {};
int count1 = ;
int count2 = ; fd1 = open( "ghostwu.txt", O_RDWR ); if ( - == fd1 ) {
printf("文件打开失败\n");
perror( "open" );
return -;
}else {
printf("文件打开成功,fd1=%d\n", fd1);
} count1 = read( fd1, buf1, );
if ( - == count1 ) {
printf( "文件读取失败\n" );
perror( "read" );
}else {
printf( "文件读取成功,读取的内容是%s\n", buf1 );
} fd2 = open( "ghostwu.txt", O_RDWR ); if ( - == fd1 ) {
printf("文件打开失败\n");
perror( "open" );
return -;
}else {
printf("文件打开成功,fd2=%d\n", fd1);
} count2 = read( fd2, buf2, );
if ( - == count2 ) {
printf( "文件读取失败\n" );
perror( "read" );
}else {
printf( "文件读取成功,读取的内容是%s\n", buf2 );
} close( fd1 );
close( fd2 ); return ;
}
二、同一个进程,多次打开同一个文件,然后写入内容的结果是: 分别写,当使用O_APPEND,就是接着写
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h> int main(int argc, char const *argv[]) { int fd1 = -;
int fd2 = -;
char buf1[] = "ghost";
char buf2[] = "wu";
int count1 = ;
int count2 = ; fd1 = open( "ghostwu.txt", O_RDWR ); if ( - == fd1 ) {
printf("文件打开失败\n");
perror( "open" );
return -;
}else {
printf("文件打开成功,fd1=%d\n", fd1);
} count1 = write( fd1, buf1, strlen( buf1 ) );
if ( - == count1 ) {
printf( "文件写入失败\n" );
perror( "write" );
}else {
printf( "文件写入成功,写入的内容是%s\n", buf1 );
} fd2 = open( "ghostwu.txt", O_RDWR ); if ( - == fd1 ) {
printf("文件打开失败\n");
perror( "open" );
return -;
}else {
printf("文件打开成功,fd2=%d\n", fd1);
} count2 = write( fd2, buf2, strlen( buf2 ) );
if ( - == count2 ) {
printf( "文件写入失败\n" );
perror( "write" );
}else {
printf( "文件写入成功,写入的内容是%s\n", buf2 );
} close( fd1 );
close( fd2 ); return ;
}
上面代码保持不变,再写入的时候加入flag标志:
fd1 = open( "ghostwu.txt", O_RDWR | O_APPEND );
fd2 = open( "ghostwu.txt", O_RDWR | O_APPEND );
三、 dup后的fd和原来打开文件的fd指向的是同一个文件,同时对这个文件写入时,是接着写
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h> int main(int argc, char const *argv[]) { int fd1 = -;
int fd2 = -; fd1 = open( "ghostwu.txt", O_RDWR ); if ( - == fd1 ) {
perror( "open" );
return -;
}else {
printf("文件打开成功:fd=%d\n", fd1);
} //dup后的文件,同时write 是接着写入
fd2 = dup( fd1 );
printf("文件dup成功:fd=%d\n", fd2); //分别向fd1和fd2指向的文件写入 char buf1[] = "ghost";
char buf2[] = "wu"; int count1 = -, count2 = -; while ( ) {
count1 = write( fd1, buf1, strlen( buf1 ) );
if ( - == count1 ) {
perror( "buf1->write" );
return -;
}else {
printf("buf1->文件写入成功\n");
} sleep( ); count2 = write( fd2, buf2, strlen( buf2 ) );
if ( - == count2 ) {
perror( "buf2->write" );
return -;
}else {
printf("buf2->文件写入成功\n");
}
} close( fd1 );
close( fd2 );
return ;
}
在linux系统中,内核占用了0、1、2这三个fd,当我们运行一个程序得到一个进程时,内部就默认已经打开了3个文件,
对应的fd就是0、1、2。分别叫stdin、stdout、stderr。也就是标准输入、标准输出、标准错误。接下来,我们把标准输出关闭,printf就不会输出,如果用dup复制原来的fd,那么新dup出来的fd就是1(对应标准输出)
之后标准输出的内容都会被写入到原来fd对应的那个文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h> int main(int argc, char const *argv[]) { int fd = -; fd = open( "ghostwu2.txt", O_RDWR );
if ( - == fd ) {
perror( "open" );
return -;
}else {
printf( "文件打开成功fd=%d\n", fd );
} //fd=0 对应stdin fd=1 对应 stdout fd=2 对应stderror
close( ); //关闭fd=1的标准输出之后,printf输出看不见 int newFd = -; newFd = dup( fd ); //newFd一定是1, 因为分配后的fd从最小的没被占用的开始
char buf[];
sprintf( buf, "%d", newFd ); //newFd转字符串型
printf( "这是一段输出,由于newFd和fd关联到标准输出(newFd=1),会被写入到文件\n" );
write( fd, buf, ); return ;
}
Linux系统编程:简单文件IO操作的更多相关文章
- 【Linux 应用编程】文件IO操作 - 常用函数
Linux 系统中的各种输入输出,设计为"一切皆文件".各种各样的IO统一用文件形式访问. 文件类型及基本操作 Linux 系统的大部分系统资源都以文件形式提供给用户读写.这些文件 ...
- linux系统编程之文件IO
1.打开文件的函数open,第一个参数表示文件路径名,第二个为打开标记,第三个为文件权限 代码: #include <sys/types.h> #include <sys/stat. ...
- Linux系统编程001--系统IO
1. 文件系统:用来存储.组织.管理文件的一套方式.协议 2. 文件 文件的属性:i-node唯一表示一个文件的存在与否 文件的内容 3. Linux系统如何实现文件的操作? 点击查看代码 硬件层: ...
- linux系统编程之文件与io(五)
上一节中已经学习了文件描述符的复制,复制方法有三种,其中最后一种fcntl还并未使用到,关于这个函数,不光只有复制文件描述符的功能,还有其它一些用法,本节就对其进行一一剖析: fcntl常用操作: 这 ...
- linux系统编程之文件与io(一)
经过了漫长的学习,C语言相关的的基础知识算是告一段落了,这也是尝试用写博客的形式来学习c语言,回过头来看,虽说可能写的内容有些比较简单,但是个人感觉是有史起来学习最踏实的一次,因为里面的每个实验都是自 ...
- UNIX系统编程:文件IO(I)
1.标准C库中访问文件用的是文件指针FILE *(stdin,stdout,stderr):对于linux系统编程而言,所有对设备或文件的操作都是通过文件描述符进行的 2.当打开或者创建一个文件的时候 ...
- linux系统编程之文件与IO(一):文件描述符、open,close
什么是IO? 输入/输出是主存和外部设备之间拷贝数据的过程 设备->内存(输入操作) 内存->设备(输出操作) 高级I/O ANSI C提供的标准I/O库称为高级I/O,通常也称为带缓冲的 ...
- Linux系统编程:文件I/O编程
文件I/O操作在Linux编程时是经常会使用到的一个内容,通常可以把比较大的数据写到一个文件中来进行存储或者与其他进程进行数据传输,这样比写到一个全局数组或指针参数来实现还要方便好多. 一.文件常用操 ...
- linux c编程:文件的操作
在Linux系统中,系统是通过inode来获得这个文件的信息.在Linux系统中,inode的信息都是封装在stat这个结构体中.可以通过man 2 stat来查看stat的具体结构.从中可以看到包含 ...
随机推荐
- YiShop_网上商城系统多少钱
电子商务的发展,网上商城系统的开发也变得越来越热门.商城系统开发对于企业来说是非常有必要的,一个好的网上商城系统对于企业来说是非常重要.那么到底网上商城系统多少钱呢?下面YiShop带大家去了解. 网 ...
- 这个接口管理平台 eoLinker 开源版部署指南你一定不想错过
本文主要内容是讲解如何在本地部署eoLinker开源版. 环境要求 1.PHP 5.5+ / PHP7+(推荐) 2.Mysql 5.5+ / Mariadb 5.5+ 3.Nginx(推荐) / A ...
- 运行循环 - RunLoop
1.RunLoop简介 1.1 什么是RunLoop 简单来说就是:运行循环,可以理解成一个死循环,一直在运行. RunLoop实际上就是一个对象,这个对象用来处理程序运行过程中出现的各种事件(触摸. ...
- arguments,caller,callee之理解
arguments对象代表正在执行的函数和调用它的函数的参数,arguments是一个不是数组但类似 数组的对象,它具有同数组一样的访问性质及方式,可以由arguments[n]来访问对应单个参数的值 ...
- android 读取系统文件 wpa_supplicant
1,须要权限 <uses-permission android:name="android.permission.ACCESS_SUPERUSER" /> 2,下载 R ...
- android checkbox 未选中状态 已选中状态 替换成自己的图片
效果图: 未选中状态: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA ...
- VMware 虚拟机 Ubuntu 登录后蓝屏问题
问题起因 在一次下班收工时关闭虚拟机 Ubuntu,出现异常:关机好久没有完成,进而导致 VMware 软件卡死.后来强行杀死 VMware.第二天上班,启动 VMware 后开启 Ubuntu,输入 ...
- linux应用态下的时间
1.时间值 1.1 日历时间(UTC) 该值是自1 9 7 0年1月1日0 0 : 0 0 : 0 0以来国际标准时间( U T C)所经过的秒数累计值(早期的手册称 U T C为格林尼治标准时间) ...
- Anaconda+用conda创建python虚拟环境
Anaconda+用conda创建python虚拟环境 Anaconda与conda区别 conda可以理解为一个工具,也是一个可执行命令,其核心功能是包管理与环境管理.包管理与pip的使用类似,环境 ...
- 数据分析与展示——Pandas数据特征分析
Pandas数据特征分析 数据的排序 将一组数据通过摘要(有损地提取数据特征的过程)的方式,可以获得基本统计(含排序).分布/累计统计.数据特征(相关性.周期性等).数据挖掘(形成知识). .sort ...