文件I/O实践(1) --基础API
什么是I/O
输入/输出是内存和外设之间拷贝数据的过程:
设备->内存: 输入操作
内存->设备: 输出操作
高级I/O: ANSI C提供的标准I/O库函数成为高级I/O, 也称为带缓冲的I/O;
低级I/O: Linux 提供的系统调用, 通常也称为不带缓冲的I/O;
文件描述符
对于Linux内核而言, 所有的文件或设备都对应一个文件描述符(Linux的设计哲学: 一切皆文件), 这样可以简化系统编程的复杂程度;
当打开/创建一个文件的时候, 内核向进程返回一个文件描述符(是一个非负整数). 后续对文件的操作只需通过该文件描述符即可进行, 内核记录有关这个打开文件的信息;
一个进程启动时, 默认已经打开了3个文件, 标准输入(0, STDIN_FILENO), 标准输出(1, STDOUT_FILENO), 标准错误输出(2, STDERR_FILENO), 这些常量定义在unistd.h头文件中;
其中, 文件描述符基本上是与文件描述指针(FILE*)一一对应的, 如文件描述符0,1,2 对应 stdin, stdout, stderr;
文件指针与文件描述符的转换
fileno: 将文件指针转换成文件描述符
int fileno(FILE *stream);
fdopen: 将文件描述符转换成文件指针
FILE *fdopen(int fd, const char *mode);
//示例 int main() { cout << "fileno(stdin) = " << fileno(stdin) << endl; cout << "fileno(stdout) = " << fileno(stdout) << endl; cout << "fileno(stderr) = " << fileno(stderr) << endl; return 0; }
文件I/O API
1.open
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);
参数:
pathname: 文件名, 可以包含[绝对/相对]路径名;
flags: 文件打开模式;
mode: 用来指定对文件所有者, 文件用户组以及系统中的其他用户的访问权限;
注意: newMode = mode & ~umask
flags常用值
//示例1 int main() { int fd = open("test.txt", O_RDONLY); if (fd == -1) { cerr << "file open error, errno = " << errno << "\nstrerror: " << strerror(errno) << endl; perror("perror"); exit(EXIT_FAILURE); } cout << "file open success" << endl; }
//示例2 inline void err_exit(std::string message) { perror(message.c_str()); exit(EXIT_FAILURE); } int main() { umask(0000); int fd = open("test.txt", O_RDWR|O_CREAT|O_EXCL, 0666); if (fd == -1) err_exit("file open error"); else cout << "file descriptor = " << fd << endl; }
[附]
(1). umask API
//改变umask值
mode_t umask(mode_t mask);
(2). ulimit -a
查看系统中的各种限制;
其中-n: 查看一个进程所能够打开的最大文件数
(3). cat /proc/sys/fs/file-max
查看一个系统能够支持的最大打开文件数(该数与内存大小有关)
2.close
#include <unistd.h> int close(int fd);
关闭文件描述符, 使得文件描述符得以重新利用
3.read
ssize_t read(int fd, void *buf, size_t count);
返回值:
错误: -1
到达文件尾: 0
成功: 返回从文件复制到规定缓冲区的字节数
4.wirte
ssize_t write(int fd, const void *buf, size_t count);
返回值:
错误: -1
什么都没做: 0
成功: 返回成功写入文件的字节数
注意:
write返回大于0时, 并不代表buf的内容已经写入到磁盘上的文件中了, 其仅仅代表buf中的数据已经copy到相应的内核缓冲区了. 要实现将缓冲区的内容真正”冲洗”到磁盘上的文件, 需要调用fsync函数;
int fsync(int fd);
其将内核缓冲区中尚未写入磁盘的内容同步到文件系统中;
其实在open调用的时候也可以指定同步选项:O_SYNC O_SYNC The file is opened for synchronous I/O. Any write(2)s on the resulting file descriptor will block the calling process until the data has been physically written to the underlying hardware.
write会等到将buf的内容真正的写入到磁盘才真正返回;
//示例: 带有O_SYNC选项 int main(int argc, char *argv[]) { if (argc < 3) { cerr << "Usage : " << argv[0] << " src dest" << endl; exit(EXIT_FAILURE); } int infd = open(argv[1], O_RDONLY); if (infd == -1) err_exit("file O_RDONLY error"); int outfd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC|O_SYNC, 0666); if (outfd == -1) err_exit("file O_WRONLY error"); char buf[1024]; int readBytes, writeBytes; while ((readBytes = read(infd, buf, sizeof(buf))) > 0) { writeBytes = write(outfd, buf, readBytes); cout << "readBytes = " << readBytes << ", writeBytes = " << writeBytes << endl; } }
文件的随机读写
5.lseek
对应于C库函数中的fseek, 通过指定相对于当前位置, 末尾位置或开始位置的字节数来重定位currp:
off_t lseek(int fd, off_t offset, int whence);
返回值: 新的文件偏移值;
Whence取值:
SEEK_SET
The offset is set to offset bytes.
SEEK_CUR
The offset is set to its current location plus offset bytes.
SEEK_END
The offset is set to the size of the file plus offset bytes.
//示例1 int main(int argc, char *argv[]) { int fd = open("test.txt", O_RDONLY); if (fd == -1) err_exit("open error"); char buf[1024] = {0}; int readBytes = read(fd, buf, 5); cout << "readBytes = " << readBytes << ", buf: " << buf << endl; int seekCount = lseek(fd, 0, SEEK_CUR); cout << "current offset = " << seekCount << endl; }
//示例2: 产生空洞文件 int main(int argc, char *argv[]) { int fd = open("hole.txt", O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0666); if (fd == -1) err_exit("open error"); if (write(fd, "ABCDE", 5) == -1) err_exit("first write error"); //创建一个1G的文件 if (lseek(fd, 1024*1024*1024, SEEK_CUR) == -1) err_exit("lseek error"); if (write(fd, "Hello", 5) == -1) err_exit("second write error"); close(fd); }
[附]
-查看hole.txt文件
od -c hole.txt
cat -A hole.txt
-查看该文件大小
du -h hole.txt
du -b hole.txt
du -k hole.txt
du -m hole.txt
目录访问
6.opendir
#include <sys/types.h> #include <dirent.h> DIR *opendir(const char *name);
返回值:
成功: 返回目录指针;
失败: 返回NULL;
7.readdir
struct dirent *readdir(DIR *dirp);
返回值:
成功: 返回一个指向dirent结构的指针, 它包含指定目录的下一个连接的细节;
没有更多连接时, 返回0;
struct dirent { ino_t d_ino; /* inode number */ off_t d_off; /* not an offset; see NOTES */ unsigned short d_reclen; /* length of this record */ unsigned char d_type; /* type of file; not supported by all filesystem types */ char d_name[256]; /* filename */ };
8.closedir: 关闭目录
int closedir(DIR *dirp);
//示例: 简单的ls程序 int main(int argc, char *argv[]) { if (argc < 2) { cerr << "Usage : " << argv[0] << " <directory>" << endl; exit(EXIT_FAILURE); } DIR *dir = opendir(argv[1]); if (dir == NULL) err_exit("opendir error"); struct dirent *ent; while ((ent = readdir(dir)) != NULL) { //过滤掉隐藏文件 if (ent->d_name[0] == '.') continue; cout << ent->d_name << "\ti-node: " << ent->d_ino << ", length: " << ent->d_reclen << endl; } closedir(dir); }
9.mkdir
int mkdir(const char *pathname, mode_t mode);
10.rmdir: 删除空目录
int rmdir(const char *pathname);
11. Chmod, fchmod更改权限
int chmod(const char *path, mode_t mode); int fchmod(int fd, mode_t mode);
12.chown,fchown更改文件所有者/所属组
int chown(const char *path, uid_t owner, gid_t group); int fchown(int fd, uid_t owner, gid_t group);
文件I/O实践(1) --基础API的更多相关文章
- Linux高性能server编程——Linux网络基础API及应用
Linux网络编程基础API 具体介绍了socket地址意义极其API,在介绍数据读写API部分引入一个有关带外数据发送和接收的程序,最后还介绍了其它一些辅助API. socket地址API 主 ...
- 服务器编程入门(4)Linux网络编程基础API
问题聚焦: 这节介绍的不仅是网络编程的几个API 更重要的是,探讨了Linux网络编程基础API与内核中TCP/IP协议族之间的关系. 这节主要介绍三个方面的内容:套接字( ...
- Linux 高性能服务器编程——Linux网络编程基础API
问题聚焦: 这节介绍的不仅是网络编程的几个API 更重要的是,探讨了Linux网络编程基础API与内核中TCP/IP协议族之间的关系. 这节主要介绍三个方面的内容:套接字(so ...
- Linux网络编程基础API
第5章 Linux网络编程基础API 探讨Linux网络编程基础API与内核中TCP/IP协议族之间的关系,并未后续章节提供编程基础.从3个方面讨论Linux网络API. socket地址API.so ...
- linux高性能服务器编程 (五) --Linux网络编程基础api
第五章 Linux网络编程基础api 1.主机字节序和网络字节序 字节序是指整数在内存中保存的顺序.字节序分为大端字节序.小端字节序. 大端字节序:一个整数的高位字节数据存放在内存的低地址处.低位字节 ...
- vue 单文件组件最佳实践
vue 单文件组件最佳实践 生命周期 template <template> <section> <h1>vue single file components te ...
- sqlservr (708) 打开日志文件 C:\Windows\system32\LogFiles\Sum\Api.log 时出现错误 -1032 (0xfffffbf8)
在windows server 2012 standard上新安装好的SQL Server 2014,查看错误日志,发现此报错 sqlservr (708) 打开日志文件 C:\Windows\sys ...
- Android BLE与终端通信(一)——Android Bluetooth基础API以及简单使用获取本地蓝牙名称地址
Android BLE与终端通信(一)--Android Bluetooth基础API以及简单使用获取本地蓝牙名称地址 Hello,工作需要,也必须开始向BLE方向学习了,公司的核心技术就是BLE终端 ...
- SVG 学习<四> 基础API
目录 SVG 学习<一>基础图形及线段 SVG 学习<二>进阶 SVG世界,视野,视窗 stroke属性 svg分组 SVG 学习<三>渐变 SVG 学习<四 ...
随机推荐
- Gradle 1.12用户指南翻译——第四十九章. Build Dashboard 插件
本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
- Java中的Lock锁
Lock锁介绍: 在java中可以使用 synchronized 来实现多线程下对象的同步访问,为了获得更加灵活使用场景.高效的性能,java还提供了Lock接口及其实现类ReentrantLock和 ...
- Openstack: MP-BIOS bug: 8254 timer not connected to IO-APIC
Issue: After you import an linux image into openstack and run an instance of it, you may find that t ...
- Android开发技巧——大图裁剪
本篇内容是接上篇<Android开发技巧--定制仿微信图片裁剪控件> 的,先简单介绍对上篇所封装的裁剪控件的使用,再详细说明如何使用它进行大图裁剪,包括对旋转图片的裁剪. 裁剪控件的简单使 ...
- DOS界面下的翻译软件制作
准备 素材 依赖 接口 地址 参数 返回值解析 编码及测试 功能代码 运行脚本 环境变量 结果展示 英语转汉语 汉语转英语 总结 昨天看到一篇关于Linux下的桌面词典的文章,于是就想实现一个Wind ...
- Python尾递归-创始人为何不愿TRE以及我们如何模拟TRE
TRE=Tail Recursion Elimination 创始人是不愿意实现TRE的.他专门用了一篇文章来阐述原因. http://neopythonic.blogspot.com/2009/04 ...
- JAVA面向对象-----匿名内部类
匿名内部类 匿名内部类:就是没有类名字的内部类. 匿名内部类作用:简化内部类书写. 匿名内部类的前提:必须继承一个父类或者是实现一个接口. 匿名内部类的格式: new 父类或者接口(){ 执行代码-. ...
- Building System之 get_abs_build_var() && get_build_var()
点击打开链接 1.get_abs_build_var() 和 get_build_var()的实现都在build/envsetup.sh中. 2.在buld目录下grep这两个函数可知:这两个函数只在 ...
- Swift中的as操作符
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交 ...
- 剑指Offer——简述堆和栈的区别
剑指Offer--简述堆和栈的区别 堆(Heap) Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建: Java虚拟机规范描述:所有的对象实例及数组都要在堆上分配: Java堆可以处于物理 ...