文件I/O实践(1) --基础API
2016-09-21 20:50
267 查看
什么是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);
#include <iostream> #include <unistd.h> #include <stdlib.h> #include <stdio.h> using namespace std; //示例 int main() { cout << "fileno(stdin) = " << fileno(stdin) << endl; cout << "fileno(stdout) = " << fileno(stdout) << endl; cout << "fileno(stderr) = " << fileno(stderr) << endl; return 0; }
.PHONY:clean all CC =g++ CFLAGS = -Wall -g BIN=01fileno all:$(BIN) %.o:%.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: rm -f *.o $(BIN)
文件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: 用来指定对文件所有者, 文件用户组以及系统中的其他用户的访问权限;
返回值:
打开成功,返回文件描述符;
打开失败,返回-1
注意: newMode = mode & ~umask
flags常用值
所有这些标志值的符号名称可以通过#inlcude<fcntl.h>访问
//示例1 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <iostream> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> //strerror()函数的头文件 using namespace std; 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; return 0; }
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <iostream> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> using namespace std; #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ }while(0) int main() { int fd = open("test.txt", O_RDONLY); if (fd == -1) { ERR_EXIT("open error"); } cout<<"open succ"<<endl; return 0; }
//示例3 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
查看一个系统能够支持的最大打开文件数(该数与内存大小有关)
(4) errno 是记录系统的最后一次错误代码。代码是一个int型的值,在errno.h中定义
(5) perror(s) 用来将上一个函数发生错误的原因输出到标准设备(stderr)。参数 s 所指的字符串会先打印出,后面再加上错误原因字符串。
头文件 #include<stdio.h> #include<stdlib.h>
(6) strerrpr 通过标准错误的标号,获得错误的描述字符串 ,将单纯的错误标号转为字符串描述,方便用户查找错误。 头文件: #include <string.h>
2.close系统调用
#include <unistd.h> int close(int fd);
关闭文件描述符, 使得文件描述符得以重新利用
参数:
-fd:要关闭的文件的文件描述符
返回值:
如果出现错误,返回-1,调用成功返回0
3.read系统调用
ssize_t read(int fd, void *buf, size_t count);
一旦有了与一个打开文件描述相连的文件描述符,只要该文件是用O_RDONLY或O_RDWR标志打开的,就可以用read()系统调用从该文件中读取字节。
参数:
fd:想要读的文件的文件描述符
buf:指向内存块的指针,从文件中读取来的字节放到这个内存块中
count:从该文件复制到buf中的字节个数
返回值:
错误: -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选项 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <iostream> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> using namespace std; inline void err_exit(std::string message) { perror(message.c_str()); exit(EXIT_FAILURE); } 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; } close(infd); close(outfd); return 0; }
文件的随机读写
5.lseekoff_t lseek(int fd, off_t offset, int whence);
功能:对应于C库函数中的fseek,通过指定相对于开始位置、当前位置或末尾位置的字节数来重定位curp,这取决于lseek()函数中指定的位置。
参数:
fd:需设置的文件标识符
offset:偏移量
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. 从文件的结束出计算偏移
[cpp] view plain copy
print?
//示例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;
}
[cpp] view plain copy
print?
//示例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[cpp] view plain copy
print?
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
返回值:
成功: 返回目录指针;
失败: 返回NULL;
7.readdir
[cpp] view plain copy
print?
struct dirent *readdir(DIR *dirp);
返回值:
成功: 返回一个指向dirent结构的指针, 它包含指定目录的下一个连接的细节;
没有更多连接时, 返回0;
[cpp] view plain copy
print?
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: 关闭目录
[cpp] view plain copy
print?
int closedir(DIR *dirp);
[cpp] view plain copy
print?
//示例: 简单的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
[cpp] view plain copy
print?
int mkdir(const char *pathname, mode_t mode);
功能:
用来创建一个称为pathname的新目录,它的权限设置为mode
10.rmdir: 删除空目录
[cpp] view plain copy
print?
int rmdir(const char *pathname);
11. chmod, fchmod更改权限
[cpp] view plain copy
print?
int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);
参数:
path:文件的路径名
fd:文件描述符
返回值:
成功调用返回0,失败返回-1
12.chown,fchown更改文件所有者/所属组
int chown(const char *path, uid_t owner, gid_t group); int fchown(int fd, uid_t owner, gid_t group);
参数:
path:文件的路径名
owner:所有者识别号
group:用户组识别号
返回值:
调用成功返回0,失败返回-1
相关文章推荐
- 文件I/O实践(1) --基础API
- 文件I/O实践(1) --基础API
- 文件I/O实践(1) --基础API
- 文件I/O实践(1) --基础API
- 【微信公众平台应用开发实践】API详解--基础接口
- 文件I/O实践(1) --基础API
- java线程与并发编程实践----API基础
- java基础之api零碎总结
- RSA算法基础->实践
- 《JPEG2000图像压缩基础、标准和实践》中两处错误
- Castle ActiveRecord学习实践(3):映射基础
- 【WCF实践】编写最基础的公共聊天服务
- api之sql基础
- BlackBerry 应用程序开发者指南 第一卷:基础--第1章 BlackBerry API
- 自动化(Automation)基础概念:二次开发接口(API)与插件(Addin)
- Javascript & DHTML 实例编程(教程)DOM基础和基本API
- QC API 编程实践
- UNIX实验项目二:UNIX基础知识实践
- RSA算法基础->实践
- RSA算法基础->实践